Add mappingservice-netconf bundle 53/10153/5
authorFlorin Coras <fcoras@ac.upc.edu>
Fri, 22 Aug 2014 03:29:22 +0000 (20:29 -0700)
committerFlorin Coras <fcoras@ac.upc.edu>
Fri, 29 Aug 2014 07:35:21 +0000 (00:35 -0700)
The goal is to enable the management of NETCONF connections to LISP
devices via a simple REST API. If the functionality turns out to be
useful to other controller services, a Java API may also be defineda in
the future.

The bundle consists of a netconf-connector data model that defines RPCs
for spinning up/down sal-netconf-connectors and the associated service
implementation. Both dependency resolution and netconf-connector
instantiation/tearing down are done programmatically via JMX.

Change-Id: I6db79956c1c43b57a6386366c9b4f16937aa53cc
Signed-off-by: Florin Coras <fcoras@ac.upc.edu>
12 files changed:
commons/parent/pom.xml
distribution/pom.xml
mappingservice/netconf/META-INF/MANIFEST.MF [new file with mode: 0644]
mappingservice/netconf/pom.xml [new file with mode: 0644]
mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/config/yang/netconf/impl/LfmNetconfConnectorProviderModule.java [new file with mode: 0644]
mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/config/yang/netconf/impl/LfmNetconfConnectorProviderModuleFactory.java [new file with mode: 0644]
mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/netconf/impl/LispDeviceNetconfConnector.java [new file with mode: 0644]
mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/netconf/impl/LispNetconfConnector.java [new file with mode: 0644]
mappingservice/netconf/src/main/yang/lfm-ncc-provider-impl.yang [new file with mode: 0644]
mappingservice/netconf/src/main/yang/lfm-netconf-connector.yang [new file with mode: 0644]
mappingservice/netconf/src/test/java/org/opendaylight/lispflowmapping/netconf/impl/LispDeviceNetconfConnectorTest.java [new file with mode: 0644]
mappingservice/pom.xml

index a5292735b3052efbb20cba4480814177348ccd7b..489a5b60f28071aa91782b0281d59f0ee5e91422 100644 (file)
                                <artifactId>clustering.services</artifactId>
                                <version>0.5.1-SNAPSHOT</version>
                        </dependency>
+                       <dependency>
+                               <groupId>org.opendaylight.controller</groupId>
+                               <artifactId>config-util</artifactId>
+                               <version>0.2.5-SNAPSHOT</version>
+                       </dependency>
+                       <dependency>
+                       <groupId>org.opendaylight.controller</groupId>
+                       <artifactId>threadpool-config-impl</artifactId>
+                       <version>0.2.5-SNAPSHOT</version>
+               </dependency>
                        <dependency>
                                <groupId>org.opendaylight.yangtools</groupId>
                                <artifactId>yang-binding</artifactId>
                        <artifactId>lispflowmapping-commons</artifactId>
                        <version>${lispflowmapping.version}</version>
                </dependency>
+               
+               <dependency>
+              <groupId>org.opendaylight.lispflowmapping</groupId>
+              <artifactId>mappingservice.netconf</artifactId>
+              <version>${lispflowmapping.version}</version>
+            </dependency>
                </dependencies>
        </dependencyManagement>
 
index 389e194fb6d784702a0e444187bed781cfd85cc9..c877c669ae2083c958c8087fceedfa971e6f0616 100644 (file)
                <dependency>
                        <groupId>org.opendaylight.lispflowmapping</groupId>
                        <artifactId>mappingservice.neutron</artifactId>
-               </dependency>           
+               </dependency>
+               
+               <dependency>
+            <groupId>org.opendaylight.lispflowmapping</groupId>
+            <artifactId>mappingservice.netconf</artifactId>
+        </dependency>
                
   </dependencies>
 
