X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fconfig-persister-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fpersist%2Fimpl%2Fosgi%2FConfigPersisterActivator.java;h=8e9f9978c4dd837334b07db2d1f6c96764e0ede9;hp=857912021b0e21d07f60d740bbc6f6372ef0f6b6;hb=de2a9ebcf8bdcc8424980878c6c4feda55376f66;hpb=4142ab5dce3021e6f6551aada26c7523cd134844 diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java index 857912021b..8e9f9978c4 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java @@ -8,109 +8,203 @@ package org.opendaylight.controller.netconf.persist.impl.osgi; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import org.opendaylight.controller.netconf.client.NetconfClient; -import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler; -import org.opendaylight.controller.netconf.persist.impl.ConfigPusher; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.management.MBeanServer; + +import org.opendaylight.controller.config.persist.api.ConfigPusher; +import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider; +import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.controller.netconf.persist.impl.ConfigPusherImpl; import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator; -import org.opendaylight.controller.netconf.persist.impl.Util; -import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; +import org.opendaylight.controller.netconf.util.CloseableUtil; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.Filter; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.management.MBeanServer; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.regex.Pattern; -import java.util.concurrent.TimeUnit; +import com.google.common.annotations.VisibleForTesting; public class ConfigPersisterActivator implements BundleActivator { private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class); + private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); - private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); - private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex"; - - private static final String PUSH_TIMEOUT = "pushTimeout"; + public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY = "maxWaitForCapabilitiesMillis"; + private static final long MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(2); + public static final String CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY = "conflictingVersionTimeoutMillis"; + private static final long CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT = TimeUnit.SECONDS.toMillis(30); public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister"; public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass"; - public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0"; + private List autoCloseables; + private volatile BundleContext context; - - private volatile ConfigPersisterNotificationHandler jmxNotificationHandler; - private volatile NetconfClient netconfClient; - private Thread initializationThread; - private EventLoopGroup nettyThreadgroup; - private PersisterAggregator persisterAggregator; + ServiceRegistration registration; @Override public void start(final BundleContext context) throws Exception { logger.debug("ConfigPersister starting"); + this.context = context; + autoCloseables = new ArrayList<>(); PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context); - String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX); - String regex; - if (regexProperty != null) { - regex = regexProperty; - } else { - regex = DEFAULT_IGNORED_REGEX; - } + final PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider); + autoCloseables.add(persisterAggregator); + long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider); + List configs = persisterAggregator.loadLastConfigs(); + long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider); + logger.debug("Following configs will be pushed: {}", configs); + + InnerCustomizer innerCustomizer = new InnerCustomizer(configs, maxWaitForCapabilitiesMillis, + conflictingVersionTimeoutMillis, persisterAggregator); + OuterCustomizer outerCustomizer = new OuterCustomizer(context, innerCustomizer); + new ServiceTracker<>(context, NetconfOperationProvider.class, outerCustomizer).open(); + } - String timeoutProperty = propertiesProvider.getProperty(PUSH_TIMEOUT); - long timeout = timeoutProperty == null ? ConfigPusher.DEFAULT_TIMEOUT : TimeUnit.SECONDS.toNanos(Integer.valueOf(timeoutProperty)); - - final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex); - nettyThreadgroup = new NioEventLoopGroup(); - - persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider); - final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context, "Netconf is not configured, persister is not operational", true); - final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadgroup); - - - // offload initialization to another thread in order to stop blocking activator - Runnable initializationRunnable = new Runnable() { - @Override - public void run() { - try { - netconfClient = configPusher.init(persisterAggregator.loadLastConfigs()); - jmxNotificationHandler = new ConfigPersisterNotificationHandler( - platformMBeanServer, netconfClient, persisterAggregator, - ignoredMissingCapabilityRegex); - jmxNotificationHandler.init(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.error("Interrupted while waiting for netconf connection"); - // uncaught exception handler will deal with this failure - throw new RuntimeException("Interrupted while waiting for netconf connection", e); - } - } - }; - initializationThread = new Thread(initializationRunnable, "ConfigPersister-registrator"); - initializationThread.start(); + private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) { + String timeoutProperty = propertiesProvider.getProperty(CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY); + return timeoutProperty == null ? CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT : Long.valueOf(timeoutProperty); + } + + private long getMaxWaitForCapabilitiesMillis(PropertiesProviderBaseImpl propertiesProvider) { + String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY); + return timeoutProperty == null ? MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT : Long.valueOf(timeoutProperty); } @Override public void stop(BundleContext context) throws Exception { - initializationThread.interrupt(); - if (jmxNotificationHandler != null) { - jmxNotificationHandler.close(); + synchronized(autoCloseables) { + CloseableUtil.closeAll(autoCloseables); + if (registration != null) { + registration.unregister(); + } + this.context = null; + } + } + + + @VisibleForTesting + public static String getFilterString() { + return "(&" + + "(" + Constants.OBJECTCLASS + "=" + NetconfOperationServiceFactory.class.getName() + ")" + + "(name" + "=" + "config-netconf-connector" + ")" + + ")"; + } + + class OuterCustomizer implements ServiceTrackerCustomizer { + private final BundleContext context; + private final InnerCustomizer innerCustomizer; + + OuterCustomizer(BundleContext context, InnerCustomizer innerCustomizer) { + this.context = context; + this.innerCustomizer = innerCustomizer; } - if (netconfClient != null) { - netconfClient = jmxNotificationHandler.getNetconfClient(); + + @Override + public NetconfOperationProvider addingService(ServiceReference reference) { + logger.trace("Got OuterCustomizer.addingService {}", reference); + // JMX was registered, track config-netconf-connector + Filter filter; try { - Util.closeClientAndDispatcher(netconfClient); - } catch (Exception e) { - logger.warn("Unable to close connection to netconf {}", netconfClient, e); + filter = context.createFilter(getFilterString()); + } catch (InvalidSyntaxException e) { + throw new IllegalStateException(e); } + new ServiceTracker<>(context, filter, innerCustomizer).open(); + return null; + } + + @Override + public void modifiedService(ServiceReference reference, NetconfOperationProvider service) { + + } + + @Override + public void removedService(ServiceReference reference, NetconfOperationProvider service) { + } - nettyThreadgroup.shutdownGracefully(); - persisterAggregator.close(); + } + + class InnerCustomizer implements ServiceTrackerCustomizer { + private final List configs; + private final PersisterAggregator persisterAggregator; + private final long maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis; + + + InnerCustomizer(List configs, long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis, + PersisterAggregator persisterAggregator) { + this.configs = configs; + this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis; + this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis; + this.persisterAggregator = persisterAggregator; + } + + @Override + public NetconfOperationServiceFactory addingService(ServiceReference reference) { + logger.trace("Got InnerCustomizer.addingService {}", reference); + NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference); + + logger.debug("Creating new job queue"); + + final ConfigPusherImpl configPusher = new ConfigPusherImpl(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis); + logger.debug("Configuration Persister got {}", service); + logger.debug("Context was {}", context); + logger.debug("Registration was {}", registration); + + final Thread pushingThread = new Thread(new Runnable() { + @Override + public void run() { + try { + if(configs != null && !configs.isEmpty()) { + configPusher.pushConfigs(configs); + } + if(context != null) { + registration = context.registerService(ConfigPusher.class.getName(), configPusher, null); + configPusher.process(autoCloseables, platformMBeanServer, persisterAggregator); + } else { + logger.warn("Unable to process configs as BundleContext is null"); + } + } catch (InterruptedException e) { + logger.info("ConfigPusher thread stopped",e); + } + logger.info("Configuration Persister initialization completed."); + } + }, "config-pusher"); + synchronized (autoCloseables) { + autoCloseables.add(new AutoCloseable() { + @Override + public void close() { + pushingThread.interrupt(); + } + }); + } + pushingThread.start(); + return service; + } + + @Override + public void modifiedService(ServiceReference reference, NetconfOperationServiceFactory service) { + } + + @Override + public void removedService(ServiceReference reference, NetconfOperationServiceFactory service) { + } + } } +