/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2008-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.provision.service; import static org.opennms.core.utils.InetAddressUtils.addr; import static org.opennms.core.utils.InetAddressUtils.str; import static org.opennms.core.utils.LogUtils.debugf; import static org.opennms.core.utils.LogUtils.errorf; import static org.opennms.core.utils.LogUtils.infof; import static org.opennms.core.utils.LogUtils.warnf; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.joda.time.DateTime; import org.joda.time.Duration; import org.opennms.core.utils.BeanUtils; import org.opennms.core.utils.LogUtils; import org.opennms.netmgt.EventConstants; import org.opennms.netmgt.dao.CategoryDao; import org.opennms.netmgt.dao.DistPollerDao; import org.opennms.netmgt.dao.IpInterfaceDao; import org.opennms.netmgt.dao.MonitoredServiceDao; import org.opennms.netmgt.dao.NodeDao; import org.opennms.netmgt.dao.ServiceTypeDao; import org.opennms.netmgt.dao.SnmpInterfaceDao; import org.opennms.netmgt.dao.support.CreateIfNecessaryTemplate; import org.opennms.netmgt.dao.support.UpsertTemplate; import org.opennms.netmgt.model.AbstractEntityVisitor; import org.opennms.netmgt.model.EntityVisitor; import org.opennms.netmgt.model.OnmsCategory; import org.opennms.netmgt.model.OnmsDistPoller; import org.opennms.netmgt.model.OnmsIpInterface; import org.opennms.netmgt.model.OnmsMonitoredService; import org.opennms.netmgt.model.OnmsNode; import org.opennms.netmgt.model.OnmsServiceType; import org.opennms.netmgt.model.OnmsSnmpInterface; import org.opennms.netmgt.model.PathElement; import org.opennms.netmgt.model.PrimaryType; import org.opennms.netmgt.model.events.AddEventVisitor; import org.opennms.netmgt.model.events.DeleteEventVisitor; import org.opennms.netmgt.model.events.EventBuilder; import org.opennms.netmgt.model.events.EventForwarder; import org.opennms.netmgt.model.events.UpdateEventVisitor; import org.opennms.netmgt.provision.IpInterfacePolicy; import org.opennms.netmgt.provision.NodePolicy; import org.opennms.netmgt.provision.ServiceDetector; import org.opennms.netmgt.provision.SnmpInterfacePolicy; import org.opennms.netmgt.provision.persist.ForeignSourceRepository; import org.opennms.netmgt.provision.persist.ForeignSourceRepositoryException; import org.opennms.netmgt.provision.persist.OnmsNodeRequisition; import org.opennms.netmgt.provision.persist.foreignsource.ForeignSource; import org.opennms.netmgt.provision.persist.foreignsource.PluginConfig; import org.opennms.netmgt.provision.persist.requisition.Requisition; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; /** * DefaultProvisionService * * @author brozow * @version $Id: $ */ @Service public class DefaultProvisionService implements ProvisionService, InitializingBean { private final static String FOREIGN_SOURCE_FOR_DISCOVERED_NODES = null; /** * ServiceTypeFulfiller * * @author brozow */ private final class ServiceTypeFulfiller extends AbstractEntityVisitor { @Override public void visitMonitoredService(OnmsMonitoredService monSvc) { OnmsServiceType dbType = monSvc.getServiceType(); if (dbType.getId() == null) { dbType = createServiceTypeIfNecessary(dbType.getName()); } monSvc.setServiceType(dbType); } } @Autowired private DistPollerDao m_distPollerDao; @Autowired private NodeDao m_nodeDao; @Autowired private IpInterfaceDao m_ipInterfaceDao; @Autowired private SnmpInterfaceDao m_snmpInterfaceDao; @Autowired private MonitoredServiceDao m_monitoredServiceDao; @Autowired private ServiceTypeDao m_serviceTypeDao; @Autowired private CategoryDao m_categoryDao; @Autowired @Qualifier("transactionAware") private EventForwarder m_eventForwarder; @Autowired @Qualifier("fused") private ForeignSourceRepository m_foreignSourceRepository; @Autowired private PluginRegistry m_pluginRegistry; @Autowired private PlatformTransactionManager m_transactionManager; private final ThreadLocal<HashMap<String, OnmsServiceType>> m_typeCache = new ThreadLocal<HashMap<String, OnmsServiceType>>(); private final ThreadLocal<HashMap<String, OnmsCategory>> m_categoryCache = new ThreadLocal<HashMap<String, OnmsCategory>>(); @Override public void afterPropertiesSet() throws Exception { BeanUtils.assertAutowiring(this); } /** * <p>isDiscoveryEnabled</p> * * @return a boolean. */ public boolean isDiscoveryEnabled() { return System.getProperty("org.opennms.provisiond.enableDiscovery", "false").equalsIgnoreCase("true"); } public boolean isRequisitionedEntityDeletionEnabled() { return System.getProperty("org.opennms.provisiond.enableDeletionOfRequisitionedEntities", "false").equalsIgnoreCase("true"); } /** {@inheritDoc} */ @Transactional public void insertNode(final OnmsNode node) { node.setDistPoller(createDistPollerIfNecessary("localhost", "127.0.0.1")); m_nodeDao.save(node); m_nodeDao.flush(); final EntityVisitor eventAccumlator = new AddEventVisitor(m_eventForwarder); node.visit(eventAccumlator); } /** {@inheritDoc} */ @Transactional public void updateNode(final OnmsNode node) { final OnmsNode dbNode = m_nodeDao.getHierarchy(node.getId()); dbNode.mergeNode(node, m_eventForwarder, false); m_nodeDao.update(dbNode); m_nodeDao.flush(); final EntityVisitor eventAccumlator = new UpdateEventVisitor(m_eventForwarder); node.visit(eventAccumlator); } /** {@inheritDoc} */ @Transactional public void deleteNode(final Integer nodeId) { final OnmsNode node = m_nodeDao.get(nodeId); if (node != null && shouldDelete(node)) { m_nodeDao.delete(node); node.visit(new DeleteEventVisitor(m_eventForwarder)); } } private boolean shouldDelete(final OnmsNode node) { String foreignSource = node.getForeignSource(); // only delete services that are on discovered nodes if discovery is enabled // meaning provisiond is managing discovered nodes rather than capsd if (foreignSource == null) return isDiscoveryEnabled(); // if we enable deletion of requisitioned entities then we can delete this if (isRequisitionedEntityDeletionEnabled()) return true; // otherwise only delete if it is not requistioned return !isRequisitioned(node); } /** {@inheritDoc} */ @Transactional public void deleteInterface(final Integer nodeId, final String ipAddr) { final OnmsIpInterface iface = m_ipInterfaceDao.findByNodeIdAndIpAddress(nodeId, ipAddr); if (iface != null && shouldDelete(iface)) { m_ipInterfaceDao.delete(iface); iface.visit(new DeleteEventVisitor(m_eventForwarder)); } } private boolean shouldDelete(final OnmsIpInterface iface) { String foreignSource = iface.getNode().getForeignSource(); // only delete services that are on discovered nodes if discovery is enabled // meaning provisiond is managing discovered nodes rather than capsd if (foreignSource == null) return isDiscoveryEnabled(); // if we enable deletion of requisitioned entities then we can delete this if (isRequisitionedEntityDeletionEnabled()) return true; // otherwise only delete if it is not requistioned return !isRequisitioned(iface); } /** {@inheritDoc} */ @Transactional public void deleteService(final Integer nodeId, final InetAddress addr, final String service) { final OnmsMonitoredService monSvc = m_monitoredServiceDao.get(nodeId, addr, service); if (monSvc != null && shouldDelete(monSvc)) { m_monitoredServiceDao.delete(monSvc); monSvc.visit(new DeleteEventVisitor(m_eventForwarder)); } } private boolean shouldDelete(final OnmsMonitoredService monSvc) { String foreignSource = monSvc.getIpInterface().getNode().getForeignSource(); // only delete services that are on discovered nodes if discovery is enabled // meaning provisiond is managing discovered nodes rather than capsd if (foreignSource == null) return isDiscoveryEnabled(); // if we enable deletion of requisitioned entities then we can delete this if (isRequisitionedEntityDeletionEnabled()) return true; // otherwise only delete if it is not requistioned return !isRequisitioned(monSvc); } public boolean isRequisitioned(OnmsNode node) { String foreignSource = node.getForeignSource(); String foreignId = node.getForeignId(); // is this a discovered node if (foreignSource == null) return false; OnmsNode reqNode = getRequisitionedNode(foreignSource, foreignId); if (reqNode == null) { // this is no requisition node? LogUtils.errorf("No requistion exists for node with foreignSource %s and foreignId %s. Treating node as unrequistioned", foreignSource, foreignId); return false; } else { return true; } } public boolean isRequisitioned(OnmsIpInterface ip) { String foreignSource = ip.getNode().getForeignSource(); String foreignId = ip.getNode().getForeignId(); // is this a discovered node if (foreignSource == null) return false; OnmsNode reqNode = getRequisitionedNode(foreignSource, foreignId); if (reqNode == null) { // this is no requisition node? LogUtils.errorf("No requistion exists for node with foreignSource %s and foreignId %s. Treating node as unrequistioned", foreignSource, foreignId); return false; } OnmsIpInterface reqIp = reqNode.getIpInterfaceByIpAddress(ip.getIpAddress()); // if we found the ip then its a requisitioned interface return reqIp != null; } public boolean isRequisitioned(OnmsMonitoredService monSvc) { String foreignSource = monSvc.getIpInterface().getNode().getForeignSource(); String foreignId = monSvc.getIpInterface().getNode().getForeignId(); // is this a discovered node if (foreignSource == null) return false; OnmsNode reqNode = getRequisitionedNode(foreignSource, foreignId); if (reqNode == null) { // this is no requisition node? LogUtils.errorf("No requistion exists for node with foreignSource %s and foreignId %s. Treating node as unrequistioned", foreignSource, foreignId); return false; } OnmsIpInterface reqIp = reqNode.getIpInterfaceByIpAddress(monSvc.getIpAddress()); if (reqIp == null) { // there is no matching requistion ip so the interface was discovered return false; } OnmsMonitoredService reqSvc = reqIp.getMonitoredServiceByServiceType(monSvc.getServiceName()); // if we found the service then its a requistion service return reqSvc != null; } private void assertNotNull(final Object o, final String format, final Object... args) { if (o == null) { throw new IllegalArgumentException(String.format(format, args)); } } /** {@inheritDoc} */ @Transactional public OnmsIpInterface updateIpInterfaceAttributes(final Integer nodeId, final OnmsIpInterface scannedIface) { final OnmsSnmpInterface snmpInterface = scannedIface.getSnmpInterface(); if (snmpInterface != null && snmpInterface.getIfIndex() != null) { scannedIface.setSnmpInterface(updateSnmpInterfaceAttributes(nodeId, snmpInterface)); } return new UpsertTemplate<OnmsIpInterface, IpInterfaceDao>(m_transactionManager, m_ipInterfaceDao) { @Override protected OnmsIpInterface query() { OnmsIpInterface dbIface = m_ipInterfaceDao.findByNodeIdAndIpAddress(nodeId, str(scannedIface.getIpAddress())); debugf(this, "Updating interface attributes for DB interface %s for node %d with ip %s", dbIface, nodeId, str(scannedIface.getIpAddress())); return dbIface; } @Override protected OnmsIpInterface doUpdate(final OnmsIpInterface dbIface) { if(dbIface.isManaged() && !scannedIface.isManaged()){ final Set<OnmsMonitoredService> monSvcs = dbIface.getMonitoredServices(); for(final OnmsMonitoredService monSvc : monSvcs){ monSvc.visit(new DeleteEventVisitor(m_eventForwarder)); } monSvcs.clear(); } dbIface.mergeInterfaceAttributes(scannedIface); infof(this, "Updating IpInterface %s", dbIface); m_ipInterfaceDao.update(dbIface); m_ipInterfaceDao.flush(); return dbIface; } @Override protected OnmsIpInterface doInsert() { final OnmsNode dbNode = m_nodeDao.load(nodeId); assertNotNull(dbNode, "no node found with nodeId %d", nodeId); // for performance reasons we don't add the ip interface to the node so we avoid loading all the interfaces // setNode only sets the node in the interface scannedIface.setNode(dbNode); saveOrUpdate(scannedIface); final AddEventVisitor visitor = new AddEventVisitor(m_eventForwarder); scannedIface.visit(visitor); m_ipInterfaceDao.flush(); return scannedIface; } }.execute(); } /** {@inheritDoc} */ @Transactional public OnmsSnmpInterface updateSnmpInterfaceAttributes(final Integer nodeId, final OnmsSnmpInterface snmpInterface) { return new UpsertTemplate<OnmsSnmpInterface, SnmpInterfaceDao>(m_transactionManager, m_snmpInterfaceDao) { @Override public OnmsSnmpInterface query() { final OnmsSnmpInterface dbSnmpIface = m_snmpInterfaceDao.findByNodeIdAndIfIndex(nodeId, snmpInterface.getIfIndex()); debugf(this, "nodeId = %d, ifIndex = %d, dbSnmpIface = %s", nodeId, snmpInterface.getIfIndex(), dbSnmpIface); return dbSnmpIface; } @Override public OnmsSnmpInterface doUpdate(OnmsSnmpInterface dbSnmpIface) { // update the interface that was found dbSnmpIface.mergeSnmpInterfaceAttributes(snmpInterface); infof(this, "Updating SnmpInterface %s", dbSnmpIface); m_snmpInterfaceDao.update(dbSnmpIface); m_snmpInterfaceDao.flush(); return dbSnmpIface; } @Override public OnmsSnmpInterface doInsert() { // add the interface to the node, if it wasn't found final OnmsNode dbNode = m_nodeDao.load(nodeId); assertNotNull(dbNode, "no node found with nodeId %d", nodeId); // for performance reasons we don't add the snmp interface to the node so we avoid loading all the interfaces // setNode only sets the node in the interface snmpInterface.setNode(dbNode); infof(this, "Saving SnmpInterface %s", snmpInterface); m_snmpInterfaceDao.save(snmpInterface); m_snmpInterfaceDao.flush(); return snmpInterface; } }.execute(); } /** {@inheritDoc} */ @Transactional public OnmsMonitoredService addMonitoredService(final Integer ipInterfaceId, final String svcName) { final OnmsIpInterface iface = m_ipInterfaceDao.get(ipInterfaceId); assertNotNull(iface, "could not find interface with id %d", ipInterfaceId); return addMonitoredService(iface, svcName); } private OnmsMonitoredService addMonitoredService(final OnmsIpInterface iface, final String svcName) { final OnmsServiceType svcType = createServiceTypeIfNecessary(svcName); return new CreateIfNecessaryTemplate<OnmsMonitoredService, MonitoredServiceDao>(m_transactionManager, m_monitoredServiceDao) { @Override protected OnmsMonitoredService query() { return iface.getMonitoredServiceByServiceType(svcName); } @Override protected OnmsMonitoredService doInsert() { OnmsMonitoredService svc = new OnmsMonitoredService(iface, svcType); svc.setStatus("A"); m_ipInterfaceDao.saveOrUpdate(iface); m_ipInterfaceDao.flush(); final AddEventVisitor visitor = new AddEventVisitor(m_eventForwarder); svc.visit(visitor); return svc; } }.execute(); } /** {@inheritDoc} */ @Transactional public OnmsMonitoredService addMonitoredService(final Integer nodeId, final String ipAddress, final String svcName) { final OnmsIpInterface iface = m_ipInterfaceDao.findByNodeIdAndIpAddress(nodeId, ipAddress); assertNotNull(iface, "could not find interface with nodeid %d and ipAddr %s", nodeId, ipAddress); return addMonitoredService(iface, svcName); } @Transactional public OnmsMonitoredService updateMonitoredServiceState(final Integer nodeId, final String ipAddress, final String svcName) { final OnmsIpInterface iface = m_ipInterfaceDao.findByNodeIdAndIpAddress(nodeId, ipAddress); assertNotNull(iface, "could not find interface with nodeid %d and ipAddr %s", nodeId, ipAddress); return new UpsertTemplate<OnmsMonitoredService, MonitoredServiceDao>(m_transactionManager, m_monitoredServiceDao) { @Override protected OnmsMonitoredService query() { return iface.getMonitoredServiceByServiceType(svcName); } @Override protected OnmsMonitoredService doUpdate(OnmsMonitoredService dbObj) { // NMS-3906 debugf(this, "current status of service %s on node with IP %s is %s ", dbObj.getServiceName(), dbObj.getIpAddress().getHostAddress(), dbObj.getStatus()); if ("S".equals(dbObj.getStatus())) { debugf(this, "suspending polling for service %s on node with IP %s", dbObj.getServiceName(), dbObj.getIpAddress().getHostAddress()); dbObj.setStatus("F"); m_monitoredServiceDao.update(dbObj); sendEvent(EventConstants.SUSPEND_POLLING_SERVICE_EVENT_UEI, dbObj); } if ("R".equals(dbObj.getStatus())) { debugf(this, "resume polling for service %s on node with IP %s", dbObj.getServiceName(), dbObj.getIpAddress().getHostAddress()); dbObj.setStatus("A"); m_monitoredServiceDao.update(dbObj); sendEvent(EventConstants.RESUME_POLLING_SERVICE_EVENT_UEI, dbObj); } return dbObj; } @Override protected OnmsMonitoredService doInsert() { return null; } private void sendEvent(String eventUEI, OnmsMonitoredService dbObj) { final EventBuilder bldr = new EventBuilder(eventUEI, "ProvisionService"); bldr.setNodeid(dbObj.getNodeId()); bldr.setInterface(dbObj.getIpAddress()); bldr.setService(dbObj.getServiceName()); m_eventForwarder.sendNow(bldr.getEvent()); } }.execute(); } /** * <p>clearCache</p> */ @Transactional public void clearCache() { m_nodeDao.clear(); m_nodeDao.flush(); } /** {@inheritDoc} */ public OnmsDistPoller createDistPollerIfNecessary(final String dpName, final String dpAddr) { return createDistPollerIfNecessary(new OnmsDistPoller(dpName, dpAddr)); } public OnmsDistPoller createDistPollerIfNecessary(OnmsDistPoller scannedDistPoller) { final OnmsDistPoller distPoller = scannedDistPoller == null ? new OnmsDistPoller("localhost", "127.0.0.1") : scannedDistPoller; return new CreateIfNecessaryTemplate<OnmsDistPoller, DistPollerDao>(m_transactionManager, m_distPollerDao) { @Override protected OnmsDistPoller query() { return m_distPollerDao.get(distPoller.getName()); } @Override public OnmsDistPoller doInsert() { m_distPollerDao.save(distPoller); m_distPollerDao.flush(); return distPoller; } }.execute(); } /** {@inheritDoc} */ @Transactional public OnmsNode getRequisitionedNode(final String foreignSource, final String foreignId) throws ForeignSourceRepositoryException { final OnmsNodeRequisition nodeReq = m_foreignSourceRepository.getNodeRequisition(foreignSource, foreignId); if (nodeReq == null) { warnf(this, "nodeReq for node %s:%s cannot be null!", foreignSource, foreignId); return null; } final OnmsNode node = nodeReq.constructOnmsNodeFromRequisition(); // fill in real database categories final HashSet<OnmsCategory> dbCategories = new HashSet<OnmsCategory>(); for(final OnmsCategory category : node.getCategories()) { dbCategories.add(createCategoryIfNecessary(category.getName())); } node.setCategories(dbCategories); // fill in real service types node.visit(new ServiceTypeFulfiller()); return node; } /** {@inheritDoc} */ @Transactional public OnmsServiceType createServiceTypeIfNecessary(final String serviceName) { preloadExistingTypes(); OnmsServiceType type = m_typeCache.get().get(serviceName); if (type == null) { type = loadServiceType(serviceName); m_typeCache.get().put(serviceName, type); } return type; } /** {@inheritDoc} */ @Transactional public OnmsCategory createCategoryIfNecessary(final String name) { preloadExistingCategories(); OnmsCategory category = m_categoryCache.get().get(name); if (category == null) { category = loadCategory(name); m_categoryCache.get().put(category.getName(), category); } return category; } /** {@inheritDoc} */ @Transactional(readOnly=true) public Map<String, Integer> getForeignIdToNodeIdMap(final String foreignSource) { return m_nodeDao.getForeignIdToNodeIdMap(foreignSource); } /** {@inheritDoc} */ @Override @Transactional public void setNodeParentAndDependencies(final String foreignSource, final String foreignId, final String parentForeignSource, final String parentForeignId, final String parentNodeLabel) { final OnmsNode node = findNodebyForeignId(foreignSource, foreignId); if (node == null) { return; } final OnmsNode parent = findParent(parentForeignSource, parentForeignId, parentNodeLabel); setParent(node, parent); setPathDependency(node, parent); m_nodeDao.update(node); m_nodeDao.flush(); } private void preloadExistingTypes() { if (m_typeCache.get() == null) { m_typeCache.set(loadServiceTypeMap()); } } @Transactional(readOnly=true) private HashMap<String, OnmsServiceType> loadServiceTypeMap() { final HashMap<String, OnmsServiceType> serviceTypeMap = new HashMap<String, OnmsServiceType>(); for (final OnmsServiceType svcType : m_serviceTypeDao.findAll()) { serviceTypeMap.put(svcType.getName(), svcType); } return serviceTypeMap; } @Transactional private OnmsServiceType loadServiceType(final String serviceName) { return new CreateIfNecessaryTemplate<OnmsServiceType, ServiceTypeDao>(m_transactionManager, m_serviceTypeDao) { @Override protected OnmsServiceType query() { return m_serviceTypeDao.findByName(serviceName); } @Override public OnmsServiceType doInsert() { OnmsServiceType type = new OnmsServiceType(serviceName); m_serviceTypeDao.save(type); m_serviceTypeDao.flush(); return type; } }.execute(); } private void preloadExistingCategories() { if (m_categoryCache.get() == null) { m_categoryCache.set(loadCategoryMap()); } } @Transactional(readOnly=true) private HashMap<String, OnmsCategory> loadCategoryMap() { final HashMap<String, OnmsCategory> categoryMap = new HashMap<String, OnmsCategory>(); for (final OnmsCategory category : m_categoryDao.findAll()) { categoryMap.put(category.getName(), category); } return categoryMap; } @Transactional private OnmsCategory loadCategory(final String name) { return new CreateIfNecessaryTemplate<OnmsCategory, CategoryDao>(m_transactionManager, m_categoryDao) { @Override protected OnmsCategory query() { return m_categoryDao.findByName(name); } @Override public OnmsCategory doInsert() { OnmsCategory category = new OnmsCategory(name); m_categoryDao.save(category); m_categoryDao.flush(); return category; } }.execute(); } @Transactional(readOnly=true) private OnmsNode findNodebyNodeLabel(final String label) { Collection<OnmsNode> nodes = m_nodeDao.findByLabel(label); if (nodes.size() == 1) { return nodes.iterator().next(); } errorf(this, "Unable to locate a unique node using label %s: %d nodes found. Ignoring relationship.", label, nodes.size()); return null; } @Transactional(readOnly=true) private OnmsNode findNodebyForeignId(final String foreignSource, final String foreignId) { return m_nodeDao.findByForeignId(foreignSource, foreignId); } @Transactional(readOnly=true) private OnmsNode findParent(final String foreignSource, final String parentForeignId, final String parentNodeLabel) { if (parentForeignId != null) { return findNodebyForeignId(foreignSource, parentForeignId); } else { if (parentNodeLabel != null) { return findNodebyNodeLabel(parentNodeLabel); } } return null; } private void setPathDependency(final OnmsNode node, final OnmsNode parent) { if (node == null) return; OnmsIpInterface critIface = null; if (parent != null) { critIface = parent.getCriticalInterface(); } infof(this, "Setting criticalInterface of node: %s to: %s", node, critIface); node.setPathElement(critIface == null ? null : new PathElement(str(critIface.getIpAddress()), "ICMP")); } @Transactional private void setParent(final OnmsNode node, final OnmsNode parent) { if (node == null) return; infof(this, "Setting parent of node: %s to: %s", node, parent); node.setParent(parent); m_nodeDao.update(node); m_nodeDao.flush(); } /** {@inheritDoc} */ @Transactional(readOnly=true) public NodeScanSchedule getScheduleForNode(final int nodeId, final boolean force) { return createScheduleForNode(m_nodeDao.get(nodeId), force); } /** * <p>getScheduleForNodes</p> * * @return a {@link java.util.List} object. */ @Transactional(readOnly=true) public List<NodeScanSchedule> getScheduleForNodes() { Assert.notNull(m_nodeDao, "Node DAO is null and is not supposed to be"); final List<OnmsNode> nodes = isDiscoveryEnabled() ? m_nodeDao.findAll() : m_nodeDao.findAllProvisionedNodes(); final List<NodeScanSchedule> scheduledNodes = new ArrayList<NodeScanSchedule>(); for(final OnmsNode node : nodes) { final NodeScanSchedule nodeScanSchedule = createScheduleForNode(node, false); if (nodeScanSchedule != null) { scheduledNodes.add(nodeScanSchedule); } } return scheduledNodes; } private NodeScanSchedule createScheduleForNode(final OnmsNode node, final boolean force) { Assert.notNull(node, "Node may not be null"); final String actualForeignSource = node.getForeignSource(); if (actualForeignSource == null && !isDiscoveryEnabled()) { infof(this, "Not scheduling node %s to be scanned since it has a null foreignSource and handling of discovered nodes is disabled in provisiond", node); return null; } final String effectiveForeignSource = actualForeignSource == null ? "default" : actualForeignSource; try { final ForeignSource fs = m_foreignSourceRepository.getForeignSource(effectiveForeignSource); final Duration scanInterval = fs.getScanInterval(); Duration initialDelay = Duration.ZERO; if (node.getLastCapsdPoll() != null && !force) { final DateTime nextPoll = new DateTime(node.getLastCapsdPoll().getTime()).plus(scanInterval); final DateTime now = new DateTime(); if (nextPoll.isAfter(now)) { initialDelay = new Duration(now, nextPoll); } } return new NodeScanSchedule(node.getId(), actualForeignSource, node.getForeignId(), initialDelay, scanInterval); } catch (final ForeignSourceRepositoryException e) { warnf(this, e, "unable to get foreign source '%s' from repository", effectiveForeignSource); return null; } } /** {@inheritDoc} */ public void setForeignSourceRepository(final ForeignSourceRepository foreignSourceRepository) { m_foreignSourceRepository = foreignSourceRepository; } /** * <p>getForeignSourceRepository</p> * * @return a {@link org.opennms.netmgt.provision.persist.ForeignSourceRepository} object. */ public ForeignSourceRepository getForeignSourceRepository() { return m_foreignSourceRepository; } /* (non-Javadoc) * @see org.opennms.netmgt.provision.service.ProvisionService#loadRequisition(java.lang.String, org.springframework.core.io.Resource) */ /** {@inheritDoc} */ public Requisition loadRequisition(final Resource resource) { final Requisition r = m_foreignSourceRepository.importResourceRequisition(resource); r.updateLastImported(); m_foreignSourceRepository.save(r); return r; } /* (non-Javadoc) * @see org.opennms.netmgt.provision.service.ProvisionService#updateNodeInfo(org.opennms.netmgt.model.OnmsNode) */ /** {@inheritDoc} */ @Transactional public OnmsNode updateNodeAttributes(final OnmsNode node) { return new UpsertTemplate<OnmsNode, NodeDao>(m_transactionManager, m_nodeDao) { @Override protected OnmsNode query() { return getDbNode(node); } @Override protected OnmsNode doUpdate(OnmsNode dbNode) { dbNode.mergeNodeAttributes(node, m_eventForwarder); return saveOrUpdate(dbNode); } @Override protected OnmsNode doInsert() { node.setDistPoller(createDistPollerIfNecessary(node.getDistPoller())); return saveOrUpdate(node); } }.execute(); } @Transactional(readOnly=true) private OnmsNode getDbNode(final OnmsNode node) { OnmsNode dbNode; if (node.getId() != null) { dbNode = m_nodeDao.get(node.getId()); } else { dbNode = m_nodeDao.findByForeignId(node.getForeignSource(), node.getForeignId()); } return dbNode; } @Transactional private OnmsNode saveOrUpdate(final OnmsNode node) { final Set<OnmsCategory> updatedCategories = new HashSet<OnmsCategory>(); for(final Iterator<OnmsCategory> it = node.getCategories().iterator(); it.hasNext(); ) { final OnmsCategory category = it.next(); if (category.getId() == null) { it.remove(); updatedCategories.add(createCategoryIfNecessary(category.getName())); } } node.getCategories().addAll(updatedCategories); m_nodeDao.saveOrUpdate(node); m_nodeDao.flush(); return node; } @Transactional private OnmsIpInterface saveOrUpdate(final OnmsIpInterface iface) { iface.visit(new ServiceTypeFulfiller()); infof(this, "SaveOrUpdating IpInterface %s", iface); m_ipInterfaceDao.saveOrUpdate(iface); m_ipInterfaceDao.flush(); return iface; } /** {@inheritDoc} */ public List<ServiceDetector> getDetectorsForForeignSource(final String foreignSourceName) { final ForeignSource foreignSource = m_foreignSourceRepository.getForeignSource(foreignSourceName); assertNotNull(foreignSource, "Expected a foreignSource with name %s", foreignSourceName); final List<PluginConfig> detectorConfigs = foreignSource.getDetectors(); if (detectorConfigs == null) { return new ArrayList<ServiceDetector>(m_pluginRegistry.getAllPlugins(ServiceDetector.class)); } final List<ServiceDetector> detectors = new ArrayList<ServiceDetector>(detectorConfigs.size()); for(final PluginConfig detectorConfig : detectorConfigs) { final ServiceDetector detector = m_pluginRegistry.getPluginInstance(ServiceDetector.class, detectorConfig); if (detector == null) { errorf(this, "Configured plugin does not exist: %s", detectorConfig); } else { detector.setServiceName(detectorConfig.getName()); detector.init(); detectors.add(detector); } } return detectors; } /** {@inheritDoc} */ public List<NodePolicy> getNodePoliciesForForeignSource(final String foreignSourceName) { return getPluginsForForeignSource(NodePolicy.class, foreignSourceName); } /** {@inheritDoc} */ public List<IpInterfacePolicy> getIpInterfacePoliciesForForeignSource(final String foreignSourceName) { return getPluginsForForeignSource(IpInterfacePolicy.class, foreignSourceName); } /** {@inheritDoc} */ public List<SnmpInterfacePolicy> getSnmpInterfacePoliciesForForeignSource(final String foreignSourceName) { return getPluginsForForeignSource(SnmpInterfacePolicy.class, foreignSourceName); } /** * <p>getPluginsForForeignSource</p> * * @param pluginClass a {@link java.lang.Class} object. * @param foreignSourceName a {@link java.lang.String} object. * @param <T> a T object. * @return a {@link java.util.List} object. */ public <T> List<T> getPluginsForForeignSource(final Class<T> pluginClass, final String foreignSourceName) { final ForeignSource foreignSource = m_foreignSourceRepository.getForeignSource(foreignSourceName); assertNotNull(foreignSource, "Expected a foreignSource with name %s", foreignSourceName); final List<PluginConfig> configs = foreignSource.getPolicies(); if (configs == null) { return Collections.emptyList(); } final List<T> plugins = new ArrayList<T>(configs.size()); for(final PluginConfig config : configs) { final T plugin = m_pluginRegistry.getPluginInstance(pluginClass, config); if (plugin == null) { debugf(this, "Configured plugin is not appropropriate for policy class %s: %s", pluginClass, config); } else { plugins.add(plugin); } } return plugins; } /** {@inheritDoc} */ @Transactional public void deleteObsoleteInterfaces(final Integer nodeId, final Date scanStamp) { final List<OnmsIpInterface> obsoleteInterfaces = m_nodeDao.findObsoleteIpInterfaces(nodeId, scanStamp); for(final OnmsIpInterface iface : obsoleteInterfaces) { iface.visit(new DeleteEventVisitor(m_eventForwarder)); } m_nodeDao.deleteObsoleteInterfaces(nodeId, scanStamp); } /** {@inheritDoc} */ @Transactional public void updateNodeScanStamp(final Integer nodeId, final Date scanStamp) { m_nodeDao.updateNodeScanStamp(nodeId, scanStamp); m_nodeDao.flush(); } /** {@inheritDoc} */ @Transactional public OnmsIpInterface setIsPrimaryFlag(final Integer nodeId, final String ipAddress) { // TODO upsert? not sure if this needs one.. leave the todo here in case if (nodeId == null) { LogUtils.debugf(this, "nodeId is null!"); return null; } else if (ipAddress == null) { LogUtils.debugf(this, "ipAddress is null!"); return null; } final OnmsIpInterface svcIface = m_ipInterfaceDao.findByNodeIdAndIpAddress(nodeId, ipAddress); if (svcIface == null) { LogUtils.infof(this, "unable to find IPInterface for nodeId=%s, ipAddress=%s", nodeId, ipAddress); return null; } OnmsIpInterface primaryIface = null; if (svcIface.isPrimary()) { primaryIface = svcIface; } else if (svcIface.getNode().getPrimaryInterface() == null) { svcIface.setIsSnmpPrimary(PrimaryType.PRIMARY); m_ipInterfaceDao.saveOrUpdate(svcIface); m_ipInterfaceDao.flush(); primaryIface= svcIface; } else { svcIface.setIsSnmpPrimary(PrimaryType.SECONDARY); m_ipInterfaceDao.saveOrUpdate(svcIface); m_ipInterfaceDao.flush(); } m_ipInterfaceDao.initialize(primaryIface); return primaryIface; } /** {@inheritDoc} */ @Transactional public OnmsIpInterface getPrimaryInterfaceForNode(final OnmsNode node) { final OnmsNode dbNode = getDbNode(node); if (dbNode == null) { return null; } else { final OnmsIpInterface primaryIface = dbNode.getPrimaryInterface(); if (primaryIface != null) { m_ipInterfaceDao.initialize(primaryIface); m_ipInterfaceDao.initialize(primaryIface.getMonitoredServices()); } return primaryIface; } } /** {@inheritDoc} */ @Transactional public OnmsNode createUndiscoveredNode(final String ipAddress) { OnmsNode node = new UpsertTemplate<OnmsNode, NodeDao>(m_transactionManager, m_nodeDao) { @Override protected OnmsNode query() { List<OnmsNode> nodes = m_nodeDao.findByForeignSourceAndIpAddress(FOREIGN_SOURCE_FOR_DISCOVERED_NODES, ipAddress); return nodes.size() > 0 ? nodes.get(0) : null; } @Override protected OnmsNode doUpdate(OnmsNode existingNode) { // we found an existing node so exit by returning null; return null; } @Override protected OnmsNode doInsert() { final Date now = new Date(); final String hostname = getHostnameForIp(ipAddress); // @ipv6 final OnmsNode node = new OnmsNode(createDistPollerIfNecessary("localhost", "127.0.0.1")); node.setLabel(hostname == null ? ipAddress : hostname); node.setLabelSource(hostname == null ? "A" : "H"); node.setForeignSource(FOREIGN_SOURCE_FOR_DISCOVERED_NODES); node.setType("A"); node.setLastCapsdPoll(now); final OnmsIpInterface iface = new OnmsIpInterface(ipAddress, node); iface.setIsManaged("M"); iface.setIpHostName(hostname); iface.setIsSnmpPrimary(PrimaryType.NOT_ELIGIBLE); iface.setIpLastCapsdPoll(now); m_nodeDao.save(node); m_nodeDao.flush(); return node; } }.execute(); if (node != null) { // we do this here rather than in the doInsert method because // the doInsert may abort node.visit(new AddEventVisitor(m_eventForwarder)); } return node; } private String getHostnameForIp(final String address) { return addr(address).getCanonicalHostName(); } /** {@inheritDoc} */ @Transactional public OnmsNode getNode(final Integer nodeId) { final OnmsNode node = m_nodeDao.get(nodeId); m_nodeDao.initialize(node); m_nodeDao.initialize(node.getCategories()); m_nodeDao.initialize(node.getIpInterfaces()); return node; } /** {@inheritDoc} */ @Transactional public OnmsNode getDbNodeInitCat(final Integer nodeId) { final OnmsNode node = m_nodeDao.get(nodeId); m_nodeDao.initialize(node.getCategories()); m_nodeDao.initialize(node.getDistPoller()); return node; } }