diff --git a/mappingservice/netconf/META-INF/MANIFEST.MF b/mappingservice/netconf/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..822ee43
--- /dev/null
@@ -0,0 +1,56 @@
+Manifest-Version: 1.0\r
+Bnd-LastModified: 1409296681049\r
+Build-Jdk: 1.7.0_65\r
+Built-By: fcoras\r
+Bundle-ManifestVersion: 2\r
+Bundle-Name: LISP Flow Mapping Netconf Connector\r
+Bundle-SymbolicName: org.opendaylight.lispflowmapping.mappingservice.net\r
+ conf\r
+Bundle-Version: 1.1.11.SNAPSHOT\r
+Created-By: Apache Maven Bundle Plugin\r
+Export-Package: org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml\r
+ .ns.yang.lispflowmapping.netconf.rev140706;uses:="org.opendaylight.yang\r
+ tools.yang.binding,org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.\r
+ yang.ietf.inet.types.rev100924,com.google.common.collect,org.opendaylig\r
+ ht.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.re\r
+ v130405,org.opendaylight.yangtools.yang.common";version="1.1.11.SNAPSHO\r
+ T",org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lis\r
+ pflowmapping.netconf.impl.rev140706.modules.module.configuration;uses:=\r
+ "org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.contr\r
+ oller.config.rev130405.modules.module,org.opendaylight.yangtools.yang.b\r
+ inding,org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang\r
+ .lispflowmapping.netconf.impl.rev140706.modules.module.configuration.lf\r
+ m.ncc.provider.impl,org.opendaylight.yangtools.yang.common";version="1.\r
+ 1.11.SNAPSHOT",org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml\r
+ .ns.yang.lispflowmapping.netconf.impl.rev140706;uses:="org.opendaylight\r
+ .yangtools.yang.binding,org.opendaylight.yang.gen.v1.urn.opendaylight.p\r
+ arams.xml.ns.yang.controller.md.sal.binding.rev131028,com.google.common\r
+ .collect,org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.ya\r
+ ng.controller.config.rev130405,org.opendaylight.yangtools.yang.common";\r
+ version="1.1.11.SNAPSHOT",org.opendaylight.yang.gen.v1.urn.opendaylight\r
+ .params.xml.ns.yang.lispflowmapping.netconf.impl.rev140706.modules.modu\r
+ le.configuration.lfm.ncc.provider.impl;uses:="org.opendaylight.yang.gen\r
+ .v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405,org\r
+ .opendaylight.yangtools.yang.binding,org.opendaylight.yangtools.yang.co\r
+ mmon";version="1.1.11.SNAPSHOT"\r
+Import-Package: com.google.common.collect;version="[14.0,15)",com.google\r
+ .common.util.concurrent;version="[14.0,15)",javax.management,org.openda\r
+ ylight.controller.config.api;version="[0.2,1)",org.opendaylight.control\r
+ ler.config.api.annotations;version="[0.2,1)",org.opendaylight.controlle\r
+ r.config.api.jmx;version="[0.2,1)",org.opendaylight.controller.config.s\r
+ pi;version="[0.2,1)",org.opendaylight.controller.config.util;version="[\r
+ 0.2,1)",org.opendaylight.controller.config.yang.md.sal.binding,org.open\r
+ daylight.controller.config.yang.md.sal.connector.netconf,org.opendaylig\r
+ ht.controller.sal.binding.api,org.opendaylight.yang.gen.v1.urn.ietf.par\r
+ ams.xml.ns.yang.ietf.inet.types.rev100924;version="[2010.9,2011)",org.o\r
+ pendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.\r
+ config.rev130405;version="[0.2,1)",org.opendaylight.yang.gen.v1.urn.ope\r
+ ndaylight.params.xml.ns.yang.controller.config.rev130405.modules.module\r
+ ;version="[0.2,1)",org.opendaylight.yang.gen.v1.urn.opendaylight.params\r
+ .xml.ns.yang.controller.md.sal.binding.rev131028,org.opendaylight.yang.\r
+ gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev1\r
+ 40706,org.opendaylight.yangtools.yang.binding;version="[0.6,1)",org.ope\r
+ ndaylight.yangtools.yang.binding.annotations;version="[0.6,1)",org.open\r
+ daylight.yangtools.yang.common;version="[0.6,1)",org.osgi.framework;ver\r
+ sion="[1.7,2)",org.slf4j;version="[1.7,2)"\r
+Tool: Bnd-1.50.0\r
diff --git a/mappingservice/netconf/pom.xml b/mappingservice/netconf/pom.xml
new file mode 100644 (file)
index 0000000..20ff701
--- /dev/null
@@ -0,0 +1,198 @@
+<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.lispflowmapping</groupId>
+        <artifactId>mappingservice-parent</artifactId>
+        <version>1.1.11-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+    <artifactId>mappingservice.netconf</artifactId>
+    <name>LISP Flow Mapping Netconf Connector</name>
+    <packaging>bundle</packaging>
+    <scm>
+        <connection>scm:git:https://git.opendaylight.org/gerrit/p/lispflowmapping.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/lispflowmapping.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Lisp_Flow_Mapping:Main</url>
+        <tag>HEAD</tag>
+    </scm>
+
+    <properties>
+        <ietf-inet-types.version>2010.09.24.4-SNAPSHOT</ietf-inet-types.version>
+        <yang-jmx-generator.version>1.0.0-SNAPSHOT</yang-jmx-generator.version>
+        <yangtools.version>0.6.2-SNAPSHOT</yangtools.version>
+        <mdsal.version>1.1-SNAPSHOT</mdsal.version>
+        <config.version>0.2.5-SNAPSHOT</config.version>
+        <osgi.core.version>5.0.0</osgi.core.version>
+        <salGeneratorPath>src/main/yang-gen-sal</salGeneratorPath>
+        <jmxGeneratorPath>src/main/yang-gen-config</jmxGeneratorPath>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-netconf-connector</artifactId>
+            <version>${mdsal.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-broker-impl</artifactId>
+            <version>${mdsal.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-broker-impl</artifactId>
+            <version>${mdsal.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>netty-event-executor-config</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>threadpool-config-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>threadpool-config-api</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-manager</artifactId>
+            <version>${config.version}</version>
+            <type>jar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-common-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-impl</artifactId>
+            <version>${yangtools.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-parser-impl</artifactId>
+            <version>${yangtools.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+            <version>${mdsal.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>${osgi.core.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+            <version>${yangtools.version}</version>
+        </dependency>
+
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Private-Package>
+                            org.opendaylight.lispflowmapping.netconf.impl,
+                            org.opendaylight.lispflowmapping.config.yang.netconf.impl,
+                        </Private-Package>
+                        <Export-Package>
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.*,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.impl.rev140706.*,
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>maven-sal-api-gen-plugin</artifactId>
+                        <version>${yangtools.version}</version>
+                        <type>jar</type>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.osgi</groupId>
+                        <artifactId>org.osgi.core</artifactId>
+                        <version>${osgi.core.version}</version>
+                    </dependency>
+                </dependencies>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                                    <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:lispflowmapping==org.opendaylight.lispflowmapping.config.yang</namespaceToPackage1>
+                                        <namespaceToPackage2>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage2>
+                                    </additionalConfiguration>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
+
+
diff --git a/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/config/yang/netconf/impl/LfmNetconfConnectorProviderModule.java b/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/config/yang/netconf/impl/LfmNetconfConnectorProviderModule.java
new file mode 100644 (file)
index 0000000..0ea35bf
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 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.lispflowmapping.config.yang.netconf.impl;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.lispflowmapping.netconf.impl.LispDeviceNetconfConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.LfmNetconfConnectorService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LfmNetconfConnectorProviderModule extends org.opendaylight.lispflowmapping.config.yang.netconf.impl.AbstractLfmNetconfConnectorProviderModule {
+    private static final Logger log = LoggerFactory.getLogger(LfmNetconfConnectorProviderModule.class);
+
+    public LfmNetconfConnectorProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public LfmNetconfConnectorProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.lispflowmapping.config.yang.netconf.impl.LfmNetconfConnectorProviderModule 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() {
+
+        final LispDeviceNetconfConnector lnconfConnector = LispDeviceNetconfConnector.createLispDeviceNetconfConnector();
+
+        final BindingAwareBroker.RpcRegistration<LfmNetconfConnectorService> rpcRegistration = getRpcRegistryDependency()
+                .addRpcImplementation(LfmNetconfConnectorService.class, lnconfConnector);
+
+
+        // Wrap as AutoCloseable and close registrations to md-sal at close()
+        final class AutoCloseableNCC implements AutoCloseable {
+
+            @Override
+            public void close() throws Exception {
+                rpcRegistration.close();
+                lnconfConnector.close();
+                log.info("Lisp netconf connector (instance {}) torn down.", this);
+            }
+        }
+
+        AutoCloseable ret = new AutoCloseableNCC();
+        log.info("Lisp netconf connector provider (instance {}) initialized.", ret);
+        return ret;
+
+    }
+
+
+}
\ No newline at end of file
diff --git a/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/config/yang/netconf/impl/LfmNetconfConnectorProviderModuleFactory.java b/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/config/yang/netconf/impl/LfmNetconfConnectorProviderModuleFactory.java
new file mode 100644 (file)
index 0000000..903abfd
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2014 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.lispflowmapping.config.yang.netconf.impl;
+public class LfmNetconfConnectorProviderModuleFactory extends org.opendaylight.lispflowmapping.config.yang.netconf.impl.AbstractLfmNetconfConnectorProviderModuleFactory {
+
+}
diff --git a/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/netconf/impl/LispDeviceNetconfConnector.java b/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/netconf/impl/LispDeviceNetconfConnector.java
new file mode 100644 (file)
index 0000000..478f1a8
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2014 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.lispflowmapping.netconf.impl;
+
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+
+import org.opendaylight.lispflowmapping.netconf.impl.LispNetconfConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.BuildConnectorInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.LfmNetconfConnectorService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.RemoveConnectorInput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+
+public class LispDeviceNetconfConnector implements AutoCloseable, LfmNetconfConnectorService {
+
+       private static final Logger logger = LoggerFactory.getLogger(LispDeviceNetconfConnector.class);
+
+       private final ExecutorService executor;
+       private LispNetconfConnector nconfConnector;
+
+       public static LispDeviceNetconfConnector createLispDeviceNetconfConnector() {
+           return new LispDeviceNetconfConnector(Executors.newFixedThreadPool(1), new LispNetconfConnector());
+       }
+
+       public LispDeviceNetconfConnector(ExecutorService executor, LispNetconfConnector nconfConnector) {
+           this.executor = executor;
+           this.nconfConnector = nconfConnector;
+           logger.info( "LispDeviceNetconfConnector constructed" );
+       }
+
+       /**
+        * Implemented from the AutoCloseable interface.
+        */
+       @Override
+       public void close() throws ExecutionException, InterruptedException {
+           executor.shutdown();
+       }
+
+
+        /**
+         * RestConf RPC call implemented from the LfmNetconfConnectorService interface.
+         */
+        @Override
+        public Future<RpcResult<Void>> buildConnector(final BuildConnectorInput input) {
+            SettableFuture<RpcResult<Void>> futureResult = SettableFuture.create();
+
+            logger.trace("Received RPC to buildConnector: " + input);
+
+            if (verifyBuildInput(input, futureResult) != true) {
+                return futureResult;
+            }
+
+            return executor.submit(new MakeConnector(input));
+
+        }
+
+        @Override
+        public Future<RpcResult<Void>> removeConnector(final RemoveConnectorInput input) {
+            SettableFuture<RpcResult<Void>> futureResult = SettableFuture.create();
+
+            if (verifyRemoveInput(input, futureResult) != true) {
+                return futureResult;
+            }
+
+            return executor.submit(new RemoveConnector(input) );
+
+        }
+
+        private boolean verifyBuildInput(final BuildConnectorInput req, SettableFuture<RpcResult<Void>> futureResult ) {
+            if (req.getInstance() == null) {
+                logger.error("Instance name not initialized");
+                futureResult.set(RpcResultBuilder.<Void> failed()
+                        .withError(ErrorType.APPLICATION, "exception", "Instance name not initialized")
+                        .build());
+                return false;
+            }
+
+            if (req.getAddress() == null) {
+                logger.error("IP address not initialized");
+                futureResult.set(RpcResultBuilder.<Void> failed()
+                        .withError(ErrorType.APPLICATION, "exception", "IP address not initialized")
+                        .build());
+                return false;
+            }
+
+            if (req.getPort() == null) {
+                logger.error("Port not initialized");
+                futureResult.set(RpcResultBuilder.<Void> failed()
+                        .withError(ErrorType.APPLICATION, "exception", "Port not initialized")
+                        .build());
+                return false;
+            }
+
+            if (req.getUsername() == null) {
+                logger.error("Username not initialized");
+                futureResult.set(RpcResultBuilder.<Void> failed()
+                        .withError(ErrorType.APPLICATION, "exception", "Username not initialized")
+                        .build());
+                return false;
+            }
+
+            if (req.getPassword() == null) {
+                logger.error("Password not initialized");
+                futureResult.set(RpcResultBuilder.<Void> failed()
+                        .withError(ErrorType.APPLICATION, "exception", "Password not initialized")
+                        .build());
+                return false;
+            }
+
+            return true;
+        }
+
+        private boolean verifyRemoveInput(final RemoveConnectorInput conn, SettableFuture<RpcResult<Void>> futureResult) {
+            if (conn.getInstance() == null) {
+                logger.error("Instance name not initialized");
+                futureResult.set(RpcResultBuilder.<Void> failed()
+                        .withError(ErrorType.APPLICATION, "exception", "Instance name not initialized")
+                        .build());
+                return false;
+            }
+
+            return true;
+        }
+
+
+        private class MakeConnector implements Callable<RpcResult<Void>> {
+
+            final BuildConnectorInput buildConnectorInput;
+
+            public MakeConnector(final BuildConnectorInput buildConnectorInput) {
+                this.buildConnectorInput = buildConnectorInput;
+            }
+
+            @Override
+            public RpcResult<Void> call() {
+
+                try {
+                    nconfConnector.createNetconfConnector(buildConnectorInput.getInstance(), buildConnectorInput.getAddress(),
+                            buildConnectorInput.getPort().getValue(), buildConnectorInput.getUsername(), buildConnectorInput.getPassword());
+                    logger.info("LispNetconfConnector {} built", buildConnectorInput.getInstance());
+                    return RpcResultBuilder.<Void>success().build();
+                } catch( InstanceAlreadyExistsException e ) {
+                    logger.error("LispNetconfConnector {} already exists!", buildConnectorInput.getInstance());
+                    return RpcResultBuilder.<Void> failed()
+                            .withError(ErrorType.APPLICATION, "exists", "LispNetconfConnector exists")
+                            .build();
+                } catch (ConflictingVersionException ex) {
+                    logger.error("LispNetconfConnector {} version exception", buildConnectorInput.getInstance());
+                    return RpcResultBuilder.<Void> failed()
+                            .withError(ErrorType.APPLICATION, "exception", "LispNetconfConnector version exception")
+                            .build();
+                } catch ( ValidationException ex) {
+                    logger.error("LispNetconfConnector {} validation exception", buildConnectorInput.getInstance());
+                    return RpcResultBuilder.<Void> failed()
+                            .withError(ErrorType.APPLICATION, "exception", "LispNetconfConnector validation exception")
+                            .build();
+                }
+
+            }
+
+        }
+
+        private class RemoveConnector implements Callable<RpcResult<Void>> {
+            final RemoveConnectorInput removeConnectorInput;
+
+            public RemoveConnector(final RemoveConnectorInput connectorInput) {
+                this.removeConnectorInput = connectorInput;
+            }
+
+            @Override
+            public RpcResult<Void> call() {
+                try {
+                    nconfConnector.removeNetconfConnector(removeConnectorInput.getInstance());
+                    logger.info("LispNetconfConnector {} removed!", removeConnectorInput.getInstance());
+                    return RpcResultBuilder.<Void> success().build();
+                } catch( InstanceNotFoundException e ) {
+                    logger.info("LispNetconfConnector {} doesn't exists!", removeConnectorInput.getInstance());
+                    return RpcResultBuilder.<Void> failed()
+                            .withError(ErrorType.APPLICATION, "no-exist", "LispNetconfConnector doesn't exist")
+                            .build();
+                } catch( ValidationException e ) {
+                    logger.info("LispNetconfConnector {}: Could not validate remove transactions!", removeConnectorInput.getInstance());
+                    return RpcResultBuilder.<Void> failed()
+                            .withError(ErrorType.APPLICATION, "fail", "LispNetconfConnector doesn't exist")
+                            .build();
+                } catch (ConflictingVersionException e) {
+                    logger.error("LispNetconfConnector {}: Cannot remove due to conflicting version", removeConnectorInput.getInstance() );
+                    return RpcResultBuilder.<Void> failed()
+                            .withError(ErrorType.APPLICATION, "fail", "Conflicting version exception")
+                            .build();
+                } catch (Exception e) {
+                    logger.error("LispNetconfConnector {} exception while removing: {}", removeConnectorInput.getInstance(), e.getClass());
+                    return RpcResultBuilder.<Void> failed()
+                            .withError(ErrorType.APPLICATION, "fail", "Cannot remove LispNetconfConnector: " + removeConnectorInput.getInstance())
+                            .build();
+                }
+
+            }
+        }
+    }
diff --git a/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/netconf/impl/LispNetconfConnector.java b/mappingservice/netconf/src/main/java/org/opendaylight/lispflowmapping/netconf/impl/LispNetconfConnector.java
new file mode 100644 (file)
index 0000000..187354a
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2014 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.lispflowmapping.netconf.impl;
+
+import java.lang.management.ManagementFactory;
+import java.util.Set;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
+import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.opendaylight.controller.config.yang.md.sal.binding.impl.BindingBrokerImplModuleFactory;
+import org.opendaylight.controller.config.yang.md.sal.connector.netconf.NetconfConnectorModuleFactory;
+import org.opendaylight.controller.config.yang.md.sal.connector.netconf.NetconfConnectorModuleMXBean;
+import org.opendaylight.controller.config.yang.md.sal.dom.impl.DomBrokerImplModuleFactory;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.GlobalEventExecutorModuleFactory;
+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.PortNumber;
+import org.opendaylight.controller.config.yang.threadpool.impl.flexible.FlexibleThreadPoolModuleFactory;
+import org.opendaylight.controller.config.yang.config.netconf.client.dispatcher.NetconfClientDispatcherModuleFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LispNetconfConnector {
+    private ConfigRegistryJMXClient configRegistryClient;
+
+    private static final Logger logger = LoggerFactory.getLogger(LispNetconfConnector.class);
+
+    private MBeanServer platformMBeanServer;
+
+    public LispNetconfConnector() {
+
+        // Obtain the platform's MBeanServer (should've been previously created)
+        // and create a ConfigRegistry JMX client via which modules can be created
+        // and destroyed
+        platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
+        configRegistryClient = new ConfigRegistryJMXClient(platformMBeanServer);
+
+    }
+
+    /**
+     * Build a sal-netconf-connector to device using given credentials. Module instantiation and dependency resolution
+     * are done via a JMX ConfigTransactionClient
+     * @param instanceName
+     * @param host
+     * @param port
+     * @param username
+     * @param password
+     * @throws InstanceAlreadyExistsException
+     * @throws ConflictingVersionException
+     * @throws ValidationException
+     */
+    public void createNetconfConnector(String instanceName, Host host, Integer port, String username, String password) throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException {
+
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+
+        if (transaction == null) {
+            logger.error("Could not create transaction with ConfigRegistry! Cannot build NETCONF connector!");
+            return;
+        }
+
+        // create sal-netconf-connector module and via an mxBean configure all
+        // yang defined parameters
+        ObjectName connName = transaction.createModule(NetconfConnectorModuleFactory.NAME, instanceName);
+        NetconfConnectorModuleMXBean mxBean = transaction.newMXBeanProxy(connName, NetconfConnectorModuleMXBean.class);
+
+        mxBean.setAddress(host);
+        mxBean.setPassword(password);
+        mxBean.setPort(new PortNumber(port));
+        mxBean.setUsername(username);
+        mxBean.setTcpOnly(false);
+
+        if (solveDependencies(transaction, mxBean) != true) {
+            logger.error("Failed to solve dependencies! Aborting!");
+            return;
+        }
+
+        transaction.commit();
+
+    }
+
+    public void removeNetconfConnector(String instanceName) throws InstanceNotFoundException, ValidationException, ConflictingVersionException {
+        ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+        transaction.destroyModule(NetconfConnectorModuleFactory.NAME, instanceName);
+        transaction.commit();
+    }
+
+    /**
+     * Lookup sal-netconf-connector dependencies using a ConfigTransactionJMXClient and configure them for the module
+     * we are about to instantiate. As long as the netconf module in configuration/initial is loaded, all of
+     * dependencies should be solvable.
+     * @param transaction
+     * @param mxBean
+     * @return
+     */
+    private boolean solveDependencies(ConfigTransactionJMXClient transaction, NetconfConnectorModuleMXBean mxBean) {
+
+        ObjectName bindingBrokerRegistry = findConfigBean(BindingBrokerImplModuleFactory.NAME, transaction);
+        if (bindingBrokerRegistry != null ) {
+            mxBean.setBindingRegistry(bindingBrokerRegistry);
+        } else {
+            logger.debug("No BindingBroker instance found");
+            return false;
+        }
+
+        ObjectName domRegistry = findConfigBean(DomBrokerImplModuleFactory.NAME, transaction);
+        if (domRegistry != null) {
+            mxBean.setDomRegistry(domRegistry);
+        } else {
+            logger.debug("No DomRegistryBroker instance found");
+            return false;
+        }
+
+        ObjectName eventExecutor = findConfigBean(GlobalEventExecutorModuleFactory.NAME, transaction);
+        if (eventExecutor != null) {
+            mxBean.setEventExecutor(eventExecutor);
+        } else {
+            logger.debug("No EventExecutor instance found");
+            return false;
+        }
+
+        ObjectName threadpool = findConfigBean(FlexibleThreadPoolModuleFactory.NAME, transaction);
+        if (threadpool != null) {
+            mxBean.setProcessingExecutor(threadpool);
+        } else {
+            logger.debug("No ThreadPool instance found");
+            return false;
+        }
+
+        ObjectName clientDispatcher = findConfigBean(NetconfClientDispatcherModuleFactory.NAME, transaction);
+        if (clientDispatcher != null) {
+            mxBean.setClientDispatcher(clientDispatcher);
+        } else {
+            logger.debug("No ClientDispatcher instance found");
+            return false;
+        }
+
+        return true;
+
+    }
+
+    /**
+     * Uses a ConfigTransactionJMXClient to find the first object name of an already instantiated MBean
+     * based on the string name of the class.
+     * @param name
+     * @param transaction
+     * @return
+     */
+    private ObjectName findConfigBean(String name, ConfigTransactionJMXClient transaction) {
+        Set<ObjectName> set = transaction.lookupConfigBeans(name);
+        if (set.size() > 0) {
+            return set.iterator().next();
+        } else {
+            return null;
+        }
+    }
+
+
+}
diff --git a/mappingservice/netconf/src/main/yang/lfm-ncc-provider-impl.yang b/mappingservice/netconf/src/main/yang/lfm-ncc-provider-impl.yang
new file mode 100644 (file)
index 0000000..1642096
--- /dev/null
@@ -0,0 +1,36 @@
+module lfm-ncc-provider-impl {
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:lispflowmapping:netconf:impl";
+    prefix "lfm-ncc-provider-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for lispflowmapping-netconf-connector implementation.";
+
+    revision "2014-07-06" {
+        description
+            "Initial revision.";
+    }
+
+    identity lfm-ncc-provider-impl {
+        base config:module-type;
+        config:java-name-prefix LfmNetconfConnectorProvider;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case lfm-ncc-provider-impl {
+            when "/config:modules/config:module/config:type = 'lfm-ncc-provider-impl'";
+            
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-rpc-registry;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/mappingservice/netconf/src/main/yang/lfm-netconf-connector.yang b/mappingservice/netconf/src/main/yang/lfm-netconf-connector.yang
new file mode 100644 (file)
index 0000000..0a20f63
--- /dev/null
@@ -0,0 +1,69 @@
+module lfm-netconf-connector {
+    yang-version 1;
+
+    namespace "urn:opendaylight:params:xml:ns:yang:lispflowmapping:netconf";
+    prefix "lnc";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import ietf-inet-types {prefix inet; revision-date "2010-09-24";}
+    
+    organization "Cisco Systems, Inc.";
+
+    contact
+      "Florin Coras <fcoras@ac.upc.edu>";
+
+    revision "2014-07-06" {
+        description
+          "Data model for lispflowmapping netconf connector";
+    }
+    
+    container nc-connector {
+        presence
+        "Indicates the netconf connector service is available";
+        
+        description
+        "Top-level container for all connector database objects.";
+    }
+    
+    rpc build-connector {
+        description
+           "Build netconf connector";
+        input {
+            leaf instance {
+                type string;
+                description "instance name";
+            }
+
+            leaf address {
+                 type inet:host;
+                 description "Device address";
+            }
+            
+            leaf port {
+                type inet:port-number;
+                description "Device port";
+            }
+            
+            leaf username {
+                type string;
+                description "Username for netconf connection";
+            }
+            
+            leaf password {
+                type string;
+                description "Password for netconf connection";
+            }
+        }
+    }
+    
+    rpc remove-connector {
+        description
+            "Removes a given netconf connector";
+        input {
+            leaf instance {
+                type string;
+                description "instance name";
+            }
+        }
+    }
+}
diff --git a/mappingservice/netconf/src/test/java/org/opendaylight/lispflowmapping/netconf/impl/LispDeviceNetconfConnectorTest.java b/mappingservice/netconf/src/test/java/org/opendaylight/lispflowmapping/netconf/impl/LispDeviceNetconfConnectorTest.java
new file mode 100644 (file)
index 0000000..4d1978d
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014 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.lispflowmapping.netconf.impl;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.concurrent.Executors;
+
+import org.junit.Test;
+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.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.BuildConnectorInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.BuildConnectorInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.RemoveConnectorInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lispflowmapping.netconf.rev140706.RemoveConnectorInputBuilder;
+
+public class LispDeviceNetconfConnectorTest {
+
+
+    @Test
+    public void testRemoveConnector() throws Exception {
+        LispNetconfConnector mockedConnector = getLispNetconfConnector();
+        LispDeviceNetconfConnector testedLispDeviceNetconfConnector = new LispDeviceNetconfConnector(Executors.newFixedThreadPool(1), mockedConnector);
+
+        assertEquals(testedLispDeviceNetconfConnector.removeConnector(removeInput("n1")).get().isSuccessful(), true);
+        verify(mockedConnector).removeNetconfConnector(any(String.class));
+
+        testedLispDeviceNetconfConnector.close();
+    }
+
+    @Test
+    public void testRemoveConnectorFail() throws Exception {
+        LispNetconfConnector mockedConnector = getLispNetconfConnector();
+        LispDeviceNetconfConnector testedLispDeviceNetconfConnector = new LispDeviceNetconfConnector(Executors.newFixedThreadPool(1), mockedConnector);
+        assertEquals(testedLispDeviceNetconfConnector.removeConnector(removeInput(null)).get().isSuccessful(), false);
+        testedLispDeviceNetconfConnector.close();
+    }
+
+    @Test
+    public void testMakeConnector() throws Exception {
+        LispNetconfConnector mockedConnector = getLispNetconfConnector();
+        LispDeviceNetconfConnector testedLispDeviceNetconfConnector = new LispDeviceNetconfConnector(Executors.newFixedThreadPool(1), mockedConnector);
+        assertEquals(testedLispDeviceNetconfConnector.buildConnector(buildConnectorInput("n1", "1.1.1.1", 830, "user", "pass")).get().isSuccessful(), true);
+
+        verify(mockedConnector).createNetconfConnector(any(String.class), any(Host.class), any(Integer.class), any(String.class), any(String.class));
+        testedLispDeviceNetconfConnector.close();
+    }
+
+    @Test
+    public void testMakeConnectorFail() throws Exception{
+        LispNetconfConnector mockedConnector = getLispNetconfConnector();
+        LispDeviceNetconfConnector testedLispDeviceNetconfConnector = new LispDeviceNetconfConnector(Executors.newFixedThreadPool(1), mockedConnector);
+
+        assertEquals(testedLispDeviceNetconfConnector.buildConnector(buildConnectorInput(null, "1.1.1.1", 830, "user", "pass")).get().isSuccessful(), false);
+        assertEquals(testedLispDeviceNetconfConnector.buildConnector(buildConnectorInput("n1", null, 830, "user", "pass")).get().isSuccessful(), false);
+        assertEquals(testedLispDeviceNetconfConnector.buildConnector(buildConnectorInput("n1", "1.1.1.1", null, "user", "pass")).get().isSuccessful(), false);
+        assertEquals(testedLispDeviceNetconfConnector.buildConnector(buildConnectorInput("n1", "1.1.1.1", 830, null, "pass")).get().isSuccessful(), false);
+        assertEquals(testedLispDeviceNetconfConnector.buildConnector(buildConnectorInput("n1", "1.1.1.1", 830, "user", null)).get().isSuccessful(), false);
+
+        testedLispDeviceNetconfConnector.close();
+    }
+
+    private BuildConnectorInput buildConnectorInput(String instance, String address, Integer port, String user, String pass) {
+        BuildConnectorInputBuilder input = new BuildConnectorInputBuilder();
+        input.setInstance(instance);
+        input.setAddress(address == null ? null : new Host(new IpAddress(new Ipv4Address(address))));
+        input.setPort(port == null ? null : new PortNumber(port));
+        input.setUsername(user);
+        input.setPassword(pass);
+        return input.build();
+    }
+
+    private RemoveConnectorInput removeInput(String instance) {
+        RemoveConnectorInputBuilder input = new RemoveConnectorInputBuilder();
+        input.setInstance(instance);
+        return input.build();
+    }
+
+    private static LispNetconfConnector getLispNetconfConnector() throws Exception{
+        LispNetconfConnector conn =  mock(LispNetconfConnector.class);
+        doNothing().when(conn).createNetconfConnector(any(String.class), any(Host.class), any(Integer.class), any(String.class), any(String.class));
+        doNothing().when(conn).removeNetconfConnector(any(String.class));
+        return(conn);
+    }
+}
index 6ba9d08e3e91d058dfb7b68832c055ecf4e5d40d..a71023e4a45494262890fd9ca9bd25b38b472a3c 100644 (file)
@@ -25,6 +25,7 @@
                 <module>southbound</module>
                 <module>northbound</module>
                 <module>neutron</module>
+                <module>netconf</module>
                 <module>integrationtest</module>
         </modules>
        <dependencies>