Monitoring for mdsal's netconf stores all available monitoring data in the datastore and provides get-schema operation
Change-Id: I573c5d57e5cf25d7688f3355b602327c7af75c65
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
<artifactId>sal-inmemory-datastore</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-netconf-connector</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-netconf-monitoring</artifactId>
+ </dependency>
+
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-netconf-connector</artifactId>
</feature>
<!-- TODO move to netconf features, however there are some weird dependencies on features-config-persister all over that cause cyclic dependencies-->
- <feature name='odl-netconf-mdsal' version='${project.version}' description="OpenDaylight :: Netconf :: All">
+ <!-- TODO when installing this in pure karaf distro, many optimistic lock exceptions are thrown from config manager -->
+ <feature name='odl-netconf-mdsal' version='${project.version}' description="OpenDaylight :: Netconf :: Mdsal">
<feature version='${config.version}'>odl-config-all</feature>
<feature version='${netconf.version}'>odl-netconf-all</feature>
<bundle>mvn:org.opendaylight.controller/netconf-ssh/${netconf.version}</bundle>
<feature version='${mdsal.version}'>odl-mdsal-broker</feature>
<bundle>mvn:org.opendaylight.controller/mdsal-netconf-connector/${netconf.version}</bundle>
+ <bundle>mvn:org.opendaylight.controller/mdsal-netconf-monitoring/${netconf.version}</bundle>
<!-- TODO 01-netconf.xml file requires netconf-config-dispatcher to be present and its part of netconf-connector features. Clean Up-->
<bundle>mvn:org.opendaylight.controller/netconf-config-dispatcher/${config.version}</bundle>
<configfile finalname='${config.configfile.directory}/${config.netconf.client.configfile}'>mvn:org.opendaylight.controller/netconf-config/${netconf.version}/xml/config</configfile>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-config-dispatcher</artifactId>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>mdsal-netconf-connector</artifactId>
- </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>netconf-tcp</artifactId>
<bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring-extension/${project.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf-inet-types.version}</bundle>
<bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types/${ietf-yang-types.version}</bundle>
+ <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types-20130715/2013.07.15.7-SNAPSHOT</bundle>
</feature>
<feature name='odl-netconf-mapping-api' version='${project.version}' description="OpenDaylight :: Netconf :: Mapping API">
<feature version='${project.version}'>odl-netconf-api</feature>
passNotifications = true;
for (final NetconfMessage cachedNotification : queue) {
- passNotification(messageTransformer.toNotification(cachedNotification));
+ final CompositeNode parsedNotification = messageTransformer.toNotification(cachedNotification);
+ // TODO possible race condition here, because this exception is thrown occasionally
+ Preconditions.checkNotNull(parsedNotification, "Unable to parse received notification %s", cachedNotification);
+ passNotification(parsedNotification);
}
queue.clear();
private synchronized void passNotification(final CompositeNode parsedNotification) {
logger.debug("{}: Forwarding notification {}", id, parsedNotification);
- Preconditions.checkNotNull(parsedNotification);
if(filter == null || filter.filterNotification(parsedNotification).isPresent()) {
salFacade.onNotification(parsedNotification);
import ietf-yang-types {
prefix yang;
+ revision-date "2010-09-24";
}
+
import ietf-inet-types {
prefix inet;
}
@Override
public java.lang.AutoCloseable createInstance() {
- return new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency(), getDomBrokerDependency());
+ final MdsalNetconfOperationServiceFactory mdsalNetconfOperationServiceFactory = new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency(), getDomBrokerDependency()) {
+ @Override
+ public void close() throws Exception {
+ super.close();
+ getMapperAggregatorDependency().onRemoveNetconfOperationServiceFactory(this);
+ }
+ };
+ getMapperAggregatorDependency().onAddNetconfOperationServiceFactory(mdsalNetconfOperationServiceFactory);
+ return mdsalNetconfOperationServiceFactory;
}
}
package org.opendaylight.controller.netconf.mdsal.connector;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.sal.core.api.model.SchemaService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
public class CurrentSchemaContext implements SchemaContextListener, AutoCloseable {
final AtomicReference<SchemaContext> currentContext = new AtomicReference<SchemaContext>();
private final ListenerRegistration<SchemaContextListener> schemaContextListenerListenerRegistration;
+ private final Set<CapabilityListener> listeners = Collections.synchronizedSet(Sets.<CapabilityListener>newHashSet());
public SchemaContext getCurrentContext() {
Preconditions.checkState(currentContext.get() != null, "Current context not received");
@Override
public void onGlobalContextUpdated(final SchemaContext schemaContext) {
currentContext.set(schemaContext);
+ // FIXME is notifying all the listeners from this callback wise ?
+ final Set<Capability> addedCaps = MdsalNetconfOperationServiceFactory.transformCapabilities(currentContext.get());
+ for (final CapabilityListener listener : listeners) {
+ listener.onCapabilitiesAdded(addedCaps);
+ }
}
@Override
public void close() throws Exception {
+ listeners.clear();
schemaContextListenerListenerRegistration.close();
currentContext.set(null);
}
+
+ public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+ listener.onCapabilitiesAdded(MdsalNetconfOperationServiceFactory.transformCapabilities(currentContext.get()));
+ listeners.add(listener);
+ return new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ listeners.remove(listener);
+ }
+ };
+ }
}
\ No newline at end of file
@Override
public Set<Capability> getCapabilities() {
+ return transformCapabilities(currentSchemaContext.getCurrentContext());
+ }
+
+ static Set<Capability> transformCapabilities(final SchemaContext currentContext1) {
final Set<Capability> capabilities = new HashSet<>();
// [RFC6241] 8.3. Candidate Configuration Capability
capabilities.add(new BasicCapability("urn:ietf:params:netconf:capability:candidate:1.0"));
- final SchemaContext currentContext = currentSchemaContext.getCurrentContext();
+ final SchemaContext currentContext = currentContext1;
final Set<Module> modules = currentContext.getModules();
for (final Module module : modules) {
if(currentContext.getModuleSource(module).isPresent()) {
@Override
public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
- // TODO provide notifications about changed schemas
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
-
- }
- };
+ return currentSchemaContext.registerCapabilityListener(listener);
}
private static class BasicCapability implements Capability {
}
}
}
+
+ container mapper-aggregator {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity nnm:netconf-mapper-registry;
+ }
+ }
+ }
}
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-subsystem</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>mdsal-netconf-monitoring</artifactId>
+ <packaging>bundle</packaging>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <!-- compile dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-mapping-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-monitoring</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-config</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.model</groupId>
+ <artifactId>ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>config</id>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+ <additionalConfiguration>
+ <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+ </additionalConfiguration>
+ </generator>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator-plugin</artifactId>
+ <version>${config.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.config.yang.netconf.mdsal.monitoring;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class MonitoringToMdsalWriter implements AutoCloseable, NetconfMonitoringService.MonitoringListener, BindingAwareProvider {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MonitoringToMdsalWriter.class);
+
+ private final NetconfMonitoringService serverMonitoringDependency;
+ private DataBroker dataBroker;
+
+ public MonitoringToMdsalWriter(final NetconfMonitoringService serverMonitoringDependency) {
+ this.serverMonitoringDependency = serverMonitoringDependency;
+ }
+
+ @Override
+ public void close() {
+ final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+ tx.delete(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NetconfState.class));
+ final CheckedFuture<Void, TransactionCommitFailedException> submit = tx.submit();
+
+ Futures.addCallback(submit, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(final Void aVoid) {
+ LOG.debug("Netconf state cleared successfully");
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.warn("Unable to clear netconf state", throwable);
+ }
+ });
+ }
+
+ @Override
+ public void onStateChanged(final NetconfState state) {
+ Preconditions.checkState(dataBroker != null);
+ final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+ tx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NetconfState.class), state);
+ // FIXME first attempt (right after we register to binding broker) always fails
+ // Is it due to the fact that we are writing from the onSessionInitiated callback ?
+ final CheckedFuture<Void, TransactionCommitFailedException> submit = tx.submit();
+
+ Futures.addCallback(submit, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(final Void aVoid) {
+ LOG.debug("Netconf state updated successfully");
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.warn("Unable to update netconf state", throwable);
+ }
+ });
+ }
+
+ @Override
+ public void onSessionInitiated(final BindingAwareBroker.ProviderContext providerContext) {
+ dataBroker = providerContext.getSALService(DataBroker.class);
+ serverMonitoringDependency.registerListener(this);
+ }
+}
--- /dev/null
+package org.opendaylight.controller.config.yang.netconf.mdsal.monitoring;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.monitoring.GetSchema;
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+
+public class NetconfMdsalMonitoringMapperModule extends org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.AbstractNetconfMdsalMonitoringMapperModule {
+ public NetconfMdsalMonitoringMapperModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfMdsalMonitoringMapperModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.NetconfMdsalMonitoringMapperModule oldModule, final java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ final NetconfMonitoringService serverMonitoringDependency = getServerMonitoringDependency();
+
+ final MonitoringToMdsalWriter monitoringToMdsalWriter = new MonitoringToMdsalWriter(serverMonitoringDependency);
+ getBindingAwareBrokerDependency().registerProvider(monitoringToMdsalWriter);
+
+ final MdSalMonitoringMapperFactory mdSalMonitoringMapperFactory = new MdSalMonitoringMapperFactory(new MdsalMonitoringMapper(serverMonitoringDependency)) {
+ @Override
+ public void close() {
+ super.close();
+ monitoringToMdsalWriter.close();
+ getAggregatorDependency().onRemoveNetconfOperationServiceFactory(this);
+ }
+ };
+
+ getAggregatorDependency().onAddNetconfOperationServiceFactory(mdSalMonitoringMapperFactory);
+ return mdSalMonitoringMapperFactory;
+
+ }
+
+ // FIXME almost exactly same code as in netconf-monitoring, refactor
+ private static class MdSalMonitoringMapperFactory implements NetconfOperationServiceFactory, AutoCloseable {
+
+ private final NetconfOperationService operationService;
+
+ private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
+
+ @Override
+ public String getCapabilityUri() {
+ return MonitoringConstants.URI;
+ }
+
+ @Override
+ public Optional<String> getModuleNamespace() {
+ return Optional.of(MonitoringConstants.NAMESPACE);
+ }
+
+ @Override
+ public Optional<String> getModuleName() {
+ return Optional.of(MonitoringConstants.MODULE_NAME);
+ }
+
+ @Override
+ public Optional<String> getRevision() {
+ return Optional.of(MonitoringConstants.MODULE_REVISION);
+ }
+
+ @Override
+ public Optional<String> getCapabilitySchema() {
+ return Optional.absent();
+ }
+
+ @Override
+ public Collection<String> getLocation() {
+ return Collections.emptyList();
+ }
+ });
+
+ private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ // NOOP
+ }
+ };
+
+ private final List<CapabilityListener> listeners = new ArrayList<>();
+
+ public MdSalMonitoringMapperFactory(final NetconfOperationService operationService) {
+ this.operationService = operationService;
+ }
+
+ @Override
+ public NetconfOperationService createService(final String netconfSessionIdForReporting) {
+ return operationService;
+ }
+
+ @Override
+ public Set<Capability> getCapabilities() {
+ return CAPABILITIES;
+ }
+
+ @Override
+ public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+ listener.onCapabilitiesAdded(getCapabilities());
+ listeners.add(listener);
+ return AUTO_CLOSEABLE;
+ }
+
+ @Override
+ public void close() {
+ for (final CapabilityListener listener : listeners) {
+ listener.onCapabilitiesRemoved(getCapabilities());
+ }
+ }
+ }
+
+
+ private static class MdsalMonitoringMapper implements NetconfOperationService {
+
+ private final NetconfMonitoringService serverMonitoringDependency;
+
+ public MdsalMonitoringMapper(final NetconfMonitoringService serverMonitoringDependency) {
+ this.serverMonitoringDependency = serverMonitoringDependency;
+ }
+
+ @Override
+ public Set<NetconfOperation> getNetconfOperations() {
+ return Collections.<NetconfOperation>singleton(new GetSchema(serverMonitoringDependency));
+ }
+
+ @Override
+ public void close() {
+ // NOOP
+ }
+ }
+}
--- /dev/null
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-mdsal-monitoring yang module local name: netconf-mdsal-monitoring-mapper
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 18 10:22:17 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.netconf.mdsal.monitoring;
+public class NetconfMdsalMonitoringMapperModuleFactory extends org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.AbstractNetconfMdsalMonitoringMapperModuleFactory {
+
+}
--- /dev/null
+/*
+* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,
+* and is available at http://www.eclipse.org/legal/epl-v10.html
+*/
+package org.opendaylight.controller.netconf.monitoring;
+
+import com.google.common.collect.Sets;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.monitoring.Get;
+import org.opendaylight.controller.netconf.monitoring.GetSchema;
+
+public class NetconfMonitoringOperationService implements NetconfOperationService {
+
+ private final NetconfMonitoringService monitor;
+
+ public NetconfMonitoringOperationService(final NetconfMonitoringService monitor) {
+ this.monitor = monitor;
+ }
+
+ @Override
+ public Set<NetconfOperation> getNetconfOperations() {
+ return Sets.<NetconfOperation>newHashSet(new Get(monitor), new GetSchema(monitor));
+ }
+
+ @Override
+ public void close() {
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.monitoring;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.opendaylight.controller.netconf.api.Capability;
+import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+
+/**
+* Created by mmarsale on 18.2.2015.
+*/
+public class NetconfMonitoringOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable {
+
+ private final NetconfMonitoringOperationService operationService;
+
+ private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
+
+ @Override
+ public String getCapabilityUri() {
+ return MonitoringConstants.URI;
+ }
+
+ @Override
+ public Optional<String> getModuleNamespace() {
+ return Optional.of(MonitoringConstants.NAMESPACE);
+ }
+
+ @Override
+ public Optional<String> getModuleName() {
+ return Optional.of(MonitoringConstants.MODULE_NAME);
+ }
+
+ @Override
+ public Optional<String> getRevision() {
+ return Optional.of(MonitoringConstants.MODULE_REVISION);
+ }
+
+ @Override
+ public Optional<String> getCapabilitySchema() {
+ return Optional.absent();
+ }
+
+ @Override
+ public Collection<String> getLocation() {
+ return Collections.emptyList();
+ }
+ });
+
+ private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ // NOOP
+ }
+ };
+
+ private final List<CapabilityListener> listeners = new ArrayList<>();
+
+ public NetconfMonitoringOperationServiceFactory(final NetconfMonitoringOperationService operationService) {
+ this.operationService = operationService;
+ }
+
+ @Override
+ public NetconfOperationService createService(final String netconfSessionIdForReporting) {
+ return operationService;
+ }
+
+ @Override
+ public Set<Capability> getCapabilities() {
+ return CAPABILITIES;
+ }
+
+ @Override
+ public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
+ listener.onCapabilitiesAdded(getCapabilities());
+ listeners.add(listener);
+ return AUTO_CLOSEABLE;
+ }
+
+ @Override
+ public void close() {
+ for (final CapabilityListener listener : listeners) {
+ listener.onCapabilitiesRemoved(getCapabilities());
+ }
+ }
+}
--- /dev/null
+module netconf-mdsal-monitoring {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring";
+ prefix "nmmonitor";
+
+ import netconf-northbound-mapper { prefix nnm; revision-date 2015-01-14; }
+ import opendaylight-md-sal-binding {prefix md-sal-binding; revision-date 2013-10-28;}
+ import netconf-northbound { prefix nn; revision-date 2015-01-14; }
+ import config { prefix config; revision-date 2013-04-05; }
+
+ organization "Cisco Systems, Inc.";
+
+ description
+ "This module contains the base YANG definitions for
+ an MD-SAL monitoring mapper implementation";
+
+ revision "2015-02-18" {
+ description
+ "Initial revision.";
+ }
+
+ identity netconf-mdsal-monitoring-mapper {
+ base config:module-type;
+ config:provided-service nnm:netconf-northbound-mapper;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netconf-mdsal-monitoring-mapper {
+ when "/config:modules/config:module/config:type = 'netconf-mdsal-monitoring-mapper'";
+
+ container server-monitoring {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity nn:netconf-server-monitoring;
+ }
+ }
+ }
+
+ container aggregator {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity nnm:netconf-mapper-registry;
+ }
+ }
+ }
+
+ container binding-aware-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-broker-osgi-registry;
+ }
+ }
+ }
+ }
+ }
+
+}
package org.opendaylight.controller.netconf.api.monitoring;
import com.google.common.base.Optional;
-import java.util.Set;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
String getSchemaForCapability(String moduleName, Optional<String> revision);
- Set<String> getCapabilities();
+ Capabilities getCapabilities();
+ /**
+ * Allows push based state information transfer. After the listener is registered, current state is pushed to the listener.
+ */
+ AutoCloseable registerListener(MonitoringListener listener);
+
+ interface MonitoringListener {
+
+ // TODO more granular updates would make sense
+ void onStateChanged(NetconfState state);
+ }
}
<artifactId>netconf-monitoring</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>mdsal-netconf-monitoring</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-netty-util</artifactId>
--- /dev/null
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+
+import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
+
+public class NetconfMapperAggregatorModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfMapperAggregatorModule {
+ public NetconfMapperAggregatorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfMapperAggregatorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final org.opendaylight.controller.config.yang.config.netconf.northbound.impl.NetconfMapperAggregatorModule oldModule, final java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {}
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new AggregatedNetconfOperationServiceFactory();
+ }
+
+}
--- /dev/null
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-northbound-impl yang module local name: netconf-mapper-aggregator
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Tue Feb 17 17:24:19 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+public class NetconfMapperAggregatorModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfMapperAggregatorModuleFactory {
+
+}
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
public class NetconfServerDispatcherModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerDispatcherModule {
public java.lang.AutoCloseable createInstance() {
final AggregatedNetconfOperationServiceFactory aggregatedOpProvider = getAggregatedOpProvider();
- final NetconfMonitoringService monitoringService = startMonitoringService(aggregatedOpProvider);
+ final NetconfMonitoringService monitoringService = getServerMonitorDependency();
final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
getTimerDependency(), aggregatedOpProvider, new SessionIdProvider(), getConnectionTimeoutMillis(), CommitNotifier.NoopCommitNotifier.getInstance(), monitoringService);
final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
}
- private NetconfMonitoringServiceImpl startMonitoringService(final AggregatedNetconfOperationServiceFactory netconfOperationProvider) {
- return new NetconfMonitoringServiceImpl(netconfOperationProvider);
- }
-
private AggregatedNetconfOperationServiceFactory getAggregatedOpProvider() {
final AggregatedNetconfOperationServiceFactory netconfOperationProvider = new AggregatedNetconfOperationServiceFactory();
for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getMappersDependency()) {
--- /dev/null
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+
+import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
+
+public class NetconfServerMonitoringModule extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerMonitoringModule {
+ public NetconfServerMonitoringModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfServerMonitoringModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.netconf.northbound.impl.NetconfServerMonitoringModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new NetconfMonitoringServiceImpl(getAggregatorDependency());
+ }
+
+}
--- /dev/null
+/*
+* Generated file
+*
+* Generated from: yang module name: netconf-northbound-impl yang module local name: netconf-server-monitoring-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Tue Feb 17 17:24:19 CET 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.netconf.northbound.impl;
+public class NetconfServerMonitoringModuleFactory extends org.opendaylight.controller.config.yang.config.netconf.northbound.impl.AbstractNetconfServerMonitoringModuleFactory {
+
+}
@Override
protected void sessionUp() {
- super.sessionUp();
Preconditions.checkState(loginTime == null, "Session is already up");
this.loginTime = new Date();
+ super.sessionUp();
}
public void onIncommingRpcSuccess() {
@Override
public void onSessionUp(final NetconfServerSession netconfNetconfServerSession) {
monitoringService.onSessionUp(netconfNetconfServerSession);
+ // FIXME monitoring service should be also notified about all the other changes to netconf session (from ietf-netconf-monitoring point of view)
+ // This means also notifying after every message is processed
}
@Override
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
}
private NetconfHelloMessage createHelloMessage(final long sessionId, final NetconfMonitoringService capabilityProvider) throws NetconfDocumentedException {
- return NetconfHelloMessage.createServerHello(Sets.union(capabilityProvider.getCapabilities(), baseCapabilities), sessionId);
+ return NetconfHelloMessage.createServerHello(Sets.union(DefaultCommit.transformCapabilities(capabilityProvider.getCapabilities()), baseCapabilities), sessionId);
}
}
package org.opendaylight.controller.netconf.impl.mapping.operations;
+import com.google.common.base.Function;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
import java.io.InputStream;
+import java.util.Set;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
removePersisterAttributes(requestMessage);
Element cfgSnapshot = getConfigSnapshot(operationRouter);
LOG.debug("Config snapshot retrieved successfully {}", cfgSnapshot);
- notificationProducer.sendCommitNotification("ok", cfgSnapshot, cap.getCapabilities());
+ notificationProducer.sendCommitNotification("ok", cfgSnapshot, transformCapabilities(cap.getCapabilities()));
}
return subsequentOperation.execute(requestMessage);
}
+ // FIXME move somewhere to util since this is required also by negotiatiorFactory
+ public static Set<String> transformCapabilities(final Capabilities capabilities) {
+ return Sets.newHashSet(Collections2.transform(capabilities.getCapability(), new Function<Uri, String>() {
+ @Override
+ public String apply(final Uri uri) {
+ return uri.getValue();
+ }
+ }));
+ }
+
@Override
protected Element handle(Document document, XmlElement message, NetconfOperationChainedExecution subsequentOperation) throws NetconfDocumentedException {
throw new UnsupportedOperationException("Never gets called");
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.util.CloseableUtil;
/**
* NetconfOperationService aggregator. Makes a collection of operation services accessible as one.
*/
-public class AggregatedNetconfOperationServiceFactory implements NetconfOperationServiceFactory, NetconfOperationServiceFactoryListener {
+public class AggregatedNetconfOperationServiceFactory implements NetconfOperationServiceFactory, NetconfOperationServiceFactoryListener, AutoCloseable {
private final Set<NetconfOperationServiceFactory> factories = new HashSet<>();
private final Multimap<NetconfOperationServiceFactory, AutoCloseable> registrations = HashMultimap.create();
return new AggregatedNetconfOperation(factories, netconfSessionIdForReporting);
}
+ @Override
+ public synchronized void close() throws Exception {
+ factories.clear();
+ for (AutoCloseable reg : registrations.values()) {
+ reg.close();
+ }
+ registrations.clear();
+ listeners.clear();
+ }
+
private static final class AggregatedNetconfOperation implements NetconfOperationService {
private final Set<NetconfOperationService> services;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import io.netty.util.internal.ConcurrentSet;
import java.util.ArrayList;
import java.util.Collection;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfStateBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class NetconfMonitoringServiceImpl implements NetconfMonitoringService {
+public class NetconfMonitoringServiceImpl implements NetconfMonitoringService, AutoCloseable {
private static final Schema.Location NETCONF_LOCATION = new Schema.Location(Schema.Location.Enumeration.NETCONF);
private static final List<Schema.Location> NETCONF_LOCATIONS = ImmutableList.of(NETCONF_LOCATION);
return input.toManagementSession();
}
};
-
- private final Set<NetconfManagementSession> sessions = new ConcurrentSet<>();
- private final NetconfOperationServiceFactory netconfOperationProvider;
- private final Map<String, Capability> capabilities = new ConcurrentHashMap<>();
- private static final Function<Capability, String> CAPABILITY_TO_URI = new Function<Capability, String>() {
+ private static final Function<Capability, Uri> CAPABILITY_TO_URI = new Function<Capability, Uri>() {
@Override
- public String apply(final Capability input) {
- return input.getCapabilityUri();
+ public Uri apply(final Capability input) {
+ return new Uri(input.getCapabilityUri());
}
};
- // FIXME check threadsafety
+ private final Set<NetconfManagementSession> sessions = new ConcurrentSet<>();
+ private final NetconfOperationServiceFactory netconfOperationProvider;
+ private final Map<Uri, Capability> capabilities = new ConcurrentHashMap<>();
+
+ private final Set<MonitoringListener> listeners = Sets.newHashSet();
public NetconfMonitoringServiceImpl(final NetconfOperationServiceFactory netconfOperationProvider) {
this.netconfOperationProvider = netconfOperationProvider;
}
@Override
- public void onSessionUp(final NetconfManagementSession session) {
+ public synchronized void onSessionUp(final NetconfManagementSession session) {
LOG.debug("Session {} up", session);
Preconditions.checkState(!sessions.contains(session), "Session %s was already added", session);
sessions.add(session);
+ notifyListeners();
}
@Override
- public void onSessionDown(final NetconfManagementSession session) {
+ public synchronized void onSessionDown(final NetconfManagementSession session) {
LOG.debug("Session {} down", session);
Preconditions.checkState(sessions.contains(session), "Session %s not present", session);
sessions.remove(session);
+ notifyListeners();
}
@Override
- public Sessions getSessions() {
+ public synchronized Sessions getSessions() {
return new SessionsBuilder().setSession(ImmutableList.copyOf(Collections2.transform(sessions, SESSION_FUNCTION))).build();
}
@Override
- public Schemas getSchemas() {
+ public synchronized Schemas getSchemas() {
try {
return transformSchemas(netconfOperationProvider.getCapabilities());
} catch (final RuntimeException e) {
}
@Override
- public String getSchemaForCapability(final String moduleName, final Optional<String> revision) {
+ public synchronized String getSchemaForCapability(final String moduleName, final Optional<String> revision) {
// FIXME not effective at all
}
@Override
- public Set<String> getCapabilities() {
- return capabilities.keySet();
+ public synchronized Capabilities getCapabilities() {
+ return new CapabilitiesBuilder().setCapability(Lists.newArrayList(capabilities.keySet())).build();
+ }
+
+ @Override
+ public synchronized AutoCloseable registerListener(final MonitoringListener listener) {
+ listeners.add(listener);
+ listener.onStateChanged(getCurrentNetconfState());
+ return new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ listeners.remove(listener);
+ }
+ };
+ }
+
+ private NetconfState getCurrentNetconfState() {
+ return new NetconfStateBuilder()
+ .setCapabilities(getCapabilities())
+ .setSchemas(getSchemas())
+ .setSessions(getSessions())
+ .build();
}
private static Schemas transformSchemas(final Set<Capability> caps) {
}
@Override
- public void onCapabilitiesAdded(final Set<Capability> addedCaps) {
- // FIXME what check for duplicates
+ public synchronized void onCapabilitiesAdded(final Set<Capability> addedCaps) {
+ // FIXME howto check for duplicates
this.capabilities.putAll(Maps.uniqueIndex(addedCaps, CAPABILITY_TO_URI));
+ notifyListeners();
+ }
+
+ private void notifyListeners() {
+ for (final MonitoringListener listener : listeners) {
+ listener.onStateChanged(getCurrentNetconfState());
+ }
}
@Override
- public void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
+ public synchronized void onCapabilitiesRemoved(final Set<Capability> addedCaps) {
for (final Capability addedCap : addedCaps) {
capabilities.remove(addedCap.getCapabilityUri());
}
+ notifyListeners();
+ }
+
+ @Override
+ public synchronized void close() throws Exception {
+ listeners.clear();
+ sessions.clear();
+ capabilities.clear();
}
}
if (!handlingPriority.equals(HandlingPriority.CANNOT_HANDLE)) {
Preconditions.checkState(!sortedPriority.containsKey(handlingPriority),
- "Multiple %s available to handle message %s with priority %s",
- NetconfOperation.class.getName(), message, handlingPriority);
+ "Multiple %s available to handle message %s with priority %s, %s and %s",
+ NetconfOperation.class.getName(), message, handlingPriority, netconfOperation, sortedPriority.get(handlingPriority));
sortedPriority.put(handlingPriority, netconfOperation);
}
}
import org.opendaylight.controller.netconf.api.util.NetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
@Override
public void removedService(ServiceReference<NetconfOperationServiceFactory> reference,
NetconfOperationServiceFactory netconfOperationServiceFactory) {
- if (netconfOperationServiceFactory != null)
+ if (netconfOperationServiceFactory != null) {
factoriesListener.onRemoveNetconfOperationServiceFactory(netconfOperationServiceFactory);
+ }
}
}
}
}
+ container server-monitor {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity nn:netconf-server-monitoring;
+ }
+ }
+ }
+
container timer {
uses config:service-ref {
refine type {
}
}
+
+ identity netconf-server-monitoring-impl {
+ base config:module-type;
+ config:provided-service nn:netconf-server-monitoring;
+ config:java-name-prefix NetconfServerMonitoring;
+ }
+
+ // TODO Monitoring could expose the monitoring data over JMX...
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netconf-server-monitoring-impl {
+ when "/config:modules/config:module/config:type = 'netconf-server-monitoring-impl'";
+
+ container aggregator {
+ uses config:service-ref {
+ refine type {
+ config:required-identity nnm:netconf-northbound-mapper;
+ }
+ }
+ }
+
+ }
+ }
+
+ identity netconf-mapper-aggregator {
+ base config:module-type;
+ config:provided-service nnm:netconf-northbound-mapper;
+ config:provided-service nnm:netconf-mapper-registry;
+ config:java-name-prefix NetconfMapperAggregator;
+ description "Aggregated operation provider for netconf servers. Joins all the operations and capabilities of all the mappers it aggregates and exposes them as a single service. The dependency orientation is reversed in order to prevent cyclic dependencies when monitoring service is considered";
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netconf-mapper-aggregator {
+ when "/config:modules/config:module/config:type = 'netconf-mapper-aggregator'";
+
+ }
+ }
+
}
\ No newline at end of file
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anySetOf;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
NetconfMonitoringService monitoring = mock(NetconfMonitoringService.class);
doNothing().when(monitoring).onSessionUp(any(NetconfServerSession.class));
doNothing().when(monitoring).onSessionDown(any(NetconfServerSession.class));
- doReturn(Collections.emptySet()).when(monitoring).getCapabilities();
+ doReturn(new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+
+ }
+ }).when(monitoring).registerListener(any(NetconfMonitoringService.MonitoringListener.class));
+ doNothing().when(monitoring).onCapabilitiesAdded(anySetOf(Capability.class));
+ doNothing().when(monitoring).onCapabilitiesRemoved(anySetOf(Capability.class));
+ doReturn(new CapabilitiesBuilder().setCapability(Collections.<Uri>emptyList()).build()).when(monitoring).getCapabilities();
return monitoring;
}
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import com.google.common.collect.Sets;
+import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.CapabilitiesBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
notifier = mock(DefaultCommitNotificationProducer.class);
doNothing().when(notifier).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
cap = mock(NetconfMonitoringService.class);
- doReturn(Sets.newHashSet()).when(cap).getCapabilities();
+ doReturn(new CapabilitiesBuilder().setCapability(Collections.<Uri>emptyList()).build()).when(cap).getCapabilities();
Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/editConfig_expectedResult.xml");
doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class));
commit = new DefaultCommit(notifier, cap, "", router);
import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.netconf.api.util.NetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
}
notificationVerifier.assertNotificationCount(2);
- notificationVerifier.assertNotificationContent(0, 0, 0, 9);
- notificationVerifier.assertNotificationContent(1, 4, 3, 9);
+ notificationVerifier.assertNotificationContent(0, 0, 0, 8);
+ notificationVerifier.assertNotificationContent(1, 4, 3, 8);
mockedAggregator.assertSnapshotCount(2);
// Capabilities are stripped for persister
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.controller.netconf.impl.osgi;
-
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+package org.opendaylight.controller.netconf.mapping.api;
public interface NetconfOperationServiceFactoryListener {
config:java-class "org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory";
}
+ identity netconf-mapper-registry {
+ base "config:service-type";
+ config:java-class "org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactoryListener";
+ }
+
}
\ No newline at end of file
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
<name>inmemory-data-broker</name>
</dom-broker>
+ <mapper-aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-mapper-registry</type>
+ <name>mapper-aggregator-registry</name>
+ </mapper-aggregator>
</module>
<module>
<name>netconf-mdsal-server-dispatcher</name>
<mappers xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">dom:netconf-northbound-mapper</type>
- <name>netconf-mdsal-mapper</name>
+ <name>mapper-aggregator</name>
</mappers>
+ <server-monitor xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-monitoring</type>
+ <name>server-monitor</name>
+ </server-monitor>
<boss-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-threadgroup</type>
<name>global-boss-group</name>
</timer>
</module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">prefix:netconf-mdsal-monitoring-mapper</type>
+ <name>netconf-mdsal-monitoring-mapper</name>
+ <server-monitoring xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-monitoring</type>
+ <name>server-monitor</name>
+ </server-monitoring>
+ <binding-aware-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-broker-osgi-registry</type>
+ <name>binding-osgi-broker</name>
+ </binding-aware-broker>
+ <aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-mapper-registry</type>
+ <name>mapper-aggregator-registry</name>
+ </aggregator>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">prefix:netconf-mapper-aggregator</type>
+ <name>mapper-aggregator</name>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">prefix:netconf-server-monitoring-impl</type>
+ <name>server-monitor</name>
+ <aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">dom:netconf-northbound-mapper</type>
+ <name>mapper-aggregator</name>
+ </aggregator>
+ </module>
+
<module>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">prefix:netconf-northbound-ssh</type>
<name>netconf-mdsal-ssh-server</name>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-monitoring</type>
+ <instance>
+ <name>server-monitor</name>
+ <provider>/modules/module[type='netconf-server-monitoring-impl'][name='server-monitor']</provider>
+ </instance>
+ </service>
<service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-northbound-mapper</type>
<instance>
<provider>/modules/module[type='netconf-mdsal-mapper'][name='netconf-mdsal-mapper']</provider>
</instance>
</service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-northbound-mapper</type>
+ <instance>
+ <name>mapper-aggregator</name>
+ <provider>/modules/module[type='netconf-mapper-aggregator'][name='mapper-aggregator']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">prefix:netconf-mapper-registry</type>
+ <instance>
+ <name>mapper-aggregator-registry</name>
+ <provider>/modules/module[type='netconf-mapper-aggregator'][name='mapper-aggregator']</provider>
+ </instance>
+ </service>
<service>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">prefix:netconf-server-dispatcher</type>
<instance>
</configuration>
<required-capabilities>
<capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper?module=netconf-mdsal-mapper&revision=2015-01-14</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring?module=netconf-mdsal-monitoring&revision=2015-02-18</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh?module=netconf-northbound-ssh&revision=2015-01-14</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl?module=netconf-northbound-impl&revision=2015-01-12</capability>
<capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled?module=threadpool-impl-scheduled&revision=2013-12-01</capability>
*/
package org.opendaylight.controller.netconf.monitoring.osgi;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
-import java.util.List;
import java.util.Set;
import org.opendaylight.controller.netconf.api.Capability;
import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
private final NetconfMonitoringOperationService operationService;
- private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
-
- @Override
- public String getCapabilityUri() {
- return MonitoringConstants.URI;
- }
-
- @Override
- public Optional<String> getModuleNamespace() {
- return Optional.of(MonitoringConstants.NAMESPACE);
- }
-
- @Override
- public Optional<String> getModuleName() {
- return Optional.of(MonitoringConstants.MODULE_NAME);
- }
-
- @Override
- public Optional<String> getRevision() {
- return Optional.of(MonitoringConstants.MODULE_REVISION);
- }
-
- @Override
- public Optional<String> getCapabilitySchema() {
- return Optional.absent();
- }
-
- @Override
- public Collection<String> getLocation() {
- return Collections.emptyList();
- }
- });
-
private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
@Override
public void close() throws Exception {
}
};
- private final List<CapabilityListener> listeners = new ArrayList<>();
-
public NetconfMonitoringOperationServiceFactory(final NetconfMonitoringOperationService operationService) {
this.operationService = operationService;
}
@Override
public Set<Capability> getCapabilities() {
- return CAPABILITIES;
+ return Collections.emptySet();
}
@Override
public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
- listener.onCapabilitiesAdded(getCapabilities());
- listeners.add(listener);
return AUTO_CLOSEABLE;
}
@Override
- public void close() {
- for (final CapabilityListener listener : listeners) {
- listener.onCapabilitiesRemoved(getCapabilities());
- }
- }
+ public void close() {}
}
}
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
-import com.google.common.base.Optional;
-import java.util.Collections;
import org.junit.Test;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
-import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
public class NetconfMonitoringOperationServiceTest {
@Test
assertEquals(2, service.getNetconfOperations().size());
- assertEquals(Optional.<String>absent(), serviceFactory.getCapabilities().iterator().next().getCapabilitySchema());
- assertEquals(Collections.<String>emptyList(), serviceFactory.getCapabilities().iterator().next().getLocation());
- assertEquals(Optional.of(MonitoringConstants.MODULE_REVISION), serviceFactory.getCapabilities().iterator().next().getRevision());
- assertEquals(Optional.of(MonitoringConstants.MODULE_NAME), serviceFactory.getCapabilities().iterator().next().getModuleName());
- assertEquals(Optional.of(MonitoringConstants.NAMESPACE), serviceFactory.getCapabilities().iterator().next().getModuleNamespace());
- assertEquals(MonitoringConstants.URI, serviceFactory.getCapabilities().iterator().next().getCapabilityUri());
}
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
}
@Override
- public Set<String> getCapabilities() {
+ public Capabilities getCapabilities() {
return null;
}
+
+ @Override
+ public AutoCloseable registerListener(final MonitoringListener listener) {
+ return new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ // NOOP
+ }
+ };
+ }
};
final NetconfState model = new NetconfState(service);
final String xml = XmlUtil.toString(new JaxBSerializer().toXml(model)).replaceAll("\\s", "");
<module>netconf-impl</module>
<module>config-netconf-connector</module>
<module>mdsal-netconf-connector</module>
+ <module>mdsal-netconf-monitoring</module>
<module>netconf-util</module>
<module>netconf-netty-util</module>
<module>config-persister-impl</module>