From ec036b343d64ade111b24f3c590aa8f8d6cacf1d Mon Sep 17 00:00:00 2001 From: Tomas Cere Date: Mon, 17 Aug 2015 15:14:29 +0200 Subject: [PATCH] BUG 2920: Extend and simplify netconf connector topology model. Add shared schema repository and netconf topology binding. Create a default schema repository instance. Add topology config. Simplifiy netconf connector model to use new netconf topology with backwards compatibility. Bump netconf connector schema revision. Change-Id: I3978a0a7e6e3c08dba52e65912bfe33ad46b4cf8 Signed-off-by: Tomas Cere --- features/netconf-connector/pom.xml | 11 + .../src/main/resources/features.xml | 5 + .../netconf/netconf-artifacts/pom.xml | 12 + .../initial/99-netconf-connector.xml | 2 +- .../netconf/netconf-topology-config/pom.xml | 43 +++ .../resources/initial/02-netconf-topology.xml | 62 ++++ opendaylight/netconf/netconf-topology/pom.xml | 123 ++++++++ .../topology/NetconfTopologyModule.java | 35 +++ .../NetconfTopologyModuleFactory.java | 21 ++ .../SchemaRepositoryImplModule.java | 43 +++ .../SchemaRepositoryImplModuleFactory.java | 28 ++ .../netconf/topology/NetconfTopology.java | 31 ++ .../topology/SchemaRepositoryProvider.java | 16 + .../topology/TopologyMountPointFacade.java | 129 ++++++++ .../topology/impl/NetconfTopologyImpl.java | 296 ++++++++++++++++++ .../src/main/yang/netconf-topology.yang | 111 +++++++ .../main/yang/shared-schema-repository.yang | 41 +++ opendaylight/netconf/pom.xml | 2 + .../netconf/sal-netconf-connector/pom.xml | 58 ++++ .../netconf/NetconfConnectorModule.java | 134 +++++--- .../NetconfConnectorModuleFactory.java | 25 -- .../netconf/sal/NetconfDeviceDataBroker.java | 2 +- .../sal/NetconfDeviceNotificationService.java | 2 +- .../netconf/sal/NetconfDeviceSalProvider.java | 10 +- .../yang/odl-sal-netconf-connector-cfg.yang | 14 +- 25 files changed, 1183 insertions(+), 73 deletions(-) create mode 100644 opendaylight/netconf/netconf-topology-config/pom.xml create mode 100644 opendaylight/netconf/netconf-topology-config/src/main/resources/initial/02-netconf-topology.xml create mode 100644 opendaylight/netconf/netconf-topology/pom.xml create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModule.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModuleFactory.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModule.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModuleFactory.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/SchemaRepositoryProvider.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/TopologyMountPointFacade.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java create mode 100644 opendaylight/netconf/netconf-topology/src/main/yang/netconf-topology.yang create mode 100644 opendaylight/netconf/netconf-topology/src/main/yang/shared-schema-repository.yang diff --git a/features/netconf-connector/pom.xml b/features/netconf-connector/pom.xml index fe50cec1e4..479309522b 100644 --- a/features/netconf-connector/pom.xml +++ b/features/netconf-connector/pom.xml @@ -19,6 +19,7 @@ jar features.xml + 1.3.0-SNAPSHOT @@ -103,6 +104,16 @@ ${project.groupId} netconf-connector-config + + ${project.groupId} + netconf-topology + + + ${project.groupId} + netconf-topology-config + config + xml + ${project.groupId} netconf-tcp diff --git a/features/netconf-connector/src/main/resources/features.xml b/features/netconf-connector/src/main/resources/features.xml index eb8daa622e..0f8d35d669 100644 --- a/features/netconf-connector/src/main/resources/features.xml +++ b/features/netconf-connector/src/main/resources/features.xml @@ -35,6 +35,11 @@ odl-mdsal-models mvn:org.opendaylight.netconf/sal-netconf-connector/${controller.mdsal.version} mvn:org.opendaylight.controller.model/model-inventory/${controller.mdsal.version} + mvn:org.opendaylight.netconf/netconf-topology/${netconf.version} + mvn:org.opendaylight.netconf/sal-netconf-connector/${netconf.connector.version} + mvn:org.opendaylight.netconf/netconf-config-dispatcher/${netconf.version} + mvn:org.opendaylight.netconf/netconf-config/${netconf.version}/xml/config + mvn:org.opendaylight.netconf/netconf-topology-config/${netconf.version}/xml/config diff --git a/opendaylight/netconf/netconf-artifacts/pom.xml b/opendaylight/netconf/netconf-artifacts/pom.xml index 00c55acf65..8a223c4317 100644 --- a/opendaylight/netconf/netconf-artifacts/pom.xml +++ b/opendaylight/netconf/netconf-artifacts/pom.xml @@ -196,6 +196,18 @@ mdsal-netconf-notification ${project.version} + + ${project.groupId} + netconf-topology + ${project.version} + + + ${project.groupId} + netconf-topology-config + ${project.version} + config + xml + ${project.groupId} netconf-client diff --git a/opendaylight/netconf/netconf-connector-config/src/main/resources/initial/99-netconf-connector.xml b/opendaylight/netconf/netconf-connector-config/src/main/resources/initial/99-netconf-connector.xml index d743bbcd40..62b2c8de44 100644 --- a/opendaylight/netconf/netconf-connector-config/src/main/resources/initial/99-netconf-connector.xml +++ b/opendaylight/netconf/netconf-connector-config/src/main/resources/initial/99-netconf-connector.xml @@ -50,6 +50,6 @@ - urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf?module=odl-sal-netconf-connector-cfg&revision=2013-10-28 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:connector:netconf?module=odl-sal-netconf-connector-cfg&revision=2015-08-03 diff --git a/opendaylight/netconf/netconf-topology-config/pom.xml b/opendaylight/netconf/netconf-topology-config/pom.xml new file mode 100644 index 0000000000..9858f6c62a --- /dev/null +++ b/opendaylight/netconf/netconf-topology-config/pom.xml @@ -0,0 +1,43 @@ + + + + netconf-subsystem + org.opendaylight.netconf + 1.0.0-SNAPSHOT + ../ + + 4.0.0 + + netconf-topology-config + Configuration files for netconf topology + jar + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/02-netconf-topology.xml + xml + config + + + + + + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/netconf-topology-config/src/main/resources/initial/02-netconf-topology.xml b/opendaylight/netconf/netconf-topology-config/src/main/resources/initial/02-netconf-topology.xml new file mode 100644 index 0000000000..b4581c497f --- /dev/null +++ b/opendaylight/netconf/netconf-topology-config/src/main/resources/initial/02-netconf-topology.xml @@ -0,0 +1,62 @@ + + + + + + + + + prefix:netconf-topology-impl + default-netconf-topology + + prefix:netty-event-executor + global-event-executor + + + prefix:binding-broker-osgi-registry + binding-osgi-broker + + + prefix:dom-broker-osgi-registry + dom-broker + + + prefix:netconf-client-dispatcher + global-netconf-dispatcher + + + prefix:threadpool + global-netconf-processing-executor + + + prefix:scheduled-threadpool + global-netconf-ssh-scheduled-executor + + + prefix:shared-schema-repository + default-shared-schema-repository + + + + + + + prefix:netconf-topology + + default-netconf-topology + /modules/module[type='netconf-topology-impl'][name='default-netconf-topology'] + + + + + + + urn:opendaylight:params:xml:ns:yang:controller:netconf:topology?module=netconf-topology&revision=2015-07-27 + + \ No newline at end of file diff --git a/opendaylight/netconf/netconf-topology/pom.xml b/opendaylight/netconf/netconf-topology/pom.xml new file mode 100644 index 0000000000..89202d8ebd --- /dev/null +++ b/opendaylight/netconf/netconf-topology/pom.xml @@ -0,0 +1,123 @@ + + + + netconf-subsystem + org.opendaylight.netconf + 1.0.0-SNAPSHOT + ../ + + 4.0.0 + + netconf-topology + bundle + + + org.opendaylight.controller + sal-binding-api + + + org.opendaylight.controller + sal-binding-config + + + org.opendaylight.mdsal + mdsal-binding-generator-impl + + + ${project.groupId} + netconf-config-dispatcher + + + org.opendaylight.controller + sal-core-api + + + org.opendaylight.controller + threadpool-config-api + + + org.opendaylight.yangtools + yang-parser-impl + + + org.opendaylight.controller + yang-jmx-generator-plugin + + + org.opendaylight.netconf + sal-netconf-connector + + + + + + + org.apache.felix + maven-bundle-plugin + + + * + + + + + + org.opendaylight.yangtools + yang-maven-plugin + + + config + + generate-sources + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + ${jmxGeneratorPath} + + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + + + + org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl + ${salGeneratorPath} + + + true + + + + + + org.opendaylight.controller + yang-jmx-generator-plugin + ${config.version} + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config; + + + + + + + + + \ No newline at end of file diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModule.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModule.java new file mode 100644 index 0000000000..e4321b7898 --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModule.java @@ -0,0 +1,35 @@ +/* + * 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.topology; + +import org.opendaylight.netconf.topology.impl.NetconfTopologyImpl; + +public class NetconfTopologyModule extends org.opendaylight.controller.config.yang.netconf.topology.AbstractNetconfTopologyModule { + public NetconfTopologyModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public NetconfTopologyModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.netconf.topology.NetconfTopologyModule oldModule, AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + // add custom validation form module attributes here. + this.getClientDispatcherDependency(); + } + + @Override + public AutoCloseable createInstance() { + return new NetconfTopologyImpl(getTopologyId(), getClientDispatcherDependency(), getBindingRegistryDependency(), + getDomRegistryDependency(), getEventExecutorDependency(), getKeepaliveExecutorDependency(), + getProcessingExecutorDependency(), getSharedSchemaRepositoryDependency()); + } + +} diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModuleFactory.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModuleFactory.java new file mode 100644 index 0000000000..f8dd1991de --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/NetconfTopologyModuleFactory.java @@ -0,0 +1,21 @@ +/* + * 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 + */ +/* +* Generated file +* +* Generated from: yang module name: netconf-topology yang module local name: netconf-topology-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Tue Jul 28 15:33:44 CEST 2015 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.netconf.topology; + +public class NetconfTopologyModuleFactory extends org.opendaylight.controller.config.yang.netconf.topology.AbstractNetconfTopologyModuleFactory { + +} diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModule.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModule.java new file mode 100644 index 0000000000..5ea2f50fc9 --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModule.java @@ -0,0 +1,43 @@ +package org.opendaylight.controller.config.yang.netconf.topology.shared.schema.repository; + +import org.opendaylight.netconf.topology.SchemaRepositoryProvider; +import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository; + +public class SchemaRepositoryImplModule extends org.opendaylight.controller.config.yang.netconf.topology.shared.schema.repository.AbstractSchemaRepositoryImplModule { + public SchemaRepositoryImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public SchemaRepositoryImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.netconf.topology.shared.schema.repository.SchemaRepositoryImplModule 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 SchemaRepositoryProviderAutoCloseAble(this); + } + + private static class SchemaRepositoryProviderAutoCloseAble implements SchemaRepositoryProvider, AutoCloseable { + + private final SharedSchemaRepository schemaRepository; + + public SchemaRepositoryProviderAutoCloseAble(SchemaRepositoryImplModule module) { + schemaRepository = new SharedSchemaRepository(module.getIdentifier().getInstanceName()); + } + + @Override + public void close() throws Exception { + //NOOP + } + + @Override + public SharedSchemaRepository getSharedSchemaRepository() { + return schemaRepository; + } + } +} diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModuleFactory.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModuleFactory.java new file mode 100644 index 0000000000..b3a64d496e --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/controller/config/yang/netconf/topology/shared/schema/repository/SchemaRepositoryImplModuleFactory.java @@ -0,0 +1,28 @@ +/* +* Generated file +* +* Generated from: yang module name: shared-schema-repository yang module local name: shared-schema-repository-impl +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Tue Sep 08 13:43:39 CEST 2015 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.controller.config.yang.netconf.topology.shared.schema.repository; + +import com.google.common.collect.Sets; +import java.util.Set; +import org.opendaylight.controller.config.api.DependencyResolverFactory; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.osgi.framework.BundleContext; + +public class SchemaRepositoryImplModuleFactory extends org.opendaylight.controller.config.yang.netconf.topology.shared.schema.repository.AbstractSchemaRepositoryImplModuleFactory { + + public static final ModuleIdentifier defaultInstanceId = new ModuleIdentifier(NAME, "default-shared-schema-repository"); + + @Override + public Set getDefaultModules(DependencyResolverFactory dependencyResolverFactory, BundleContext bundleContext) { + SchemaRepositoryImplModule defaultModule = new SchemaRepositoryImplModule( + defaultInstanceId, dependencyResolverFactory.createDependencyResolver(defaultInstanceId)); + return Sets.newHashSet(defaultModule); + } +} diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java new file mode 100644 index 0000000000..d9ad8046a2 --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/NetconfTopology.java @@ -0,0 +1,31 @@ +/* + * 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.netconf.topology; + +import com.google.common.util.concurrent.ListenableFuture; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler; +import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities; +import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; + +// TODO maybe rename to NetconfTopologyDispatcher? +public interface NetconfTopology { + + String getTopologyId(); + + DataBroker getDataBroker(); + + ListenableFuture connectNode(NodeId nodeId, Node configNode); + + ListenableFuture disconnectNode(NodeId nodeId); + + void registerConnectionStatusListener(NodeId node, RemoteDeviceHandler listener); +} diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/SchemaRepositoryProvider.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/SchemaRepositoryProvider.java new file mode 100644 index 0000000000..e4664d6f3b --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/SchemaRepositoryProvider.java @@ -0,0 +1,16 @@ +/* + * 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.netconf.topology; + +import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository; + +public interface SchemaRepositoryProvider{ + + SharedSchemaRepository getSharedSchemaRepository(); +} diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/TopologyMountPointFacade.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/TopologyMountPointFacade.java new file mode 100644 index 0000000000..f5900064f0 --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/TopologyMountPointFacade.java @@ -0,0 +1,129 @@ +/* + * 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.netconf.topology; + +import com.google.common.base.Preconditions; +import java.util.ArrayList; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMNotification; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler; +import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences; +import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceDataBroker; +import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceNotificationService; +import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalProvider; +import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TopologyMountPointFacade implements AutoCloseable, RemoteDeviceHandler { + + private static final Logger LOG = LoggerFactory.getLogger(TopologyMountPointFacade.class); + + private final RemoteDeviceId id; + private final Broker domBroker; + private final BindingAwareBroker bindingBroker; + private final long defaultRequestTimeoutMillis; + + private SchemaContext remoteSchemaContext = null; + private NetconfSessionPreferences netconfSessionPreferences = null; + private DOMRpcService deviceRpc = null; + private final NetconfDeviceSalProvider salProvider; + + private final ArrayList> connectionStatusListeners = new ArrayList<>(); + + public TopologyMountPointFacade(final RemoteDeviceId id, + final Broker domBroker, + final BindingAwareBroker bindingBroker, + long defaultRequestTimeoutMillis) { + + this.id = id; + this.domBroker = domBroker; + this.bindingBroker = bindingBroker; + this.defaultRequestTimeoutMillis = defaultRequestTimeoutMillis; + this.salProvider = new NetconfDeviceSalProvider(id); + registerToSal(domBroker, bindingBroker); + } + + public void registerToSal(final Broker domRegistryDependency, final BindingAwareBroker bindingBroker) { + domRegistryDependency.registerProvider(salProvider); + bindingBroker.registerProvider(salProvider); + } + + @Override + public void onDeviceConnected(final SchemaContext remoteSchemaContext, + final NetconfSessionPreferences netconfSessionPreferences, + final DOMRpcService deviceRpc) { + // prepare our prerequisites for mountpoint + this.remoteSchemaContext = remoteSchemaContext; + this.netconfSessionPreferences = netconfSessionPreferences; + this.deviceRpc = deviceRpc; + for (RemoteDeviceHandler listener : connectionStatusListeners) { + listener.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc); + } + } + + @Override + public void onDeviceDisconnected() { + salProvider.getMountInstance().onTopologyDeviceDisconnected(); + for (RemoteDeviceHandler listener : connectionStatusListeners) { + listener.onDeviceDisconnected(); + } + } + + @Override + public void onDeviceFailed(Throwable throwable) { + salProvider.getMountInstance().onTopologyDeviceDisconnected(); + for (RemoteDeviceHandler listener : connectionStatusListeners) { + listener.onDeviceFailed(throwable); + } + } + + @Override + public void onNotification(DOMNotification domNotification) { + salProvider.getMountInstance().publish(domNotification); + } + + public void registerMountPoint() { + Preconditions.checkNotNull(id); + Preconditions.checkNotNull(remoteSchemaContext); + Preconditions.checkNotNull(netconfSessionPreferences); + + final DOMDataBroker netconfDeviceDataBroker = new NetconfDeviceDataBroker(id, remoteSchemaContext, deviceRpc, netconfSessionPreferences, defaultRequestTimeoutMillis); + final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService(); + + salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, netconfDeviceDataBroker, deviceRpc, notificationService); + } + + public void unregisterMountPoint() { + salProvider.getMountInstance().onTopologyDeviceDisconnected(); + } + + public void registerConnectionStatusListener(final RemoteDeviceHandler listener) { + connectionStatusListeners.add(listener); + } + + @Override + public void close() { + closeGracefully(salProvider); + } + + private void closeGracefully(final AutoCloseable resource) { + if (resource != null) { + try { + resource.close(); + } catch (final Exception e) { + LOG.warn("{}: Ignoring exception while closing {}", id, resource, e); + } + } + } +} diff --git a/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java new file mode 100644 index 0000000000..027836993f --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java @@ -0,0 +1,296 @@ +/* + * 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.netconf.topology.impl; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.netty.util.concurrent.EventExecutor; +import java.math.BigDecimal; +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; +import org.opendaylight.controller.config.threadpool.ThreadPool; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.netconf.client.NetconfClientDispatcher; +import org.opendaylight.netconf.client.conf.NetconfClientConfiguration; +import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration; +import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder; +import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; +import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPassword; +import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler; +import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice; +import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemas; +import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities; +import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator; +import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences; +import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade; +import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId; +import org.opendaylight.netconf.topology.NetconfTopology; +import org.opendaylight.netconf.topology.SchemaRepositoryProvider; +import org.opendaylight.netconf.topology.TopologyMountPointFacade; +import org.opendaylight.protocol.framework.ReconnectStrategy; +import org.opendaylight.protocol.framework.ReconnectStrategyFactory; +import org.opendaylight.protocol.framework.TimedReconnectStrategy; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory; +import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfTopologyImpl implements NetconfTopology, BindingAwareProvider, Provider, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyImpl.class); + + private final String topologyId; + private final NetconfClientDispatcher clientDispatcher; + private final BindingAwareBroker bindingAwareBroker; + private final Broker domBroker; + private final EventExecutor eventExecutor; + private final ScheduledThreadPool keepaliveExecutor; + private final ThreadPool processingExecutor; + private final SchemaRepositoryProvider sharedSchemaRepository; + + private SchemaSourceRegistry schemaSourceRegistry = null; + private SchemaContextFactory schemaContextFactory = null; + + private DOMMountPointService mountPointService = null; + private DataBroker dataBroker = null; + private final HashMap activeConnectors = new HashMap<>(); + + public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher, + final BindingAwareBroker bindingAwareBroker, final Broker domBroker, + final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor, + final ThreadPool processingExecutor, final SchemaRepositoryProvider sharedSchemaRepository) { + this.topologyId = topologyId; + this.clientDispatcher = clientDispatcher; + this.bindingAwareBroker = bindingAwareBroker; + this.domBroker = domBroker; + this.eventExecutor = eventExecutor; + this.keepaliveExecutor = keepaliveExecutor; + this.processingExecutor = processingExecutor; + this.sharedSchemaRepository = sharedSchemaRepository; + + registerToSal(this, this); + } + + private void registerToSal(BindingAwareProvider baProvider, Provider provider) { + domBroker.registerProvider(provider); + bindingAwareBroker.registerProvider(baProvider); + } + + @Override + public void close() throws Exception { + // close all existing connectors, delete whole topology in datastore? + for (NetconfConnectorDTO connectorDTO : activeConnectors.values()) { + connectorDTO.getCommunicator().disconnect(); + } + activeConnectors.clear(); + } + + @Override + public String getTopologyId() { + return topologyId; + } + + @Override + public DataBroker getDataBroker() { + return Preconditions.checkNotNull(dataBroker, "DataBroker not initialized yet"); + } + + @Override + public ListenableFuture connectNode(NodeId nodeId, Node configNode) { + return setupConnection(nodeId, configNode); + } + + @Override + public ListenableFuture disconnectNode(NodeId nodeId) { + if (!activeConnectors.containsKey(nodeId)) { + return Futures.immediateFailedFuture(new IllegalStateException("Unable to disconnect device that is not connected")); + } + + // retrieve connection, and disconnect it + activeConnectors.remove(nodeId).getCommunicator().disconnect(); + return Futures.immediateFuture(null); + } + + @Override + public void registerConnectionStatusListener(NodeId node, RemoteDeviceHandler listener) { + activeConnectors.get(node).getMountPointFacade().registerConnectionStatusListener(listener); + } + + private ListenableFuture setupConnection(final NodeId nodeId, + final Node configNode) { + final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class); + + final NetconfConnectorDTO deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode); + final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator(); + final NetconfReconnectingClientConfiguration clientConfig = getClientConfig(deviceCommunicator, netconfNode); + final ListenableFuture future = deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig); + + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(NetconfDeviceCapabilities result) { + LOG.debug("Connector for : " + nodeId.getValue() + " started succesfully"); + activeConnectors.put(nodeId, deviceCommunicatorDTO); + } + + @Override + public void onFailure(Throwable t) { + LOG.error("Connector for : " + nodeId.getValue() + " failed"); + // remove this node from active connectors? + } + }); + + return future; + } + + private NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, + final NetconfNode node) { + IpAddress ipAddress = node.getHost().getIpAddress(); + InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null ? + ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(), + node.getPort().getValue()); + RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address); + + // we might need to create a new SalFacade to maintain backwards compatibility with special case loopback connection + TopologyMountPointFacade mountPointFacade = + new TopologyMountPointFacade(remoteDeviceId, domBroker, bindingAwareBroker, node.getDefaultRequestTimeoutMillis()); + RemoteDeviceHandler salFacade = mountPointFacade; + if (node.getKeepaliveDelay() > 0) { + salFacade = new KeepaliveSalFacade(remoteDeviceId, mountPointFacade, keepaliveExecutor.getExecutor(), node.getKeepaliveDelay()); + } + + NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = + new NetconfDevice.SchemaResourcesDTO(schemaSourceRegistry, schemaContextFactory, new NetconfStateSchemas.NetconfStateSchemasResolverImpl()); + + NetconfDevice device = new NetconfDevice(schemaResourcesDTO, remoteDeviceId, salFacade, + processingExecutor.getExecutor(), node.isReconnectOnChangedSchema()); + + return new NetconfConnectorDTO(new NetconfDeviceCommunicator(remoteDeviceId, device), mountPointFacade); + } + + public NetconfReconnectingClientConfiguration getClientConfig(final NetconfDeviceCommunicator listener, NetconfNode node) { + final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue()); + final long clientConnectionTimeoutMillis = node.getDefaultRequestTimeoutMillis(); + + final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor, + node.getMaxConnectionAttempts(), node.getBetweenAttemptsTimeoutMillis(), node.getSleepFactor()); + final ReconnectStrategy strategy = sf.createReconnectStrategy(); + + final AuthenticationHandler authHandler; + final Credentials credentials = node.getCredentials(); + if (credentials instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword) { + authHandler = new LoginPassword( + ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword) credentials).getUsername(), + ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword) credentials).getPassword()); + } else { + throw new IllegalStateException("Only login/password authentification is supported"); + } + + return NetconfReconnectingClientConfigurationBuilder.create() + .withAddress(socketAddress) + .withConnectionTimeoutMillis(clientConnectionTimeoutMillis) + .withReconnectStrategy(strategy) + .withAuthHandler(authHandler) + .withProtocol(node.isTcpOnly() ? + NetconfClientConfiguration.NetconfClientProtocol.TCP : + NetconfClientConfiguration.NetconfClientProtocol.SSH) + .withConnectStrategyFactory(sf) + .withSessionListener(listener) + .build(); + } + + @Override + public void onSessionInitiated(ProviderSession session) { + mountPointService = session.getService(DOMMountPointService.class); + } + + @Override + public Collection getProviderFunctionality() { + return Collections.emptySet(); + } + + @Override + public void onSessionInitiated(ProviderContext session) { + dataBroker = session.getSALService(DataBroker.class); + } + + private static final class NetconfConnectorDTO { + + private final NetconfDeviceCommunicator communicator; + private final TopologyMountPointFacade mountPointFacade; + + private NetconfConnectorDTO(final NetconfDeviceCommunicator communicator, final TopologyMountPointFacade mountPointFacade) { + this.communicator = communicator; + this.mountPointFacade = mountPointFacade; + } + + public NetconfDeviceCommunicator getCommunicator() { + return communicator; + } + + public TopologyMountPointFacade getMountPointFacade() { + return mountPointFacade; + } + } + + private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory { + private final Long connectionAttempts; + private final EventExecutor executor; + private final double sleepFactor; + private final int minSleep; + + TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts, final int minSleep, final BigDecimal sleepFactor) { + if (maxConnectionAttempts != null && maxConnectionAttempts > 0) { + connectionAttempts = maxConnectionAttempts; + } else { + connectionAttempts = null; + } + + this.sleepFactor = sleepFactor.doubleValue(); + this.executor = executor; + this.minSleep = minSleep; + } + + @Override + public ReconnectStrategy createReconnectStrategy() { + final Long maxSleep = null; + final Long deadline = null; + + return new TimedReconnectStrategy(executor, minSleep, + minSleep, sleepFactor, maxSleep, connectionAttempts, deadline); + } + } + + private InetSocketAddress getSocketAddress(final Host host, int port) { + if(host.getDomainName() != null) { + return new InetSocketAddress(host.getDomainName().getValue(), port); + } else { + final IpAddress ipAddress = host.getIpAddress(); + final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(); + return new InetSocketAddress(ip, port); + } + } +} diff --git a/opendaylight/netconf/netconf-topology/src/main/yang/netconf-topology.yang b/opendaylight/netconf/netconf-topology/src/main/yang/netconf-topology.yang new file mode 100644 index 0000000000..8f55e63768 --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/yang/netconf-topology.yang @@ -0,0 +1,111 @@ +module netconf-topology { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:netconf:topology"; + prefix "nt"; + + import config { prefix config; revision-date 2013-04-05; } + import threadpool {prefix th;} + import netty {prefix netty;} + import opendaylight-md-sal-dom {prefix dom;} + import opendaylight-md-sal-binding {prefix md-sal-binding; revision-date 2013-10-28;} + import odl-netconf-cfg { prefix cfg-net; revision-date 2014-04-08; } + import shared-schema-repository { prefix sh; revision-date 2015-07-27; } + + description + "Module definition for Netconf topolgy. Netconf topology provides a set of common configuration "; + + revision "2015-07-27" { + description + "Initial revision"; + } + + identity netconf-topology { + base config:service-type; + config:java-class "org.opendaylight.netconf.topology.NetconfTopology"; + } + + identity netconf-topology-impl { + base config:module-type; + config:java-name-prefix NetconfTopology; + config:provided-service netconf-topology; + } + + augment "/config:modules/config:module/config:configuration" { + case netconf-topology-impl { + when "/config:modules/config:module/config:type = 'netconf-topology-impl'"; + + leaf topology-id { + mandatory true; + type string; + } + + container dom-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity dom:dom-broker-osgi-registry; + } + } + } + + container binding-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding:binding-broker-osgi-registry; + } + } + } + + container event-executor { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity netty:netty-event-executor; + } + } + } + + container processing-executor { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity th:threadpool; + } + } + + description "Makes up for flaws in netty threading design"; + } + + container client-dispatcher { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity cfg-net:netconf-client-dispatcher; + } + } + } + + container keepalive-executor { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity th:scheduled-threadpool; + } + } + + description "Dedicated solely to keepalive execution"; + } + + container shared-schema-repository { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity sh:shared-schema-repository; + } + } + } + } + } +} \ No newline at end of file diff --git a/opendaylight/netconf/netconf-topology/src/main/yang/shared-schema-repository.yang b/opendaylight/netconf/netconf-topology/src/main/yang/shared-schema-repository.yang new file mode 100644 index 0000000000..e5d1f07807 --- /dev/null +++ b/opendaylight/netconf/netconf-topology/src/main/yang/shared-schema-repository.yang @@ -0,0 +1,41 @@ +module shared-schema-repository { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:netconf:topology:shared:schema:repository"; + prefix "ssr"; + + import config { prefix config; revision-date 2013-04-05; } + + description + "Module definition for Shared schema repository."; + + revision "2015-07-27" { + description + "Initial revision"; + } + + identity shared-schema-repository { + base "config:service-type"; + config:java-class "org.opendaylight.netconf.topology.SchemaRepositoryProvider"; + } + + identity shared-schema-repository-impl { + base "config:module-type"; + config:provided-service shared-schema-repository; + config:java-name-prefix SchemaRepositoryImpl; + } + + augment "/config:modules/config:module/config:configuration" { + case shared-schema-repository-impl { + when "/config:modules/config:module/config:type = 'shared-schema-repository-impl'"; + + container schema-repository-fallbacks { + list schema-repository-fallback { + leaf repository-url { + type string; + } + } + } + } + } +} \ No newline at end of file diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index f2027d53ea..f1474e11b4 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -35,6 +35,8 @@ aaa-authn-odl-plugin netconf-notifications-impl netconf-notifications-api + netconf-topology + netconf-topology-config sal-netconf-connector messagebus-netconf models diff --git a/opendaylight/netconf/sal-netconf-connector/pom.xml b/opendaylight/netconf/sal-netconf-connector/pom.xml index 5dbd9e1d7f..418cfc3de6 100644 --- a/opendaylight/netconf/sal-netconf-connector/pom.xml +++ b/opendaylight/netconf/sal-netconf-connector/pom.xml @@ -83,6 +83,14 @@ org.opendaylight.yangtools yang-data-impl + + org.opendaylight.yangtools + yang-model-api + + + org.opendaylight.yangtools + yang-model-util + org.opendaylight.yangtools yang-parser-impl @@ -173,10 +181,60 @@ org.apache.felix maven-bundle-plugin + + + * + + + org.opendaylight.yangtools yang-maven-plugin + + + config + + generate-sources + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + ${jmxGeneratorPath} + + urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang + + + + org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl + ${salGeneratorPath} + + + true + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config; + + + + diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java index ed0be0d96d..40e4fe2331 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java +++ b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java @@ -12,14 +12,19 @@ import static org.opendaylight.controller.config.api.JmxAttributeValidationExcep import com.google.common.base.Optional; import io.netty.util.concurrent.EventExecutor; +import java.io.File; import java.math.BigDecimal; import java.net.InetSocketAddress; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import org.opendaylight.controller.config.api.JmxAttributeValidationException; +import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; +import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.netconf.client.NetconfClientDispatcher; @@ -41,7 +46,13 @@ import org.opendaylight.protocol.framework.TimedReconnectStrategy; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry; +import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache; +import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository; +import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,11 +64,26 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co { private static final Logger LOG = LoggerFactory.getLogger(NetconfConnectorModule.class); + private static FilesystemSchemaSourceCache CACHE = null; + //when no topology is defined in connector config, we need to add a default schema repository to mantain backwards compatibility + private static SharedSchemaRepository DEFAULT_SCHEMA_REPOSITORY = null; + + //keep track of already initialized repositories to avoid adding redundant listeners + private static final Set INITIALIZED_SCHEMA_REPOSITORIES = new HashSet<>(); + private BundleContext bundleContext; private Optional userCapabilities; private SchemaSourceRegistry schemaRegistry; private SchemaContextFactory schemaContextFactory; + private Broker domRegistry; + private NetconfClientDispatcher clientDispatcher; + private BindingAwareBroker bindingRegistry; + private ThreadPool processingExecutor; + private ScheduledThreadPool keepaliveExecutor; + private SharedSchemaRepository sharedSchemaRepository; + private EventExecutor eventExecutor; + public NetconfConnectorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } @@ -71,8 +97,6 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co checkNotNull(getAddress(), addressJmxAttribute); checkCondition(isHostAddressPresent(getAddress()), "Host address not present in " + getAddress(), addressJmxAttribute); checkNotNull(getPort(), portJmxAttribute); - checkNotNull(getDomRegistry(), portJmxAttribute); - checkNotNull(getDomRegistry(), domRegistryJmxAttribute); checkNotNull(getConnectionTimeoutMillis(), connectionTimeoutMillisJmxAttribute); checkCondition(getConnectionTimeoutMillis() > 0, "must be > 0", connectionTimeoutMillisJmxAttribute); @@ -83,9 +107,12 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co checkNotNull(getBetweenAttemptsTimeoutMillis(), betweenAttemptsTimeoutMillisJmxAttribute); checkCondition(getBetweenAttemptsTimeoutMillis() > 0, "must be > 0", betweenAttemptsTimeoutMillisJmxAttribute); - checkNotNull(getClientDispatcher(), clientDispatcherJmxAttribute); - checkNotNull(getBindingRegistry(), bindingRegistryJmxAttribute); - checkNotNull(getProcessingExecutor(), processingExecutorJmxAttribute); +// if (getNetconfTopology() == null) { +// checkNotNull(getDomRegistry(), domRegistryJmxAttribute); +// checkNotNull(getClientDispatcher(), clientDispatcherJmxAttribute); +// checkNotNull(getBindingRegistry(), bindingRegistryJmxAttribute); +// checkNotNull(getProcessingExecutor(), processingExecutorJmxAttribute); +// } // Check username + password in case of ssh if(getTcpOnly() == false) { @@ -94,23 +121,6 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co } userCapabilities = getUserCapabilities(); - - if(getKeepaliveExecutor() == null) { - LOG.warn("Keepalive executor missing. Using default instance for now, the configuration needs to be updated"); - - // Instantiate the default executor, now we know its necessary - if(DEFAULT_KEEPALIVE_EXECUTOR == null) { - DEFAULT_KEEPALIVE_EXECUTOR = Executors.newScheduledThreadPool(2, new ThreadFactory() { - @Override - public Thread newThread(final Runnable r) { - final Thread thread = new Thread(r); - thread.setName("netconf-southound-keepalives-" + thread.getId()); - thread.setDaemon(true); - return thread; - } - }); - } - } } private boolean isHostAddressPresent(final Host address) { @@ -123,21 +133,19 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co @Override public java.lang.AutoCloseable createInstance() { + initDependenciesFromTopology(); final RemoteDeviceId id = new RemoteDeviceId(getIdentifier(), getSocketAddress()); - final ExecutorService globalProcessingExecutor = getProcessingExecutorDependency().getExecutor(); - - final Broker domBroker = getDomRegistryDependency(); - final BindingAwareBroker bindingBroker = getBindingRegistryDependency(); + final ExecutorService globalProcessingExecutor = processingExecutor.getExecutor(); RemoteDeviceHandler salFacade - = new NetconfDeviceSalFacade(id, domBroker, bindingBroker, getDefaultRequestTimeoutMillis()); + = new NetconfDeviceSalFacade(id, domRegistry, bindingRegistry, getDefaultRequestTimeoutMillis()); final Long keepaliveDelay = getKeepaliveDelay(); - if(shouldSendKeepalive()) { + if (shouldSendKeepalive()) { // Keepalive executor is optional for now and a default instance is supported - final ScheduledExecutorService executor = getKeepaliveExecutor() == null ? - DEFAULT_KEEPALIVE_EXECUTOR : getKeepaliveExecutorDependency().getExecutor(); + final ScheduledExecutorService executor = keepaliveExecutor == null ? DEFAULT_KEEPALIVE_EXECUTOR : keepaliveExecutor.getExecutor(); + salFacade = new KeepaliveSalFacade(id, salFacade, executor, keepaliveDelay); } @@ -150,18 +158,72 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co final NetconfDeviceCommunicator listener = userCapabilities.isPresent() ? new NetconfDeviceCommunicator(id, device, userCapabilities.get()) : new NetconfDeviceCommunicator(id, device); - if(shouldSendKeepalive()) { + if (shouldSendKeepalive()) { ((KeepaliveSalFacade) salFacade).setListener(listener); } final NetconfReconnectingClientConfiguration clientConfig = getClientConfig(listener); - final NetconfClientDispatcher dispatcher = getClientDispatcherDependency(); - - listener.initializeRemoteConnection(dispatcher, clientConfig); + listener.initializeRemoteConnection(clientDispatcher, clientConfig); return new SalConnectorCloseable(listener, salFacade); } + private void initDependenciesFromTopology() { +// topology = getNetconfTopologyDependency(); + +// domRegistry = topology.getDomRegistryDependency(); +// clientDispatcher = topology.getNetconfClientDispatcherDependency(); +// bindingRegistry = topology.getBindingAwareBroker(); +// processingExecutor = topology.getProcessingExecutorDependency(); +// keepaliveExecutor = topology.getKeepaliveExecutorDependency(); +// sharedSchemaRepository = topology.getSharedSchemaRepository().getSharedSchemaRepository(); +// eventExecutor = topology.getEventExecutorDependency(); + +// initFilesystemSchemaSourceCache(sharedSchemaRepository); + domRegistry = getDomRegistryDependency(); + clientDispatcher = getClientDispatcherDependency(); + bindingRegistry = getBindingRegistryDependency(); + processingExecutor = getProcessingExecutorDependency(); + eventExecutor = getEventExecutorDependency(); + + if(getKeepaliveExecutor() == null) { + LOG.warn("Keepalive executor missing. Using default instance for now, the configuration needs to be updated"); + + // Instantiate the default executor, now we know its necessary + if(DEFAULT_KEEPALIVE_EXECUTOR == null) { + DEFAULT_KEEPALIVE_EXECUTOR = Executors.newScheduledThreadPool(2, new ThreadFactory() { + @Override + public Thread newThread(final Runnable r) { + final Thread thread = new Thread(r); + thread.setName("netconf-southound-keepalives-" + thread.getId()); + thread.setDaemon(true); + return thread; + } + }); + } + } + + LOG.warn("No topology defined in config, using default-shared-schema-repo"); + if (DEFAULT_SCHEMA_REPOSITORY == null) { + DEFAULT_SCHEMA_REPOSITORY = new SharedSchemaRepository("default shared schema repo"); + } + initFilesystemSchemaSourceCache(DEFAULT_SCHEMA_REPOSITORY); + } + + private void initFilesystemSchemaSourceCache(SharedSchemaRepository repository) { + LOG.warn("Schema repository used: {}", repository.getIdentifier()); + if (CACHE == null) { + CACHE = new FilesystemSchemaSourceCache<>(repository, YangTextSchemaSource.class, new File("cache/schema")); + } + if (!INITIALIZED_SCHEMA_REPOSITORIES.contains(repository)) { + repository.registerSchemaSourceListener(CACHE); + repository.registerSchemaSourceListener(TextToASTTransformer.create(repository, repository)); + INITIALIZED_SCHEMA_REPOSITORIES.add(repository); + } + setSchemaRegistry(repository); + setSchemaContextFactory(repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT)); + } + private boolean shouldSendKeepalive() { return getKeepaliveDelay() > 0; } @@ -190,8 +252,8 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co final InetSocketAddress socketAddress = getSocketAddress(); final long clientConnectionTimeoutMillis = getConnectionTimeoutMillis(); - final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory( - getEventExecutorDependency(), getMaxConnectionAttempts(), getBetweenAttemptsTimeoutMillis(), getSleepFactor()); + final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor, + getMaxConnectionAttempts(), getBetweenAttemptsTimeoutMillis(), getSleepFactor()); final ReconnectStrategy strategy = sf.createReconnectStrategy(); return NetconfReconnectingClientConfigurationBuilder.create() diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModuleFactory.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModuleFactory.java index 70261b2b10..2b31fe05d0 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModuleFactory.java +++ b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModuleFactory.java @@ -7,16 +7,9 @@ */ package org.opendaylight.controller.config.yang.md.sal.connector.netconf; -import java.io.File; import org.opendaylight.controller.config.api.DependencyResolver; import org.opendaylight.controller.config.api.DynamicMBeanWithInstance; import org.opendaylight.controller.config.spi.Module; -import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory; -import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter; -import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; -import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache; -import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository; -import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer; import org.osgi.framework.BundleContext; /** @@ -25,27 +18,11 @@ import org.osgi.framework.BundleContext; public class NetconfConnectorModuleFactory extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModuleFactory { - // TODO this should be injected - // Netconf devices have separated schema registry + factory from controller - private final SharedSchemaRepository repository = new SharedSchemaRepository(NAME); - private final SchemaContextFactory schemaContextFactory - = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT); - - public NetconfConnectorModuleFactory() { - // Start cache and Text to AST transformer - final FilesystemSchemaSourceCache cache = new FilesystemSchemaSourceCache<>(repository, YangTextSchemaSource.class, new File("cache/schema")); - repository.registerSchemaSourceListener(cache); - repository.registerSchemaSourceListener(TextToASTTransformer.create(repository, repository)); - } - @Override public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final DynamicMBeanWithInstance old, final BundleContext bundleContext) throws Exception { final NetconfConnectorModule module = (NetconfConnectorModule) super.createModule(instanceName, dependencyResolver, old, bundleContext); - - module.setSchemaRegistry(repository); - module.setSchemaContextFactory(schemaContextFactory); return module; } @@ -53,8 +30,6 @@ public class NetconfConnectorModuleFactory extends public Module createModule(final String instanceName, final DependencyResolver dependencyResolver, final BundleContext bundleContext) { final NetconfConnectorModule module = (NetconfConnectorModule) super.createModule(instanceName, dependencyResolver, bundleContext); - module.setSchemaRegistry(repository); - module.setSchemaContextFactory(schemaContextFactory); return module; } } diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceDataBroker.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceDataBroker.java index 0782739b99..093abde49d 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceDataBroker.java +++ b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceDataBroker.java @@ -33,7 +33,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -final class NetconfDeviceDataBroker implements DOMDataBroker { +public final class NetconfDeviceDataBroker implements DOMDataBroker { private final RemoteDeviceId id; private final NetconfBaseOps netconfOps; private final long requestTimeoutMillis; diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java index 555d1741c0..6cb51966ba 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java +++ b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java @@ -19,7 +19,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.model.api.SchemaPath; -class NetconfDeviceNotificationService implements DOMNotificationService { +public class NetconfDeviceNotificationService implements DOMNotificationService { private final Multimap listeners = HashMultimap.create(); diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalProvider.java b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalProvider.java index 8cb34c15da..ef13e0484f 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalProvider.java +++ b/opendaylight/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalProvider.java @@ -27,7 +27,7 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class NetconfDeviceSalProvider implements AutoCloseable, Provider, BindingAwareProvider { +public final class NetconfDeviceSalProvider implements AutoCloseable, Provider, BindingAwareProvider { private static final Logger logger = LoggerFactory.getLogger(NetconfDeviceSalProvider.class); @@ -92,7 +92,7 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding topologyDatastoreAdapter = null; } - static final class MountInstance implements AutoCloseable { + public static final class MountInstance implements AutoCloseable { private DOMMountPointService mountService; private final RemoteDeviceId id; @@ -144,7 +144,7 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding } } - synchronized void onTopologyDeviceConnected(final SchemaContext initialCtx, + public synchronized void onTopologyDeviceConnected(final SchemaContext initialCtx, final DOMDataBroker broker, final DOMRpcService rpc, final NetconfDeviceNotificationService notificationService) { @@ -163,7 +163,7 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding } - synchronized void onTopologyDeviceDisconnected() { + public synchronized void onTopologyDeviceDisconnected() { if(topologyRegistration == null) { logger.trace("{}: Not removing TOPOLOGY mountpoint from MD-SAL, mountpoint was not registered yet", id); return; @@ -181,7 +181,7 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding } @Override - synchronized public void close() throws Exception { + public synchronized void close() throws Exception { onDeviceDisconnected(); onTopologyDeviceDisconnected(); mountService = null; diff --git a/opendaylight/netconf/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang b/opendaylight/netconf/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang index 799c9c8999..62cd4514e6 100644 --- a/opendaylight/netconf/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang +++ b/opendaylight/netconf/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang @@ -14,6 +14,12 @@ module odl-sal-netconf-connector-cfg { description "Service definition for Binding Aware MD-SAL."; + revision "2015-08-03" { + description + "Add netconf topology from which dependencies are inherited, change + existing dependencies to non-mandatory to preserve backwards compatibility"; + } + revision "2013-10-28" { description "Initial revision"; @@ -76,7 +82,7 @@ module odl-sal-netconf-connector-cfg { container dom-registry { uses config:service-ref { refine type { - mandatory true; + mandatory false; config:required-identity dom:dom-broker-osgi-registry; } } @@ -85,7 +91,7 @@ module odl-sal-netconf-connector-cfg { container binding-registry { uses config:service-ref { refine type { - mandatory true; + mandatory false; config:required-identity md-sal-binding:binding-broker-osgi-registry; } } @@ -94,7 +100,7 @@ module odl-sal-netconf-connector-cfg { container event-executor { uses config:service-ref { refine type { - mandatory true; + mandatory false; config:required-identity netty:netty-event-executor; } } @@ -103,7 +109,7 @@ module odl-sal-netconf-connector-cfg { container processing-executor { uses config:service-ref { refine type { - mandatory true; + mandatory false; config:required-identity th:threadpool; } } -- 2.36.6