From: Ed Warnicke Date: Tue, 8 Apr 2014 16:11:16 +0000 (+0000) Subject: Merge "Fixed potential class pool override in integration tests." X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~264 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=44bac35e828c5dfee8a9fb7fad4f57bceaa9490b;hp=3d4e563bd21a6b7a159eb5b8512b0e7f274cc767 Merge "Fixed potential class pool override in integration tests." --- diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index e7c7bbe637..3690b8542b 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -1351,31 +1351,16 @@ config-persister-api ${config.version} - - org.opendaylight.controller - config-persister-file-adapter - ${config.version} - org.opendaylight.controller config-persister-file-xml-adapter ${config.version} - - org.opendaylight.controller - config-persister-directory-adapter - ${config.version} - org.opendaylight.controller config-persister-directory-xml-adapter ${config.version} - - org.opendaylight.controller - config-persister-directory-autodetect-adapter - ${config.version} - org.opendaylight.controller @@ -1481,7 +1466,16 @@ configuration ${configuration.version} - + + org.bouncycastle + bcprov-jdk15on + 1.50 + + + org.bouncycastle + bcpkix-jdk15on + 1.50 + diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java index e90af73785..5e55cddf8e 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java @@ -89,11 +89,23 @@ public abstract class AbstractDispatcher, L extends }); b.childOption(ChannelOption.SO_KEEPALIVE, true); + customizeBootstrap(b); + // Bind and start to accept incoming connections. final ChannelFuture f = b.bind(address); LOG.debug("Initiated server {} at {}.", f, address); return f; + } + /** + * Customize a server bootstrap before the server is created. This allows + * subclasses to assign non-default server options before the server is + * created. + * + * @param b Server bootstrap + */ + protected void customizeBootstrap(final ServerBootstrap b) { + // The default is a no-op } /** @@ -116,11 +128,25 @@ public abstract class AbstractDispatcher, L extends initializer.initializeChannel(ch, p); } }); + + customizeBootstrap(b); + p.connect(); LOG.debug("Client created."); return p; } + /** + * Customize a client bootstrap before the connection is attempted. This + * allows subclasses to assign non-default options before the client is + * created. + * + * @param b Client bootstrap + */ + protected void customizeBootstrap(final Bootstrap b) { + // The default is a no-op + } + /** * Creates a client. * @@ -138,7 +164,6 @@ public abstract class AbstractDispatcher, L extends p.connect(); return p; - } /** diff --git a/opendaylight/config/config-module-archetype/README.txt b/opendaylight/config/config-module-archetype/README.txt new file mode 100644 index 0000000000..8b1f29bf26 --- /dev/null +++ b/opendaylight/config/config-module-archetype/README.txt @@ -0,0 +1,12 @@ +Use +GROUP_ID=com.mycompany.app +ARTIFACT_ID=my-app +mvn archetype:generate -DgroupId=$GROUP_ID -DartifactId=$ARTIFACT_ID \ + -DarchetypeArtifactId=config-module-archetype -DarchetypeGroupId=org.opendaylight.controller \ + -DarchetypeVersion=0.2.5-SNAPSHOT + +Module name and prefix define yang module name and its java name prefix. +For example when creating thread factory wrapper, yang name might be +thread-factory +and java prefix +ThreadFactory \ No newline at end of file diff --git a/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml index fc30b4d2c3..f7b87290df 100644 --- a/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml +++ b/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml @@ -15,7 +15,7 @@ 2013-04-05 - 0.2.4-SNAPSHOT + 0.2.5-SNAPSHOT 0.6.2-SNAPSHOT diff --git a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml index d1c371d618..21b1a5590b 100644 --- a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml +++ b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml @@ -9,8 +9,13 @@ ${project.build.directory}/generated-sources/config + ${project.build.directory}/generated-sources/sal ${config-api-version} + ${yang-maven-plugin-version} ${maven-bundle-plugin-version} + 1.7 + 1.7 + 2.5.1 @@ -26,7 +31,7 @@ org.opendaylight.yangtools yang-maven-plugin - ${yang-maven-plugin-version} + ${yangtools.version} config @@ -46,6 +51,14 @@ + + + org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl + + + ${salGeneratorPath} + + true @@ -57,6 +70,11 @@ yang-jmx-generator-plugin ${config.version} + + org.opendaylight.yangtools + maven-sal-api-gen-plugin + ${yangtools.version} + @@ -88,16 +106,21 @@ ${project.groupId}.${project.artifactId} - - ${yang-namespace-mapping-to}.${module-name}, - - - * - + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compile.plugin.version} + + ${java.version.source} + ${java.version.target} + ${java.version.source} + ${java.version.target} + + diff --git a/opendaylight/config/config-persister-directory-adapter/pom.xml b/opendaylight/config/config-persister-directory-adapter/pom.xml deleted file mode 100644 index 86b8c4d947..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - 4.0.0 - - config-subsystem - org.opendaylight.controller - 0.2.5-SNAPSHOT - .. - - config-persister-directory-adapter - ${project.artifactId} - bundle - - - - - ${project.groupId} - config-persister-api - - - org.apache.commons - commons-lang3 - - - com.google.guava - guava - - - org.slf4j - slf4j-api - - - commons-io - commons-io - - - - - org.opendaylight.yangtools - mockito-configuration - - - ${project.groupId} - config-persister-api - test-jar - test - - - - - - - - - org.codehaus.groovy.maven - gmaven-plugin - - - generate-sources - - execute - - - - System.setProperty("osgiversion", "${project.version}".replace('-', '.')) - - - - - - - org.apache.felix - maven-bundle-plugin - - - ${project.groupId}.config-persister-impl;bundle-version=${osgiversion} - - org.opendaylight.controller.config.persister.storage.adapter - - - com.google.common.base, - com.google.common.io, - org.apache.commons.io, - org.opendaylight.controller.config.persist.api, - org.slf4j - - - - - - - - diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java deleted file mode 100644 index eb8ef8cddf..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryPersister.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.config.persist.storage.directory; - -import com.google.common.base.Charsets; -import com.google.common.io.Files; -import org.apache.commons.io.IOUtils; -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl; -import org.opendaylight.controller.config.persist.api.Persister; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; - -public class DirectoryPersister implements Persister { - private static final Logger logger = LoggerFactory.getLogger(DirectoryPersister.class); - private static final Charset ENCODING = Charsets.UTF_8; - - public static final String MODULES_START = "//MODULES START"; - static final String SERVICES_START = "//SERVICES START"; - static final String CAPABILITIES_START = "//CAPABILITIES START"; - - - private final File storage; - private static final String header, middle, footer; - - static { - header = readResource("header.txt"); - middle = readResource("middle.txt"); - footer = readResource("footer.txt"); - } - - public DirectoryPersister(File storage) { - checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage); - this.storage = storage; - } - - private static String readResource(String resource) { - try { - return IOUtils.toString(DirectoryPersister.class.getResourceAsStream("/" + resource)); - } catch (IOException e) { - throw new IllegalStateException("Cannot load " + resource, e); - } - } - - @Override - public void persistConfig(ConfigSnapshotHolder holder) throws IOException { - throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass()); - } - - @Override - public List loadLastConfigs() throws IOException { - File[] filesArray = storage.listFiles(); - if (filesArray == null || filesArray.length == 0) { - return Collections.emptyList(); - } - List sortedFiles = new ArrayList<>(Arrays.asList(filesArray)); - Collections.sort(sortedFiles); - // combine all found files - logger.debug("Reading files in following order: {}", sortedFiles); - - List result = new ArrayList<>(); - for (File file : sortedFiles) { - logger.trace("Adding file '{}' to combined result", file); - - ConfigSnapshotHolder configSnapshotHolder = loadLastConfig(file); - result.add(configSnapshotHolder); - } - return result; - } - - public static ConfigSnapshotHolder loadLastConfig(File file) throws IOException { - final MyLineProcessor lineProcessor = new MyLineProcessor(file.getAbsolutePath()); - Files.readLines(file, ENCODING, lineProcessor); - return lineProcessor.getConfigSnapshotHolder(header, middle, footer); - } - - - @Override - public void close() { - - } - - @Override - public String toString() { - return "FileStorageAdapter [storage=" + storage + "]"; - } -} - -class MyLineProcessor implements com.google.common.io.LineProcessor { - private final String fileNameForReporting; - - private boolean inModules, inServices, inCapabilities; - private final StringBuffer modulesBuffer = new StringBuffer(), servicesBuilder = new StringBuffer(); - private final SortedSet caps = new TreeSet<>(); - - MyLineProcessor(String fileNameForReporting) { - this.fileNameForReporting = fileNameForReporting; - } - - @Override - public String getResult() { - return null; - } - - @Override - public boolean processLine(String line) throws IOException { - - String lineWithNewLine = line + System.lineSeparator(); - if (line.equals(DirectoryPersister.MODULES_START)) { - checkState(inModules == false && inServices == false && inCapabilities == false); - inModules = true; - } else if (line.equals(DirectoryPersister.SERVICES_START)) { - checkState(inModules == true && inServices == false && inCapabilities == false); - inModules = false; - inServices = true; - } else if (line.equals(DirectoryPersister.CAPABILITIES_START)) { - checkState(inModules == false && inServices == true && inCapabilities == false); - inServices = false; - inCapabilities = true; - } else if (inModules) { - modulesBuffer.append(lineWithNewLine); - } else if (inServices) { - servicesBuilder.append(lineWithNewLine); - } else { - caps.add(line); - } - return true; - } - - private void checkFileConsistency(){ - checkState(inCapabilities, "File %s is missing delimiters in this order: %s", fileNameForReporting, - Arrays.asList(DirectoryPersister.MODULES_START, - DirectoryPersister.SERVICES_START, - DirectoryPersister.CAPABILITIES_START)); - } - - String getModules() { - checkFileConsistency(); - return modulesBuffer.toString(); - } - - String getServices() { - checkFileConsistency(); - return servicesBuilder.toString(); - } - - SortedSet getCapabilities() { - checkFileConsistency(); - return caps; - } - - ConfigSnapshotHolder getConfigSnapshotHolder(String header, String middle, String footer) { - String combinedSnapshot = header + getModules() + middle + getServices() + footer; - ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, getCapabilities(), fileNameForReporting); - return result; - } - -} - diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapter.java deleted file mode 100644 index 69c8fba9da..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.config.persist.storage.directory; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.config.persist.api.Persister; -import org.opendaylight.controller.config.persist.api.PropertiesProvider; -import org.opendaylight.controller.config.persist.api.StorageAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; - -/** - * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and - * required capabilities will be merged together. Writing to this persister is not supported. - */ -public class DirectoryStorageAdapter implements StorageAdapter { - private static final Logger logger = LoggerFactory.getLogger(DirectoryStorageAdapter.class); - - public static final String DIRECTORY_STORAGE_PROP = "directoryStorage"; - - - @Override - public Persister instantiate(PropertiesProvider propertiesProvider) { - String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP); - Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP)); - File storage = new File(fileStorageProperty); - logger.debug("Using {}", storage); - return new DirectoryPersister(storage); - } - -} diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/resources/footer.txt b/opendaylight/config/config-persister-directory-adapter/src/main/resources/footer.txt deleted file mode 100644 index d4dcc62822..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/main/resources/footer.txt +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/resources/header.txt b/opendaylight/config/config-persister-directory-adapter/src/main/resources/header.txt deleted file mode 100644 index 90ed41c3da..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/main/resources/header.txt +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/opendaylight/config/config-persister-directory-adapter/src/main/resources/middle.txt b/opendaylight/config/config-persister-directory-adapter/src/main/resources/middle.txt deleted file mode 100644 index f728cfdd95..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/main/resources/middle.txt +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java b/opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java deleted file mode 100644 index 278d0d2456..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/DirectoryStorageAdapterTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.config.persist.storage.directory; - -import java.io.File; -import java.util.Collections; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; -import org.apache.commons.io.IOUtils; -import org.junit.Test; -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; -import org.opendaylight.controller.config.persist.api.Persister; -import org.opendaylight.controller.config.persist.test.PropertiesProviderTest; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -public class DirectoryStorageAdapterTest { - Persister tested; - - private Persister instantiatePersisterFromAdapter(File file){ - PropertiesProviderTest pp = new PropertiesProviderTest(); - pp.addProperty("directoryStorage",file.getPath()); - DirectoryStorageAdapter dsa = new DirectoryStorageAdapter(); - return dsa.instantiate(pp); - } - @Test - public void testEmptyDirectory() throws Exception { - File folder = new File("target/emptyFolder"); - folder.mkdir(); - - tested = instantiatePersisterFromAdapter(folder); - assertEquals(Collections.emptyList(), tested.loadLastConfigs()); - - try { - tested.persistConfig(new ConfigSnapshotHolder() { - @Override - public String getConfigSnapshot() { - throw new RuntimeException(); - } - - @Override - public SortedSet getCapabilities() { - throw new RuntimeException(); - } - }); - fail(); - } catch (UnsupportedOperationException e) { - - } - } - - private File getFolder(String folderName) { - File result = new File(("src/test/resources/" + - folderName).replace("/", File.separator)); - assertTrue(result + " is not a directory", result.isDirectory()); - return result; - } - - @Test - public void testOneFile() throws Exception { - File folder = getFolder("oneFile"); - - tested = instantiatePersisterFromAdapter(folder); - - List results = tested.loadLastConfigs(); - assertEquals(1, results.size()); - ConfigSnapshotHolder result = results.get(0); - assertSnapshot(result, "oneFileExpected"); - } - - - @Test - public void testTwoFiles() throws Exception { - File folder = getFolder("twoFiles"); - tested = instantiatePersisterFromAdapter(folder); - - List results = tested.loadLastConfigs(); - assertEquals(2, results.size()); - assertSnapshot(results.get(0), "twoFilesExpected1"); - assertSnapshot(results.get(1), "twoFilesExpected2"); - } - - private void assertSnapshot(ConfigSnapshotHolder result, String directory) throws Exception { - SortedSet expectedCapabilities = new TreeSet<>(IOUtils.readLines(getClass().getResourceAsStream("/" + directory + "/expectedCapabilities.txt"))); - String expectedSnapshot = IOUtils.toString(getClass().getResourceAsStream("/" + directory + "/expectedSnapshot.xml")); - expectedSnapshot = expectedSnapshot.replaceAll("\r",""); - String _snapshot = result.getConfigSnapshot(); - _snapshot = _snapshot.replaceAll("\r",""); - assertEquals(expectedCapabilities, result.getCapabilities()); - assertEquals(expectedSnapshot, _snapshot); - } - -} diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFile/controller.config.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFile/controller.config.txt deleted file mode 100644 index 99b4cb9891..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFile/controller.config.txt +++ /dev/null @@ -1,120 +0,0 @@ -//MODULES START - - prefix:schema-service-singleton - yang-schema-service - - - prefix:hash-map-data-store - hash-map-data-store - - - prefix:dom-broker-impl - dom-broker - - dom:dom-data-store - ref_hash-map-data-store - - - - prefix:binding-broker-impl - binding-broker-impl - - binding:binding-notification-service - ref_binding-notification-broker - - - binding:binding-data-broker - ref_binding-data-broker - - - - prefix:runtime-generated-mapping - runtime-mapping-singleton - - - prefix:binding-notification-broker - binding-notification-broker - - - prefix:binding-data-broker - binding-data-broker - - dom:dom-broker-osgi-registry - ref_dom-broker - - - binding:binding-dom-mapping-service - ref_runtime-mapping-singleton - - -//SERVICES START - - dom:schema-service - - ref_yang-schema-service - /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] - - - - binding:binding-notification-service - - ref_binding-notification-broker - /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] - - - - dom:dom-data-store - - ref_hash-map-data-store - /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] - - - - binding:binding-broker-osgi-registry - - ref_binding-broker-impl - /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] - - - - binding-impl:binding-dom-mapping-service - - ref_runtime-mapping-singleton - /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] - - - - dom:dom-broker-osgi-registry - - ref_dom-broker - /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] - - - - binding:binding-data-broker - - ref_binding-data-broker - /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] - - -//CAPABILITIES START -urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 -urn:ietf:params:netconf:capability:candidate:1.0 -urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04 -urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12 -urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 -urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24 -urn:ietf:params:netconf:capability:rollback-on-error:1.0 -urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24 -urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16 -urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 -urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19 diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedCapabilities.txt deleted file mode 100644 index 84c85b740c..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedCapabilities.txt +++ /dev/null @@ -1,20 +0,0 @@ -urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 -urn:ietf:params:netconf:capability:candidate:1.0 -urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04 -urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12 -urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 -urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24 -urn:ietf:params:netconf:capability:rollback-on-error:1.0 -urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24 -urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16 -urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 -urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19 diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedSnapshot.xml deleted file mode 100644 index a6a57d704a..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/oneFileExpected/expectedSnapshot.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - prefix:schema-service-singleton - yang-schema-service - - - prefix:hash-map-data-store - hash-map-data-store - - - prefix:dom-broker-impl - dom-broker - - dom:dom-data-store - ref_hash-map-data-store - - - - prefix:binding-broker-impl - binding-broker-impl - - binding:binding-notification-service - ref_binding-notification-broker - - - binding:binding-data-broker - ref_binding-data-broker - - - - prefix:runtime-generated-mapping - runtime-mapping-singleton - - - prefix:binding-notification-broker - binding-notification-broker - - - prefix:binding-data-broker - binding-data-broker - - dom:dom-broker-osgi-registry - ref_dom-broker - - - binding:binding-dom-mapping-service - ref_runtime-mapping-singleton - - - - - - dom:schema-service - - ref_yang-schema-service - /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] - - - - binding:binding-notification-service - - ref_binding-notification-broker - /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] - - - - dom:dom-data-store - - ref_hash-map-data-store - /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] - - - - binding:binding-broker-osgi-registry - - ref_binding-broker-impl - /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] - - - - binding-impl:binding-dom-mapping-service - - ref_runtime-mapping-singleton - /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] - - - - dom:dom-broker-osgi-registry - - ref_dom-broker - /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] - - - - binding:binding-data-broker - - ref_binding-data-broker - /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] - - - - diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config1.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config1.txt deleted file mode 100644 index 6ae48fb84b..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config1.txt +++ /dev/null @@ -1,82 +0,0 @@ -//MODULES START - - prefix:schema-service-singleton - yang-schema-service - - - prefix:hash-map-data-store - hash-map-data-store - - - prefix:dom-broker-impl - dom-broker - - dom:dom-data-store - ref_hash-map-data-store - - - - prefix:binding-broker-impl - binding-broker-impl - - binding:binding-notification-service - ref_binding-notification-broker - - - binding:binding-data-broker - ref_binding-data-broker - - - - prefix:runtime-generated-mapping - runtime-mapping-singleton - - - prefix:binding-notification-broker - binding-notification-broker - -//SERVICES START - - dom:schema-service - - ref_yang-schema-service - /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] - - - - binding:binding-notification-service - - ref_binding-notification-broker - /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] - - - - dom:dom-data-store - - ref_hash-map-data-store - /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] - - - - binding:binding-broker-osgi-registry - - ref_binding-broker-impl - /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] - - - - binding-impl:binding-dom-mapping-service - - ref_runtime-mapping-singleton - /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] - - - - dom:dom-broker-osgi-registry - - ref_dom-broker - /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] - - -//CAPABILITIES START -urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27 diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config2.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config2.txt deleted file mode 100644 index ad9138f5d2..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFiles/controller.config2.txt +++ /dev/null @@ -1,41 +0,0 @@ -//MODULES START - - prefix:binding-data-broker - binding-data-broker - - dom:dom-broker-osgi-registry - ref_dom-broker - - - binding:binding-dom-mapping-service - ref_runtime-mapping-singleton - - -//SERVICES START - - binding:binding-data-broker - - ref_binding-data-broker - /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] - - -//CAPABILITIES START -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 -urn:ietf:params:netconf:capability:candidate:1.0 -urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04 -urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12 -urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 -urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24 -urn:ietf:params:netconf:capability:rollback-on-error:1.0 -urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24 -urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16 -urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 -urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19 diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt deleted file mode 100644 index ef35fddbce..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedCapabilities.txt +++ /dev/null @@ -1 +0,0 @@ -urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27 diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml deleted file mode 100644 index 2b1d06ecc0..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected1/expectedSnapshot.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - prefix:schema-service-singleton - yang-schema-service - - - prefix:hash-map-data-store - hash-map-data-store - - - prefix:dom-broker-impl - dom-broker - - dom:dom-data-store - ref_hash-map-data-store - - - - prefix:binding-broker-impl - binding-broker-impl - - binding:binding-notification-service - ref_binding-notification-broker - - - binding:binding-data-broker - ref_binding-data-broker - - - - prefix:runtime-generated-mapping - runtime-mapping-singleton - - - prefix:binding-notification-broker - binding-notification-broker - - - - - dom:schema-service - - ref_yang-schema-service - /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service'] - - - - binding:binding-notification-service - - ref_binding-notification-broker - /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker'] - - - - dom:dom-data-store - - ref_hash-map-data-store - /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store'] - - - - binding:binding-broker-osgi-registry - - ref_binding-broker-impl - /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl'] - - - - binding-impl:binding-dom-mapping-service - - ref_runtime-mapping-singleton - /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton'] - - - - dom:dom-broker-osgi-registry - - ref_dom-broker - /config/modules/module[name='dom-broker-impl']/instance[name='dom-broker'] - - - - diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt deleted file mode 100644 index 9924111627..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedCapabilities.txt +++ /dev/null @@ -1,19 +0,0 @@ -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&revision=2013-04-09 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05 -urn:ietf:params:netconf:capability:candidate:1.0 -urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04 -urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&revision=2013-11-12 -urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28 -urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24 -urn:ietf:params:netconf:capability:rollback-on-error:1.0 -urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24 -urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl?module=threadpool-impl&revision=2013-04-05 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16 -urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09 -urn:opendaylight:params:xml:ns:yang:iana?module=iana&revision=2013-08-16 -urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28 -urn:opendaylight:params:xml:ns:yang:ieee754?module=ieee754&revision=2013-08-19 diff --git a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml b/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml deleted file mode 100644 index 887cb2c1d4..0000000000 --- a/opendaylight/config/config-persister-directory-adapter/src/test/resources/twoFilesExpected2/expectedSnapshot.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - prefix:binding-data-broker - binding-data-broker - - dom:dom-broker-osgi-registry - ref_dom-broker - - - binding:binding-dom-mapping-service - ref_runtime-mapping-singleton - - - - - - binding:binding-data-broker - - ref_binding-data-broker - /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker'] - - - - diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml b/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml deleted file mode 100644 index 5e556c07a9..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - 4.0.0 - - config-subsystem - org.opendaylight.controller - 0.2.5-SNAPSHOT - .. - - config-persister-directory-autodetect-adapter - ${project.artifactId} - bundle - - - - - ${project.groupId} - config-persister-api - - - org.apache.commons - commons-lang3 - - - com.google.guava - guava - - - org.opendaylight.controller - config-persister-directory-adapter - - - org.opendaylight.controller - config-persister-directory-xml-adapter - - - - org.slf4j - slf4j-api - - - commons-io - commons-io - - - - - org.opendaylight.yangtools - mockito-configuration - - - ${project.groupId} - config-persister-api - test-jar - test - - - - - - - - - org.codehaus.groovy.maven - gmaven-plugin - - - generate-sources - - execute - - - - System.setProperty("osgiversion", "${project.version}".replace('-', '.')) - - - - - - - org.apache.felix - maven-bundle-plugin - - - ${project.groupId}.config-persister-impl;bundle-version=${osgiversion} - - org.opendaylight.controller.config.persister.storage.adapter - - - com.google.common.base, - com.google.common.io, - org.apache.commons.io, - org.opendaylight.controller.config.persist.api, - org.slf4j, - com.google.common.collect, - javax.xml.bind, - javax.xml.bind.annotation, - javax.xml.transform, - javax.xml.transform.stream, - org.eclipse.persistence.jaxb, - org.apache.commons.lang3 - - - org.opendaylight.controller.config.persist.storage.file.xml.model, - org.opendaylight.controller.config.persist.storage.directory, - org.opendaylight.controller.config.persist.storage.directory.xml, - - - - - - - - diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersister.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersister.java deleted file mode 100644 index 2028d62bd0..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersister.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.config.persist.storage.directory.autodetect; - -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; -import org.opendaylight.controller.config.persist.api.Persister; -import org.opendaylight.controller.config.persist.storage.directory.DirectoryPersister; -import org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryPersister; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.xml.bind.JAXBException; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; - -public class AutodetectDirectoryPersister implements Persister { - private static final Logger logger = LoggerFactory.getLogger(AutodetectDirectoryPersister.class); - - private final File storage; - - public AutodetectDirectoryPersister(File storage) { - checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage); - this.storage = storage; - } - - @Override - public void persistConfig(ConfigSnapshotHolder holder) throws IOException { - throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass()); - } - - @Override - public List loadLastConfigs() throws IOException { - File[] filesArray = storage.listFiles(); - if (filesArray == null || filesArray.length == 0) { - return Collections.emptyList(); - } - List sortedFiles = new ArrayList<>(Arrays.asList(filesArray)); - Collections.sort(sortedFiles); - - // combine all found files - logger.debug("Reading files in following order: {}", sortedFiles); - - List result = new ArrayList<>(); - for (File file : sortedFiles) { - logger.trace("Adding file '{}' to combined result", file); - - FileType fileType = FileType.getFileType(file); - logger.trace("File '{}' detected as {} storage", file, fileType); - - ConfigSnapshotHolder snapshot = loadLastConfig(file, fileType); - result.add(snapshot); - } - return result; - } - - private ConfigSnapshotHolder loadLastConfig(File file, FileType fileType) throws IOException { - switch (fileType) { - case plaintext: - logger.warn("Plaintext configuration files are deprecated, and will not be supported in future versions. " + - "Use xml files instead"); - return DirectoryPersister.loadLastConfig(file); - case xml: - try { - return XmlDirectoryPersister.loadLastConfig(file); - } catch (JAXBException e) { - logger.warn("Unable to restore configuration snapshot from {}", file, e); - throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e); - } - default: - throw new IllegalStateException("Unknown storage type " + fileType); - } - } - - @Override - public void close() { - - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("AutodetectDirectoryPersister{"); - sb.append("storage=").append(storage); - sb.append('}'); - return sb.toString(); - } -} diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryStorageAdapter.java deleted file mode 100644 index f856ddd6cb..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryStorageAdapter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.config.persist.storage.directory.autodetect; - -import com.google.common.base.Preconditions; -import org.opendaylight.controller.config.persist.api.Persister; -import org.opendaylight.controller.config.persist.api.PropertiesProvider; -import org.opendaylight.controller.config.persist.api.StorageAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; - -/** - * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and - * required capabilities will be merged together. Writing to this persister is not supported. - */ -public class AutodetectDirectoryStorageAdapter implements StorageAdapter { - private static final Logger logger = LoggerFactory.getLogger(AutodetectDirectoryStorageAdapter.class); - - public static final String DIRECTORY_STORAGE_PROP = "directoryStorage"; - - - @Override - public Persister instantiate(PropertiesProvider propertiesProvider) { - String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP); - Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP)); - File storage = new File(fileStorageProperty); - logger.debug("Using {}", storage); - return new AutodetectDirectoryPersister(storage); - } - -} diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileType.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileType.java deleted file mode 100644 index 779a887924..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileType.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.config.persist.storage.directory.autodetect; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import com.google.common.io.Files; -import org.apache.commons.lang3.StringUtils; -import org.opendaylight.controller.config.persist.storage.directory.DirectoryPersister; -import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; - -enum FileType { - - plaintext, xml; - - public static final String XML_STORAGE_FIRST_LINE = "<" + ConfigSnapshot.SNAPSHOT_ROOT_ELEMENT_NAME + ">"; - private static final String XML_FILE_DEFINITION_LINE = " { - private String firstNonBlankLine; - - @Override - public boolean processLine(String line) throws IOException { - if(isEmptyLine(line)) { - return true; - } else { - firstNonBlankLine = line.trim(); - return false; - } - } - - private boolean isEmptyLine(String line) { - return StringUtils.isBlank(line); - } - - @Override - public String getResult() { - return firstNonBlankLine; - } - } -} diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersisterTest.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersisterTest.java deleted file mode 100644 index bcade93352..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/AutodetectDirectoryPersisterTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.config.persist.storage.directory.autodetect; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import junit.framework.Assert; -import org.junit.Test; -import org.junit.matchers.JUnitMatchers; -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; -import org.opendaylight.controller.config.persist.test.PropertiesProviderTest; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -public class AutodetectDirectoryPersisterTest { - - @Test - public void testCombined() throws Exception { - File resourcePath = FileTypeTest.getResourceAsFile("/combined/1controller.txt.config"); - File parentFile = resourcePath.getParentFile(); - - AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter(); - - PropertiesProviderTest pp = new PropertiesProviderTest(); - pp.addProperty("directoryStorage",parentFile.getPath()); - AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp); - List configs = persister.loadLastConfigs(); - - Assert.assertEquals(2, configs.size()); - String snapFromTxt = configs.get(0).getConfigSnapshot(); - org.junit.Assert.assertThat(snapFromTxt, JUnitMatchers.containsString("txt")); - org.junit.Assert.assertThat(snapFromTxt, JUnitMatchers.containsString("txt")); - - String snapFromXml = configs.get(1).getConfigSnapshot(); - org.junit.Assert.assertThat(snapFromXml, JUnitMatchers.containsString("xml")); - - Assert.assertEquals(configs.get(0).getCapabilities(), configs.get(1).getCapabilities()); - } - - @Test - public void testInvalidXml() throws Exception { - File resourcePath = FileTypeTest.getResourceAsFile("/bad_controller.xml.config"); - File parentFile = resourcePath.getParentFile(); - - AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter(); - - PropertiesProviderTest pp = new PropertiesProviderTest(); - pp.addProperty("directoryStorage",parentFile.getPath()); - AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp); - try { - List configs = persister.loadLastConfigs(); - fail("An exception of type " + IllegalStateException.class + " was expected"); - } catch (IllegalStateException ise){ - String message = ise.getMessage(); - assertThat(message, JUnitMatchers.containsString("Unable to restore configuration snapshot from ")); - } - - } - - @Test - public void testPersistConfig() throws Exception { - File resourcePath = FileTypeTest.getResourceAsFile("/combined/1controller.txt.config"); - File parentFile = resourcePath.getParentFile(); - - AutodetectDirectoryStorageAdapter adapter = new AutodetectDirectoryStorageAdapter(); - - PropertiesProviderTest pp = new PropertiesProviderTest(); - pp.addProperty("directoryStorage",parentFile.getPath()); - AutodetectDirectoryPersister persister = (AutodetectDirectoryPersister) adapter.instantiate(pp); - List configs = null; - try { - configs = persister.loadLastConfigs(); - } catch (IOException e) { - fail("An exception of type " + UnsupportedOperationException.class + " was expected"); - } - Assert.assertEquals(2, configs.size()); - try { - persister.persistConfig(configs.get(0)); - } catch (UnsupportedOperationException uoe){ - String message = uoe.getMessage(); - assertThat(message,JUnitMatchers.containsString("This adapter is read only. Please set readonly=true on class")); - } - } - -} diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileTypeTest.java b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileTypeTest.java deleted file mode 100644 index bbc272d388..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/autodetect/FileTypeTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.config.persist.storage.directory.autodetect; - -import junit.framework.Assert; -import org.junit.Test; -import org.junit.matchers.JUnitMatchers; - -import java.io.File; - -public class FileTypeTest { - - @Test - public void testPlaintext() throws Exception { - File file = getResourceAsFile("/test.txt.config"); - - FileType type = FileType.getFileType(file); - Assert.assertEquals(FileType.plaintext, type); - - } - - @Test - public void testXml() throws Exception { - File file = getResourceAsFile("/test.xml.config"); - - FileType type = FileType.getFileType(file); - Assert.assertEquals(FileType.xml, type); - } - - @Test(expected = IllegalArgumentException.class) - public void testUnknown() throws Exception { - File file = getResourceAsFile("/unknown.config"); - - try { - FileType.getFileType(file); - } catch (IllegalArgumentException e) { - org.junit.Assert.assertThat(e.getMessage(), JUnitMatchers.containsString("File " + file + " is not of permitted storage type")); - throw e; - } - } - - static File getResourceAsFile(String resource) { - String f = FileTypeTest.class.getResource(resource).getFile(); - return new File(f); - } - -} diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config deleted file mode 100644 index 3f6a3375d0..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/bad_controller.xml.config +++ /dev/null @@ -1,10 +0,0 @@ - - - cap2 - capa a - - - xml - - \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/1controller.txt.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/1controller.txt.config deleted file mode 100644 index f72cd1c080..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/1controller.txt.config +++ /dev/null @@ -1,8 +0,0 @@ -//MODULES START - txt -//SERVICES START - txt -//CAPABILITIES START -cap1&rev -cap2 -capa a \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/2controller.xml.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/2controller.xml.config deleted file mode 100644 index 988f86675d..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/combined/2controller.xml.config +++ /dev/null @@ -1,10 +0,0 @@ - - - cap1&rev - cap2 - capa a - - - xml - - \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.txt.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.txt.config deleted file mode 100644 index edf37caf0e..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.txt.config +++ /dev/null @@ -1,2 +0,0 @@ -//MODULES START -configuration \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.xml.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.xml.config deleted file mode 100644 index fe94299adb..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/test.xml.config +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/unknown.config b/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/unknown.config deleted file mode 100644 index c4218c8d64..0000000000 --- a/opendaylight/config/config-persister-directory-autodetect-adapter/src/test/resources/unknown.config +++ /dev/null @@ -1,2 +0,0 @@ -unknown -file type \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java index 0ca47edf0e..7f8ebd7fdd 100644 --- a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.config.persist.storage.directory.xml; +import com.google.common.base.Optional; +import com.google.common.io.Files; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; import org.opendaylight.controller.config.persist.api.Persister; import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot; @@ -17,11 +19,13 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.SortedSet; import static com.google.common.base.Preconditions.checkArgument; @@ -30,10 +34,26 @@ public class XmlDirectoryPersister implements Persister { private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryPersister.class); private final File storage; + private final Optional extensionsFilter; + /** + * Creates XmlDirectoryPersister that picks up all files in specified folder + */ public XmlDirectoryPersister(File storage) { + this(storage, Optional.absent()); + } + + /** + * Creates XmlDirectoryPersister that picks up files only with specified file extension + */ + public XmlDirectoryPersister(File storage, Set fileExtensions) { + this(storage, Optional.of(getFilter(fileExtensions))); + } + + private XmlDirectoryPersister(File storage, Optional extensionsFilter) { checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage); this.storage = storage; + this.extensionsFilter = extensionsFilter; } @Override @@ -43,7 +63,7 @@ public class XmlDirectoryPersister implements Persister { @Override public List loadLastConfigs() throws IOException { - File[] filesArray = storage.listFiles(); + File[] filesArray = extensionsFilter.isPresent() ? storage.listFiles(extensionsFilter.get()) : storage.listFiles(); if (filesArray == null || filesArray.length == 0) { return Collections.emptyList(); } @@ -55,19 +75,30 @@ public class XmlDirectoryPersister implements Persister { List result = new ArrayList<>(); for (File file : sortedFiles) { logger.trace("Adding file '{}' to combined result", file); - ConfigSnapshotHolder h = fromXmlSnapshot(file); - result.add(h); + Optional h = fromXmlSnapshot(file); + // Ignore non valid snapshot + if(h.isPresent() == false) { + continue; + } + + result.add(h.get()); } return result; } - private ConfigSnapshotHolder fromXmlSnapshot(File file) { + private Optional fromXmlSnapshot(File file) { try { - return loadLastConfig(file); + return Optional.of(loadLastConfig(file)); } catch (JAXBException e) { - logger.warn("Unable to restore configuration snapshot from {}", file, e); - throw new IllegalStateException("Unable to restore configuration snapshot from " + file, e); + // In case of parse error, issue a warning, ignore and continue + logger.warn( + "Unable to parse configuration snapshot from {}. Initial config from {} will be IGNORED in this run. " + + "Note that subsequent config files may fail due to this problem. " + + "Xml markup in this file needs to be fixed, for detailed information see enclosed exception.", + file, file, e); } + + return Optional.absent(); } public static ConfigSnapshotHolder loadLastConfig(File file) throws JAXBException { @@ -96,6 +127,17 @@ public class XmlDirectoryPersister implements Persister { }; } + private static FilenameFilter getFilter(final SetfileExtensions) { + checkArgument(fileExtensions.isEmpty() == false, "No file extension provided", fileExtensions); + + return new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + String ext = Files.getFileExtension(name); + return fileExtensions.contains(ext); + } + }; + } @Override public void close() { diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java index ab6fb1577c..40f8c283dd 100644 --- a/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryStorageAdapter.java @@ -9,6 +9,8 @@ package org.opendaylight.controller.config.persist.storage.directory.xml; import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.collect.Sets; import org.opendaylight.controller.config.persist.api.Persister; import org.opendaylight.controller.config.persist.api.PropertiesProvider; import org.opendaylight.controller.config.persist.api.StorageAdapter; @@ -16,6 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.util.Set; /** * StorageAdapter that retrieves initial configuration from a directory. If multiple files are present, snapshot and @@ -25,6 +28,8 @@ public class XmlDirectoryStorageAdapter implements StorageAdapter { private static final Logger logger = LoggerFactory.getLogger(XmlDirectoryStorageAdapter.class); public static final String DIRECTORY_STORAGE_PROP = "directoryStorage"; + public static final String INCLUDE_EXT_PROP = "includeExtensions"; + private static final char EXTENSIONS_SEPARATOR = ','; @Override @@ -32,8 +37,21 @@ public class XmlDirectoryStorageAdapter implements StorageAdapter { String fileStorageProperty = propertiesProvider.getProperty(DIRECTORY_STORAGE_PROP); Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(DIRECTORY_STORAGE_PROP)); File storage = new File(fileStorageProperty); - logger.debug("Using {}", storage); - return new XmlDirectoryPersister(storage); + String fileExtensions = propertiesProvider.getProperty(INCLUDE_EXT_PROP); + + logger.debug("Using storage: {}", storage); + + if(fileExtensions != null) { + logger.debug("Using extensions: {}", fileExtensions); + return new XmlDirectoryPersister(storage, splitExtensions(fileExtensions)); + } else { + return new XmlDirectoryPersister(storage); + } + } + + private Set splitExtensions(String fileExtensions) { + return Sets.newHashSet(Splitter.on(EXTENSIONS_SEPARATOR).trimResults().omitEmptyStrings() + .split(fileExtensions)); } } diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java index 8e34bc7990..da442ef4b2 100644 --- a/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/directory/xml/DirectoryStorageAdapterTest.java @@ -12,6 +12,8 @@ import java.io.File; import java.util.Collections; import java.util.List; import java.util.SortedSet; + +import com.google.common.base.Optional; import org.junit.Test; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; import org.opendaylight.controller.config.persist.api.Persister; @@ -26,13 +28,21 @@ public class DirectoryStorageAdapterTest { Persister tested; Logger logger = LoggerFactory.getLogger(DirectoryStorageAdapterTest.class.toString()); - private Persister instantiatePersisterFromAdapter(File file){ + private Persister instantiatePersisterFromAdapter(File file, Optional extensions){ PropertiesProviderTest pp = new PropertiesProviderTest(); - pp.addProperty("directoryStorage",file.getPath()); + pp.addProperty(XmlDirectoryStorageAdapter.DIRECTORY_STORAGE_PROP,file.getPath()); + if(extensions.isPresent()) { + pp.addProperty(XmlDirectoryStorageAdapter.INCLUDE_EXT_PROP, extensions.get()); + } + XmlDirectoryStorageAdapter dsa = new XmlDirectoryStorageAdapter(); return dsa.instantiate(pp); } + private Persister instantiatePersisterFromAdapter(File file){ + return instantiatePersisterFromAdapter(file, Optional.absent()); + } + @Test public void testEmptyDirectory() throws Exception { File folder = new File("target/emptyFolder"); @@ -69,15 +79,22 @@ public class DirectoryStorageAdapterTest { @Test public void testOneFile() throws Exception { File folder = getFolder("oneFile"); - tested = instantiatePersisterFromAdapter(folder); + tested = instantiatePersisterFromAdapter(folder, Optional.of("xml")); - logger.info("Testing : "+tested.toString()); + logger.info("Testing : " + tested.toString()); List results = tested.loadLastConfigs(); assertEquals(1, results.size()); ConfigSnapshotHolder result = results.get(0); assertResult(result, "1", "cap1&rev", "cap2", "capa a"); } + @Test + public void testOneFileWrongExtension() throws Exception { + File folder = getFolder("oneFile"); + tested = instantiatePersisterFromAdapter(folder, Optional.of("aa, bb")); + logger.info("Testing : " + tested.toString()); + } + private void assertResult(ConfigSnapshotHolder result, String s, String... caps) { assertEquals(s, result.getConfigSnapshot().replaceAll("\\s", "")); int i = 0; @@ -87,16 +104,45 @@ public class DirectoryStorageAdapterTest { } @Test - public void testTwoFiles() throws Exception { + public void testTwoFilesAllExtensions() throws Exception { File folder = getFolder("twoFiles"); tested = instantiatePersisterFromAdapter(folder); - logger.info("Testing : "+tested.toString()); + logger.info("Testing : " + tested.toString()); List results = tested.loadLastConfigs(); assertEquals(2, results.size()); assertResult(results.get(0), "1", "cap1-a", "cap2-a", "capa a-a"); assertResult(results.get(1), "2", "cap1-b", "cap2-b", "capa a-b"); + } + + @Test + public void testTwoFilesTwoExtensions() throws Exception { + File folder = getFolder("twoFiles"); + tested = instantiatePersisterFromAdapter(folder, Optional.of("xml, xml2")); + logger.info("Testing : " + tested.toString()); + assertEquals(2, tested.loadLastConfigs().size()); + } + + @Test + public void testTwoFilesOnlyOneExtension() throws Exception { + File folder = getFolder("twoFiles"); + tested = instantiatePersisterFromAdapter(folder, Optional.of("xml")); + logger.info("Testing : " + tested.toString()); + List results = tested.loadLastConfigs(); + assertEquals(1, results.size()); + assertResult(results.get(0), "1", "cap1-a", "cap2-a", "capa a-a"); + } + + @Test + public void testTwoFilesOneInvalid() throws Exception { + File folder = getFolder("twoFiles_corrupt"); + tested = instantiatePersisterFromAdapter(folder, Optional.of("xml")); + logger.info("Testing : " + tested.toString()); + List results = tested.loadLastConfigs(); + assertEquals(1, results.size()); + + assertResult(results.get(0), "1", "cap1-a", "cap2-a", "capa a-a"); } } diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml2 similarity index 100% rename from opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml rename to opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles/controller.config2.xml2 diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config1.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config1.xml new file mode 100644 index 0000000000..28f112e4fa --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config1.xml @@ -0,0 +1,10 @@ + + + cap1-a + cap2-a + capa a-a + + + 1 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config2.xml b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config2.xml new file mode 100644 index 0000000000..ed781d5ee2 --- /dev/null +++ b/opendaylight/config/config-persister-directory-xml-adapter/src/test/resources/twoFiles_corrupt/controller.config2.xml @@ -0,0 +1,10 @@ + + + cap1-b + cap2-b + capa a-b + + + 2 + + \ No newline at end of file diff --git a/opendaylight/config/config-persister-file-adapter/pom.xml b/opendaylight/config/config-persister-file-adapter/pom.xml deleted file mode 100644 index a8ea93e71b..0000000000 --- a/opendaylight/config/config-persister-file-adapter/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - 4.0.0 - - config-subsystem - org.opendaylight.controller - 0.2.5-SNAPSHOT - .. - - config-persister-file-adapter - ${project.artifactId} - bundle - - - - - ${project.groupId} - config-persister-api - - - org.apache.commons - commons-lang3 - - - com.google.guava - guava - - - org.slf4j - slf4j-api - - - - - org.opendaylight.yangtools - mockito-configuration - - - ${project.groupId} - config-persister-api - test-jar - test - - - - - - - - org.codehaus.groovy.maven - gmaven-plugin - - - generate-sources - - execute - - - - System.setProperty("osgiversion", "${project.version}".replace('-', '.')) - - - - - - - org.apache.felix - maven-bundle-plugin - - - ${project.groupId}.config-persister-impl;bundle-version=${osgiversion} - - org.opendaylight.controller.config.persister.storage.adapter - - - - - - - - diff --git a/opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java b/opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java deleted file mode 100644 index 1b9948bf39..0000000000 --- a/opendaylight/config/config-persister-file-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapter.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.config.persist.storage.file; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.io.Files; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import org.apache.commons.lang3.StringUtils; -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolderImpl; -import org.opendaylight.controller.config.persist.api.Persister; -import org.opendaylight.controller.config.persist.api.PropertiesProvider; -import org.opendaylight.controller.config.persist.api.StorageAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * StorageAdapter that stores configuration in a plain file. - */ -public class FileStorageAdapter implements StorageAdapter, Persister { - private static final Logger logger = LoggerFactory.getLogger(FileStorageAdapter.class); - - - private static final Charset ENCODING = Charsets.UTF_8; - - public static final String FILE_STORAGE_PROP = "fileStorage"; - public static final String NUMBER_OF_BACKUPS = "numberOfBackups"; - - - private static final String SEPARATOR_E_PURE = "//END OF CONFIG"; - private static final String SEPARATOR_E = newLine(SEPARATOR_E_PURE); - - private static final String SEPARATOR_M_PURE = "//END OF SNAPSHOT"; - private static final String SEPARATOR_M = newLine(SEPARATOR_M_PURE); - - private static final String SEPARATOR_S = newLine("//START OF CONFIG"); - - private static final String SEPARATOR_SL_PURE = "//START OF CONFIG-LAST"; - private static final String SEPARATOR_SL = newLine(SEPARATOR_SL_PURE); - - private static Integer numberOfStoredBackups; - private File storage; - - @Override - public Persister instantiate(PropertiesProvider propertiesProvider) { - File storage = extractStorageFileFromProperties(propertiesProvider); - logger.debug("Using file {}", storage.getAbsolutePath()); - // Create file if it does not exist - File parentFile = storage.getAbsoluteFile().getParentFile(); - if (parentFile.exists() == false) { - logger.debug("Creating parent folders {}", parentFile); - parentFile.mkdirs(); - } - if (storage.exists() == false) { - logger.debug("Storage file does not exist, creating empty file"); - try { - boolean result = storage.createNewFile(); - if (result == false) - throw new RuntimeException("Unable to create storage file " + storage); - } catch (IOException e) { - throw new RuntimeException("Unable to create storage file " + storage, e); - } - } - if (numberOfStoredBackups == 0) { - throw new RuntimeException(NUMBER_OF_BACKUPS - + " property should be either set to positive value, or ommited. Can not be set to 0."); - } - setFileStorage(storage); - return this; - } - - @VisibleForTesting - void setFileStorage(File storage) { - this.storage = storage; - } - - @VisibleForTesting - void setNumberOfBackups(Integer numberOfBackups) { - numberOfStoredBackups = numberOfBackups; - } - - private static File extractStorageFileFromProperties(PropertiesProvider propertiesProvider) { - String fileStorageProperty = propertiesProvider.getProperty(FILE_STORAGE_PROP); - Preconditions.checkNotNull(fileStorageProperty, "Unable to find " + propertiesProvider.getFullKeyForReporting(FILE_STORAGE_PROP)); - File result = new File(fileStorageProperty); - String numberOfBAckupsAsString = propertiesProvider.getProperty(NUMBER_OF_BACKUPS); - if (numberOfBAckupsAsString != null) { - numberOfStoredBackups = Integer.valueOf(numberOfBAckupsAsString); - } else { - numberOfStoredBackups = Integer.MAX_VALUE; - } - logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups); - return result; - } - - private static String newLine(String string) { - return string + "\n"; - } - - @Override - public void persistConfig(ConfigSnapshotHolder holder) throws IOException { - Preconditions.checkNotNull(storage, "Storage file is null"); - - String content = Files.toString(storage, ENCODING); - if (numberOfStoredBackups == Integer.MAX_VALUE) { - resetLastConfig(content); - persistLastConfig(holder); - } else { - if (numberOfStoredBackups == 1) { - Files.write("", storage, ENCODING); - persistLastConfig(holder); - } else { - int count = StringUtils.countMatches(content, SEPARATOR_S); - if ((count + 1) < numberOfStoredBackups) { - resetLastConfig(content); - persistLastConfig(holder); - } else { - String contentSubString = StringUtils.substringBefore(content, SEPARATOR_E); - contentSubString = contentSubString.concat(SEPARATOR_E_PURE); - content = StringUtils.substringAfter(content, contentSubString); - resetLastConfig(content); - persistLastConfig(holder); - } - } - } - } - - private void resetLastConfig(String content) throws IOException { - content = content.replaceFirst(SEPARATOR_SL, SEPARATOR_S); - Files.write(content, storage, ENCODING); - } - - private void persistLastConfig(ConfigSnapshotHolder holder) throws IOException { - Files.append(SEPARATOR_SL, storage, ENCODING); - String snapshotAsString = holder.getConfigSnapshot(); - Files.append(newLine(snapshotAsString), storage, ENCODING); - Files.append(SEPARATOR_M, storage, ENCODING); - Files.append(toStringCaps(holder.getCapabilities()), storage, ENCODING); - Files.append(SEPARATOR_E, storage, ENCODING); - } - - private CharSequence toStringCaps(Set capabilities) { - StringBuilder b = new StringBuilder(); - for (String capability : capabilities) { - b.append(newLine(capability)); - } - return b.toString(); - } - - @Override - public List loadLastConfigs() throws IOException { - Preconditions.checkNotNull(storage, "Storage file is null"); - - if (!storage.exists()) { - return Collections.emptyList(); - } - - final LineProcessor lineProcessor = new LineProcessor(); - Files.readLines(storage, ENCODING, lineProcessor); - - if (lineProcessor.getConfigSnapshot().isPresent() == false) { - return Collections.emptyList(); - } else { - return Arrays.asList(new ConfigSnapshotHolderImpl(lineProcessor.getConfigSnapshot().get(), - lineProcessor.getCapabilities(), storage.getAbsolutePath())); - } - - } - - private static final class LineProcessor implements com.google.common.io.LineProcessor { - - private boolean inLastConfig, inLastSnapshot; - private final StringBuffer snapshotBuffer = new StringBuffer(); - private final SortedSet caps = new TreeSet<>(); - - @Override - public String getResult() { - return null; - } - - @Override - public boolean processLine(String line) throws IOException { - if (inLastConfig && line.equals(SEPARATOR_E_PURE)) { - inLastConfig = false; - return false; - } - - if (inLastConfig && line.equals(SEPARATOR_M_PURE)) { - inLastSnapshot = false; - return true; - } - - if (inLastConfig) { - if (inLastSnapshot) { - snapshotBuffer.append(line); - snapshotBuffer.append(System.lineSeparator()); - } else { - caps.add(line); - } - } - - if (line.equals(SEPARATOR_SL_PURE)) { - inLastConfig = true; - inLastSnapshot = true; - } - - return true; - } - - Optional getConfigSnapshot() { - final String xmlContent = snapshotBuffer.toString(); - if (xmlContent.equals("")) { - return Optional.absent(); - } else { - return Optional.of(xmlContent); - } - } - - SortedSet getCapabilities() { - return caps; - } - - } - - @Override - public void close() { - - } - - @Override - public String toString() { - return "FileStorageAdapter [storage=" + storage + "]"; - } - -} diff --git a/opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java b/opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java deleted file mode 100644 index 0366dbcaed..0000000000 --- a/opendaylight/config/config-persister-file-adapter/src/test/java/org/opendaylight/controller/config/persist/storage/file/FileStorageAdapterTest.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.config.persist.storage.file; - -import com.google.common.base.Charsets; -import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import java.io.File; -import java.nio.file.Files; -import java.util.Collection; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; -import org.opendaylight.controller.config.persist.api.Persister; -import org.opendaylight.controller.config.persist.test.PropertiesProviderTest; -import static junit.framework.Assert.assertFalse; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -public class FileStorageAdapterTest { - - private static int i; - private File file; - - @Before - public void setUp() throws Exception { - file = Files.createTempFile("testFilePersist", ".txt").toFile(); - if (!file.exists()) - return; - com.google.common.io.Files.write("", file, Charsets.UTF_8); - i = 1; - } - - - @Test - public void testFileAdapterAsPersister() throws Exception { - FileStorageAdapter storage = new FileStorageAdapter(); - PropertiesProviderTest pp = new PropertiesProviderTest(); - pp.addProperty("fileStorage",file.getPath()); - pp.addProperty("numberOfBackups",Integer.toString(Integer.MAX_VALUE)); - - Persister configPersister = storage.instantiate(pp); - final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { - @Override - public String getConfigSnapshot() { - return createConfig(); - } - - @Override - public SortedSet getCapabilities() { - return createCaps(); - } - }; - configPersister.persistConfig(holder); - - configPersister.persistConfig(holder); - - Collection readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8), - new Predicate() { - - @Override - public boolean apply(String input) { - if (input.equals("")) - return false; - return true; - } - }); - assertEquals(14, readLines.size()); - - List lastConf = storage.loadLastConfigs(); - assertEquals(1, lastConf.size()); - ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); - assertEquals("2", - configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); - assertEquals(createCaps(), configSnapshotHolder.getCapabilities()); - } - @Test - public void testFileAdapter() throws Exception { - FileStorageAdapter storage = new FileStorageAdapter(); - storage.setFileStorage(file); - storage.setNumberOfBackups(Integer.MAX_VALUE); - final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { - @Override - public String getConfigSnapshot() { - return createConfig(); - } - - @Override - public SortedSet getCapabilities() { - return createCaps(); - } - }; - storage.persistConfig(holder); - - storage.persistConfig(holder); - - Collection readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8), - new Predicate() { - - @Override - public boolean apply(String input) { - if (input.equals("")) - return false; - return true; - } - }); - assertEquals(14, readLines.size()); - - List lastConf = storage.loadLastConfigs(); - assertEquals(1, lastConf.size()); - ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); - assertEquals("2", - configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); - assertEquals(createCaps(), configSnapshotHolder.getCapabilities()); - } - - private SortedSet createCaps() { - SortedSet caps = new TreeSet<>(); - - caps.add("cap1"); - caps.add("cap2"); - caps.add("capaaaa as dasfasdf s2"); - return caps; - } - - @Test - public void testFileAdapterOneBackup() throws Exception { - FileStorageAdapter storage = new FileStorageAdapter(); - storage.setFileStorage(file); - storage.setNumberOfBackups(1); - final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { - @Override - public String getConfigSnapshot() { - return createConfig(); - } - - @Override - public SortedSet getCapabilities() { - return createCaps(); - } - }; - storage.persistConfig(holder); - - storage.persistConfig(holder); - - Collection readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8), - new Predicate() { - - @Override - public boolean apply(String input) { - if (input.equals("")) - return false; - return true; - } - }); - assertEquals(7, readLines.size()); - - List lastConf = storage.loadLastConfigs(); - assertEquals(1, lastConf.size()); - ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); - assertEquals("2", - configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); - } - - @Test - public void testFileAdapterOnlyTwoBackups() throws Exception { - FileStorageAdapter storage = new FileStorageAdapter(); - storage.setFileStorage(file); - storage.setNumberOfBackups(2); - final ConfigSnapshotHolder holder = new ConfigSnapshotHolder() { - @Override - public String getConfigSnapshot() { - return createConfig(); - } - - @Override - public SortedSet getCapabilities() { - return createCaps(); - } - }; - storage.persistConfig(holder); - - storage.persistConfig(holder); - storage.persistConfig(holder); - - Collection readLines = Collections2.filter(com.google.common.io.Files.readLines(file, Charsets.UTF_8), - new Predicate() { - - @Override - public boolean apply(String input) { - if (input.equals("")) - return false; - return true; - } - }); - - assertEquals(14, readLines.size()); - - List lastConf = storage.loadLastConfigs(); - assertEquals(1, lastConf.size()); - ConfigSnapshotHolder configSnapshotHolder = lastConf.get(0); - assertEquals("3", - configSnapshotHolder.getConfigSnapshot().replaceAll("\\s", "")); - assertFalse(readLines.contains(holder.getConfigSnapshot())); - } - - @Test - public void testNoLastConfig() throws Exception { - File file = Files.createTempFile("testFilePersist", ".txt").toFile(); - if (!file.exists()) - return; - FileStorageAdapter storage = new FileStorageAdapter(); - storage.setFileStorage(file); - - List elementOptional = storage.loadLastConfigs(); - assertThat(elementOptional.size(), is(0)); - } - - @Test(expected = NullPointerException.class) - public void testNoProperties() throws Exception { - FileStorageAdapter storage = new FileStorageAdapter(); - storage.loadLastConfigs(); - } - - @Test(expected = NullPointerException.class) - public void testNoProperties2() throws Exception { - FileStorageAdapter storage = new FileStorageAdapter(); - storage.persistConfig(new ConfigSnapshotHolder() { - @Override - public String getConfigSnapshot() { - return Mockito.mock(String.class); - } - - @Override - public SortedSet getCapabilities() { - return new TreeSet<>(); - } - } ); - } - - static String createConfig() { - return "" + i++ + ""; - } - -} diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 6b55b6ad16..d700075e95 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -23,7 +23,6 @@ config-plugin-parent config-util config-persister-api - config-persister-file-adapter config-persister-file-xml-adapter yang-jmx-generator yang-jmx-generator-plugin @@ -35,9 +34,7 @@ netty-threadgroup-config netty-event-executor-config netty-timer-config - config-persister-directory-adapter config-persister-directory-xml-adapter - config-persister-directory-autodetect-adapter yang-test-plugin shutdown-api shutdown-impl diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index a38a9b4f93..776fb7a0f6 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -202,26 +202,14 @@ org.opendaylight.controller config-persister-api - - org.opendaylight.controller - config-persister-file-adapter - org.opendaylight.controller config-persister-file-xml-adapter - - org.opendaylight.controller - config-persister-directory-adapter - org.opendaylight.controller config-persister-directory-xml-adapter - - org.opendaylight.controller - config-persister-directory-autodetect-adapter - org.opendaylight.controller @@ -287,6 +275,14 @@ org.apache.xml.resolver 1.2.0 + + org.bouncycastle + bcprov-jdk15on + + + org.bouncycastle + bcpkix-jdk15on + diff --git a/opendaylight/distribution/opendaylight/src/assemble/bin.xml b/opendaylight/distribution/opendaylight/src/assemble/bin.xml index 6f8878bee9..0ff4c9a83c 100644 --- a/opendaylight/distribution/opendaylight/src/assemble/bin.xml +++ b/opendaylight/distribution/opendaylight/src/assemble/bin.xml @@ -69,6 +69,7 @@ version.properties + configuration/config.ini opendaylight/ @@ -81,5 +82,10 @@ opendaylight true + + src/main/resources/configuration/config.ini + opendaylight/configuration + true + diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/RSA.pk b/opendaylight/distribution/opendaylight/src/main/resources/configuration/RSA.pk deleted file mode 100644 index c0266c7bd2..0000000000 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/RSA.pk +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAuC9hbEacpewvylI0mwFwjy3Wou2hpr/ncN9BBiFDSaG5yW2k -3Oy+SCAcFCL+ZKWb6cc6Ch4gUeCwyEHRojZguuhliKtak9YQf6qbvpPLe00842Lx -iqNAGurMpzizCDsGFq8ChaAkBZQI3TvcHuPoSUWSMJ+K8xHpRyUdVr6g2yEjezKJ -sTXBtWaeCCh6YUafFujuDJk7fvYcPW7Je5KRBBStIKvxcMW0zB+7eq04deTHwGbJ -gGjKWilQ72hsDDP3Hbp5CJMAYg1r4GlCmFx3KyHRGztgWgNgaD7nNpKCkTLjtmA6 -b4x7TA+jrzZ6Af2z5TMrI4dv5w1SrxHaZ+ziLQIDAQABAoIBAHTndeGgq/rQf8De -Do+4CTaHtK0zQSAyu/azbXUzlZ7drKuCEVs8VMY4wzmwwGEnkF+A2YDkgEUX5X0l -8aYQ97KKoS9u+43MGCrAIhyDeGrpqlT1TzRcy+qJz53v6gq2U/X/3QztiQ+VV078 -mIluxNgE9XYxPaNsYfGLSCTv1+9c8y/hjGVX2kwFK+u4ut0ZZETggNa8UxfaHVDS -fIJQX9Gm3J3GSUV30fDGMBIUW6ESLc2L8b7u8Mp9TRP39ZeQSuEUjBe8MYKv0Rel -oEpjZvcnniMTpFbLpndBYn7/AoIiEBvtCN8faVTuRRcvvLcsRm09IctzKQYnMh6M -6PLKV+ECgYEA8HFRYaKHUzxpzE/fyon82GQbzqFFY0/bbWrfWICMfNbIgshJUie6 -FmH5iUFMfeqaT7v557HFM0GB9FeIeSbvd88YmiBAcRopZ3DfMkDH+DT73yJ+/TKG -2nrQtdhyuTIs4bwHqeS2BBJYs7PK9R2rratF3l34Tf7mjlvyOgygHdUCgYEAxBo2 -8hEBlAVNcNb1hTYUxe1w1B6675/mFlmw98Xmj9dRYfICXNhahs8tX3/lsBEd+vBu -fI0oyHaff8m5bPgGzD1ZMybfeROujNrgxaKVk7Ef0FDRRCop4bm18OroFlFAt9l8 -wMp++ToACbdvQvL/mjWMPYlIxhB/YxHswICZZvkCgYAexxKYwdo6sGAGlC7cWT9x -X5cjowcjyEQZRHXkeUgCbufpvcOM7aLnXJE5nY8yCwbHsBM0MlBA2GDPKylAANjk -aDEJAZneIHAuWodngl1Wi0m2bU7+ECqs6s2uiU9eH2sZVh1RBQK7kLGkBx6ys6KX -L3ZZGYRAT6GplWFzRsx0JQKBgCeVlxPD5QqpC1nEumi6YvUVGdpnnZpzL3HBhxxs -wT612wKnZFyze4qM1X7ahVXGDsQxtkvD/sCAWW/lG13orw6ZL6FIroF1PJ3ILOkY -CZN3hJF7TtKwpCWhZB2OfWzL2AGEkE8mUP0j/Q/5DCd6f6f0OSvOw3bfq6cm3iB5 -lP2ZAoGAXsRN5TZTX4AQ2xTlrDQ8A5XgcvyWQpJOmEXMTyHV7VaJVzmNWFVAvndK -5UIq8ALDwB2t7vjmMUW6euvIwqtXiop7G79UOb3e3NhzeyWFGQyBLqCRznGaXQTT -dlFy73xhukZMhFnj006bjKCYvOPnwuGl3+0fuWil5Rq3jOuY5c8= ------END RSA PRIVATE KEY----- diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini index 4598bac593..9df653cf94 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini @@ -8,7 +8,7 @@ osgi.bundles=\ reference\:file\:../lib/slf4j-api-1.7.2.jar@1:start,\ reference\:file\:../lib/logback-classic-1.0.9.jar@1:start,\ reference\:file\:../lib/logback-core-1.0.9.jar@1:start,\ - reference\:file\:../lib/logging.bridge-0.4.2-SNAPSHOT@1:start,\ + reference\:file\:../lib/logging.bridge-${controller.version}@1:start,\ reference\:file\:../lib/jersey-core-1.17.jar@2:start,\ reference\:file\:../lib/jersey-server-1.17.jar@2:start @@ -26,22 +26,12 @@ netconf.ssh.pk.path = ./configuration/RSA.pk netconf.config.persister.active=1,2 # read startup configuration -#netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.DirectoryStorageAdapter -#netconf.config.persister.1.properties.directoryStorage=configuration/initial/ -#netconf.config.persister.1.readonly=true - -netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.autodetect.AutodetectDirectoryStorageAdapter +netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter netconf.config.persister.1.properties.directoryStorage=configuration/initial/ +# include only xml files, files with other extensions will be skipped, multiple extensions are permitted e.g. netconf.config.persister.1.properties.includeExtensions=xml,cfg,config +netconf.config.persister.1.properties.includeExtensions=xml netconf.config.persister.1.readonly=true -#netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter -#netconf.config.persister.3.properties.directoryStorage=configuration/initialXml/ -#netconf.config.persister.3.readonly=true - -#netconf.config.persister.4.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter -#netconf.config.persister.4.properties.fileStorage=configuration/current/controller.currentconfig.txt -#netconf.config.persister.4.properties.numberOfBackups=1 - netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml netconf.config.persister.2.properties.numberOfBackups=1 diff --git a/opendaylight/md-sal/clustered-data-store/integrationtest/pom.xml b/opendaylight/md-sal/clustered-data-store/integrationtest/pom.xml index 74e7d1afe7..01e5ae0372 100644 --- a/opendaylight/md-sal/clustered-data-store/integrationtest/pom.xml +++ b/opendaylight/md-sal/clustered-data-store/integrationtest/pom.xml @@ -165,7 +165,7 @@ org.opendaylight.controller - config-persister-file-adapter + config-persister-file-xml-adapter ${config.version} @@ -269,11 +269,6 @@ config-persister-impl ${config.version} - - org.opendaylight.controller - config-persister-file-adapter - ${config.version} - org.opendaylight.controller netconf-impl diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml index 3e73f161c2..ffdcda31eb 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml @@ -50,7 +50,7 @@ - org.eclipse.m2e @@ -203,7 +203,7 @@ org.opendaylight.yangtools yang-data-api - org.opendaylight.yangtools @@ -455,7 +455,7 @@ org.opendaylight.controller - config-persister-file-adapter + config-persister-file-xml-adapter ${config.version} @@ -472,8 +472,8 @@ org.ops4j.pax.exam pax-exam ${exam.version} - compile diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend index 8ebf28f35f..fa478ac72e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend @@ -305,7 +305,7 @@ class RestconfImpl implements RestconfService { return callRpc(rpc, null) } - def resolveIdentifierInInvokeRpc(String identifier) { + private def resolveIdentifierInInvokeRpc(String identifier) { if (identifier.indexOf("/") === -1) { val identifierDecoded = identifier.urlPathArgDecode val rpc = identifierDecoded.rpcDefinition @@ -314,8 +314,8 @@ class RestconfImpl implements RestconfService { } throw new ResponseException(NOT_FOUND, "RPC does not exist."); } - val slashErrorMsg = String.format("Identifier %n%s%ncan't contain slash character (/). + - If slash is part of identifier name then use %2F placeholder.",identifier) + val slashErrorMsg = String.format( + "Identifier %n%s%ncan't contain slash character (/).%nIf slash is part of identifier name then use %%2F placeholder.", identifier) throw new ResponseException(NOT_FOUND, slashErrorMsg); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java index dff9d65db3..320a7f9d08 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java @@ -7,20 +7,34 @@ */ package org.opendaylight.controller.sal.restconf.impl.test; +import static junit.framework.Assert.assertNotNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import java.io.FileNotFoundException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; + import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; + import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.core.api.mount.MountService; @@ -33,16 +47,12 @@ import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import static junit.framework.Assert.assertNotNull; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; public class RestGetOperationTest extends JerseyTest { @@ -133,6 +143,52 @@ public class RestGetOperationTest extends JerseyTest { assertEquals(200, get(uri, MediaType.APPLICATION_XML)); } + /** + * MountPoint test. URI represents mount point. + * + * Slashes in URI behind mount point. lst1 element with key + * GigabitEthernet0%2F0%2F0%2F0 (GigabitEthernet0/0/0/0) is requested via + * GET HTTP operation. It is tested whether %2F character is replaced with + * simple / in InstanceIdentifier parameter in method + * {@link BrokerFacade#readConfigurationDataBehindMountPoint(MountInstance, InstanceIdentifier)} + * which is called in method {@link RestconfImpl#readConfigurationData} + * + * + * @throws ParseException + */ + @Test + public void getDataWithSlashesBehindMountPoint() throws UnsupportedEncodingException, URISyntaxException, + ParseException { + InstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList(); + when( + brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), + eq(awaitedInstanceIdentifier))).thenReturn(prepareCnDataForMountPointTest()); + MountInstance mountInstance = mock(MountInstance.class); + when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); + MountService mockMountService = mock(MountService.class); + when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance); + + ControllerContext.getInstance().setMountService(mockMountService); + + String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/lst1/GigabitEthernet0%2F0%2F0%2F0"; + assertEquals(200, get(uri, MediaType.APPLICATION_XML)); + } + + private InstanceIdentifier prepareInstanceIdentifierForList() throws URISyntaxException, ParseException { + List parameters = new ArrayList<>(); + + Date revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-01-09"); + URI uri = new URI("test:module"); + QName qNameCont = QName.create(uri, revision, "cont"); + QName qNameList = QName.create(uri, revision, "lst1"); + QName qNameKeyList = QName.create(uri, revision, "lf11"); + + parameters.add(new InstanceIdentifier.NodeIdentifier(qNameCont)); + parameters.add(new InstanceIdentifier.NodeIdentifierWithPredicates(qNameList, qNameKeyList, + "GigabitEthernet0/0/0/0")); + return new InstanceIdentifier(parameters); + } + @Test public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException { when( @@ -162,6 +218,7 @@ public class RestGetOperationTest extends JerseyTest { response = target(uri).request("application/yang.api+xml").get(); validateModulesResponseXml(response); } + // /streams/ @Test public void getStreamsTest() throws UnsupportedEncodingException, FileNotFoundException { @@ -193,7 +250,7 @@ public class RestGetOperationTest extends JerseyTest { assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody) .find()); String[] split = responseBody.split(" + + 4.0.0 + + sal-samples + org.opendaylight.controller.samples + 1.1-SNAPSHOT + ../.. + + org.opendaylight.controller.samples.l2switch.md + l2switch-impl + bundle + + + + + org.apache.felix + maven-bundle-plugin + true + + + + org.opendaylight.controller.sample.l2switch.md.L2SwitchProvider + + ${project.build.directory}/META-INF + + + + + + + junit + junit + ${junit.version} + test + + + org.opendaylight.controller.samples.l2switch.md + l2switch-model + ${project.version} + + + + org.opendaylight.controller.model + model-inventory + + + + org.opendaylight.controller + sal-binding-api + + + org.opendaylight.yangtools + yang-common + ${yangtools.version} + + + org.opendaylight.yangtools + yang-binding + ${yangtools.version} + + + junit + junit + test + + + org.mockito + mockito-all + ${mockito.version} + test + + + org.opendaylight.controller + sal + + + org.opendaylight.controller.model + model-flow-service + + + org.opendaylight.controller.thirdparty + net.sf.jung2 + + + org.opendaylight.controller.model + model-topology + 1.1-SNAPSHOT + + + diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/L2SwitchProvider.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/L2SwitchProvider.java new file mode 100644 index 0000000000..6f31a7ec76 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/L2SwitchProvider.java @@ -0,0 +1,77 @@ +/* + * 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.controller.sample.l2switch.md; + +import org.opendaylight.controller.sample.l2switch.md.addresstracker.AddressTracker; +import org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterService; +import org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterServiceImpl; +import org.opendaylight.controller.sample.l2switch.md.inventory.InventoryService; +import org.opendaylight.controller.sample.l2switch.md.packet.PacketHandler; +import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphDijkstra; +import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService; +import org.opendaylight.controller.sample.l2switch.md.topology.TopologyLinkDataChangeHandler; +import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * L2SwitchProvider serves as the Activator for our L2Switch OSGI bundle. + */ +public class L2SwitchProvider extends AbstractBindingAwareConsumer + implements AutoCloseable { + + private final static Logger _logger = LoggerFactory.getLogger(L2SwitchProvider.class); + + private Registration listenerRegistration; + private AddressTracker addressTracker; + private TopologyLinkDataChangeHandler topologyLinkDataChangeHandler; + + + /** + * Setup the L2Switch. + * @param consumerContext The context of the L2Switch. + */ + @Override + public void onSessionInitialized(BindingAwareBroker.ConsumerContext consumerContext) { + DataBrokerService dataService = consumerContext.getSALService(DataBrokerService.class); + addressTracker = new AddressTracker(dataService); + + NetworkGraphService networkGraphService = new NetworkGraphDijkstra(); + FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataService, networkGraphService); + + NotificationService notificationService = + consumerContext.getSALService(NotificationService.class); + PacketProcessingService packetProcessingService = + consumerContext.getRpcService(PacketProcessingService.class); + PacketHandler packetHandler = new PacketHandler(); + packetHandler.setAddressTracker(addressTracker); + packetHandler.setFlowWriterService(flowWriterService); + packetHandler.setPacketProcessingService(packetProcessingService); + packetHandler.setInventoryService(new InventoryService(dataService)); + + this.listenerRegistration = notificationService.registerNotificationListener(packetHandler); + this.topologyLinkDataChangeHandler = new TopologyLinkDataChangeHandler(dataService, networkGraphService); + topologyLinkDataChangeHandler.registerAsDataChangeListener(); + } + + /** + * Cleanup the L2Switch. + * @throws Exception occurs when the NotificationListener is closed + */ + @Override + public void close() throws Exception { + if (listenerRegistration != null) + listenerRegistration.close(); + } +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/addresstracker/AddressTracker.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/addresstracker/AddressTracker.java new file mode 100644 index 0000000000..ae5f03110c --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/addresstracker/AddressTracker.java @@ -0,0 +1,102 @@ +/* + * 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.controller.sample.l2switch.md.addresstracker; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.L2Addresses; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2AddressKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.Future; + +/** + * AddressTracker manages the MD-SAL data tree for L2Address (mac, node connector pairings) information. + */ +public class AddressTracker { + + private final static Logger _logger = LoggerFactory.getLogger(AddressTracker.class); + private DataBrokerService dataService; + + /** + * Construct an AddressTracker with the specified inputs + * @param dataService The DataBrokerService for the AddressTracker + */ + public AddressTracker(DataBrokerService dataService) { + this.dataService = dataService; + } + + /** + * Get all the L2 Addresses in the MD-SAL data tree + * @return All the L2 Addresses in the MD-SAL data tree + */ + public L2Addresses getAddresses() { + return (L2Addresses)dataService.readOperationalData(InstanceIdentifier.builder(L2Addresses.class).toInstance()); + } + + /** + * Get a specific L2 Address in the MD-SAL data tree + * @param macAddress A MacAddress associated with an L2 Address object + * @return The L2 Address corresponding to the specified macAddress + */ + public L2Address getAddress(MacAddress macAddress) { + return (L2Address) dataService.readOperationalData(createPath(macAddress)); + } + + /** + * Add L2 Address into the MD-SAL data tree + * @param macAddress The MacAddress of the new L2Address object + * @param nodeConnectorRef The NodeConnectorRef of the new L2Address object + * @return Future containing the result of the add operation + */ + public Future> addAddress(MacAddress macAddress, NodeConnectorRef nodeConnectorRef) { + if(macAddress == null || nodeConnectorRef == null) { + return null; + } + + // Create L2Address + final L2AddressBuilder builder = new L2AddressBuilder(); + builder.setKey(new L2AddressKey(macAddress)) + .setMac(macAddress) + .setNodeConnectorRef(nodeConnectorRef); + + // Add L2Address to MD-SAL data tree + final DataModificationTransaction it = dataService.beginTransaction(); + it.putOperationalData(createPath(macAddress), builder.build()); + return it.commit(); + } + + /** + * Remove L2Address from the MD-SAL data tree + * @param macAddress The MacAddress of an L2Address object + * @return Future containing the result of the remove operation + */ + public Future> removeHost(MacAddress macAddress) { + final DataModificationTransaction it = dataService.beginTransaction(); + it.removeOperationalData(createPath(macAddress)); + return it.commit(); + } + + /** + * Create InstanceIdentifier path for an L2Address in the MD-SAL data tree + * @param macAddress The MacAddress of an L2Address object + * @return InstanceIdentifier of the L2Address corresponding to the specified macAddress + */ + private InstanceIdentifier createPath(MacAddress macAddress) { + return InstanceIdentifier.builder(L2Addresses.class) + .child(L2Address.class, new L2AddressKey(macAddress)).toInstance(); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterService.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterService.java new file mode 100644 index 0000000000..2d5149e492 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterService.java @@ -0,0 +1,42 @@ +/* + * 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.controller.sample.l2switch.md.flow; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; + +/** + * Service that adds packet forwarding flows to configuration data store. + */ +public interface FlowWriterService { + + /** + * Writes a flow that forwards packets to destPort if destination mac in packet is destMac and + * source Mac in packet is sourceMac. If sourceMac is null then flow would not set any source mac, + * resulting in all packets with destMac being forwarded to destPort. + * + * @param sourceMac + * @param destMac + * @param destNodeConnectorRef + */ + public void addMacToMacFlow(MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destNodeConnectorRef); + + /** + * Writes mac-to-mac flow on all ports that are in the path between given source and destination ports. + * It uses path provided by NetworkGraphService{@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService} to find a links{@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link} + * between given ports. And then writes appropriate flow on each port that is covered in that path. + * + * @param sourceMac + * @param sourceNodeConnectorRef + * @param destMac + * @param destNodeConnectorRef + */ + public void addMacToMacFlowsUsingShortestPath(MacAddress sourceMac, NodeConnectorRef sourceNodeConnectorRef, MacAddress destMac, NodeConnectorRef destNodeConnectorRef); + + +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImpl.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImpl.java new file mode 100644 index 0000000000..f49771a953 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImpl.java @@ -0,0 +1,284 @@ +/* + * 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.controller.sample.l2switch.md.flow; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService; +import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder; +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.Link; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Implementation of FlowWriterService{@link org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterService}, + * that builds required flow and writes to configuration data store using provided DataBrokerService + * {@link org.opendaylight.controller.sal.binding.api.data.DataBrokerService} + */ +public class FlowWriterServiceImpl implements FlowWriterService { + private static final Logger _logger = LoggerFactory.getLogger(FlowWriterServiceImpl.class); + private final DataBrokerService dataBrokerService; + private final NetworkGraphService networkGraphService; + private AtomicLong flowIdInc = new AtomicLong(); + private AtomicLong flowCookieInc = new AtomicLong(0x2a00000000000000L); + + + public FlowWriterServiceImpl(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService) { + Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null."); + Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null."); + this.dataBrokerService = dataBrokerService; + this.networkGraphService = networkGraphService; + } + + /** + * Writes a flow that forwards packets to destPort if destination mac in packet is destMac and + * source Mac in packet is sourceMac. If sourceMac is null then flow would not set any source mac, + * resulting in all packets with destMac being forwarded to destPort. + * + * @param sourceMac + * @param destMac + * @param destNodeConnectorRef + */ + @Override + public void addMacToMacFlow(MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destNodeConnectorRef) { + + Preconditions.checkNotNull(destMac, "Destination mac address should not be null."); + Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null."); + + + // do not add flow if both macs are same. + if(sourceMac != null && destMac.equals(sourceMac)) { + _logger.info("In addMacToMacFlow: No flows added. Source and Destination mac are same."); + return; + } + + // get flow table key + TableKey flowTableKey = new TableKey((short) 0); //TODO: Hard coded Table Id 0, need to get it from Configuration data. + + //build a flow path based on node connector to program flow + InstanceIdentifier flowPath = buildFlowPath(destNodeConnectorRef, flowTableKey); + + // build a flow that target given mac id + Flow flowBody = createMacToMacFlow(flowTableKey.getId(), 0, sourceMac, destMac, destNodeConnectorRef); + + // commit the flow in config data + writeFlowToConfigData(flowPath, flowBody); + } + + /** + * Writes mac-to-mac flow on all ports that are in the path between given source and destination ports. + * It uses path provided by NetworkGraphService + * {@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService} to find a links + * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link} + * between given ports. And then writes appropriate flow on each port that is covered in that path. + * + * @param sourceMac + * @param sourceNodeConnectorRef + * @param destMac + * @param destNodeConnectorRef + */ + @Override + public void addMacToMacFlowsUsingShortestPath(MacAddress sourceMac, + NodeConnectorRef sourceNodeConnectorRef, + MacAddress destMac, + NodeConnectorRef destNodeConnectorRef) { + Preconditions.checkNotNull(sourceMac, "Source mac address should not be null."); + Preconditions.checkNotNull(sourceNodeConnectorRef, "Source port should not be null."); + Preconditions.checkNotNull(destMac, "Destination mac address should not be null."); + Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null."); + + if(sourceNodeConnectorRef.equals(destNodeConnectorRef)) { + _logger.info("In addMacToMacFlowsUsingShortestPath: No flows added. Source and Destination ports are same."); + return; + + } + NodeId sourceNodeId = new NodeId(sourceNodeConnectorRef.getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue()); + NodeId destNodeId = new NodeId(destNodeConnectorRef.getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue()); + + // add destMac-To-sourceMac flow on source port + addMacToMacFlow(destMac, sourceMac, sourceNodeConnectorRef); + + // add sourceMac-To-destMac flow on destination port + addMacToMacFlow(sourceMac, destMac, destNodeConnectorRef); + + if(!sourceNodeId.equals(destNodeId)) { + List linksInBeween = networkGraphService.getPath(sourceNodeId, destNodeId); + + if(linksInBeween != null) { + // assumes the list order is maintained and starts with link that has source as source node + for(Link link : linksInBeween) { + // add sourceMac-To-destMac flow on source port + addMacToMacFlow(sourceMac, destMac, getSourceNodeConnectorRef(link)); + + // add destMac-To-sourceMac flow on destination port + addMacToMacFlow(destMac, sourceMac, getDestNodeConnectorRef(link)); + } + } + } + } + + private NodeConnectorRef getSourceNodeConnectorRef(Link link) { + InstanceIdentifier nodeConnectorInstanceIdentifier + = InstanceIdentifierUtils.createNodeConnectorIdentifier( + link.getSource().getSourceNode().getValue(), + link.getSource().getSourceTp().getValue()); + return new NodeConnectorRef(nodeConnectorInstanceIdentifier); + } + + private NodeConnectorRef getDestNodeConnectorRef(Link link) { + InstanceIdentifier nodeConnectorInstanceIdentifier + = InstanceIdentifierUtils.createNodeConnectorIdentifier( + link.getDestination().getDestNode().getValue(), + link.getDestination().getDestTp().getValue()); + + return new NodeConnectorRef(nodeConnectorInstanceIdentifier); + } + + /** + * @param nodeConnectorRef + * @return + */ + private InstanceIdentifier buildFlowPath(NodeConnectorRef nodeConnectorRef, TableKey flowTableKey) { + + // generate unique flow key + FlowId flowId = new FlowId(String.valueOf(flowIdInc.getAndIncrement())); + FlowKey flowKey = new FlowKey(flowId); + + return InstanceIdentifierUtils.generateFlowInstanceIdentifier(nodeConnectorRef, flowTableKey, flowKey); + } + + /** + * @param tableId + * @param priority + * @param sourceMac + * @param destMac + * @param destPort + * @return {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder} + * builds flow that forwards all packets with destMac to given port + */ + private Flow createMacToMacFlow(Short tableId, int priority, + MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destPort) { + + // start building flow + FlowBuilder macToMacFlow = new FlowBuilder() // + .setTableId(tableId) // + .setFlowName("mac2mac"); + + // use its own hash code for id. + macToMacFlow.setId(new FlowId(Long.toString(macToMacFlow.hashCode()))); + + // create a match that has mac to mac ethernet match + EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder() // + .setEthernetDestination(new EthernetDestinationBuilder() // + .setAddress(destMac) // + .build()); + // set source in the match only if present + if(sourceMac != null) { + ethernetMatchBuilder.setEthernetSource(new EthernetSourceBuilder() + .setAddress(sourceMac) + .build()); + } + EthernetMatch ethernetMatch = ethernetMatchBuilder.build(); + Match match = new MatchBuilder() + .setEthernetMatch(ethernetMatch) + .build(); + + + Uri destPortUri = destPort.getValue().firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId(); + + Action outputToControllerAction = new ActionBuilder() // + .setAction(new OutputActionCaseBuilder() // + .setOutputAction(new OutputActionBuilder() // + .setMaxLength(new Integer(0xffff)) // + .setOutputNodeConnector(destPortUri) // + .build()) // + .build()) // + .build(); + + // Create an Apply Action + ApplyActions applyActions = new ApplyActionsBuilder().setAction(ImmutableList.of(outputToControllerAction)) + .build(); + + // Wrap our Apply Action in an Instruction + Instruction applyActionsInstruction = new InstructionBuilder() // + .setInstruction(new ApplyActionsCaseBuilder()// + .setApplyActions(applyActions) // + .build()) // + .build(); + + // Put our Instruction in a list of Instructions + macToMacFlow + .setMatch(match) // + .setInstructions(new InstructionsBuilder() // + .setInstruction(ImmutableList.of(applyActionsInstruction)) // + .build()) // + .setPriority(priority) // + .setBufferId(0L) // + .setHardTimeout(0) // + .setIdleTimeout(0) // + .setCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement())) + .setFlags(new FlowModFlags(false, false, false, false, false)); + + return macToMacFlow.build(); + } + + /** + * Starts and commits data change transaction which + * modifies provided flow path with supplied body. + * + * @param flowPath + * @param flowBody + * @return transaction commit + */ + private Future> writeFlowToConfigData(InstanceIdentifier flowPath, + Flow flowBody) { + DataModificationTransaction addFlowTransaction = dataBrokerService.beginTransaction(); + addFlowTransaction.putConfigurationData(flowPath, flowBody); + return addFlowTransaction.commit(); + } +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/inventory/InventoryService.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/inventory/InventoryService.java new file mode 100644 index 0000000000..a12f394e66 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/inventory/InventoryService.java @@ -0,0 +1,102 @@ +/* + * 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.controller.sample.l2switch.md.inventory; + +import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.*; + +/** + * InventoryService provides functions related to Nodes & NodeConnectors. + */ +public class InventoryService { + private DataBrokerService dataService; + // Key: SwitchId, Value: NodeConnectorRef that corresponds to NC between controller & switch + private HashMap controllerSwitchConnectors; + + /** + * Construct an InventoryService object with the specified inputs. + * @param dataService The DataBrokerService associated with the InventoryService. + */ + public InventoryService(DataBrokerService dataService) { + this.dataService = dataService; + controllerSwitchConnectors = new HashMap(); + } + + public HashMap getControllerSwitchConnectors() { + return controllerSwitchConnectors; + } + + // ToDo: Improve performance for thousands of switch ports + /** + * Get the External NodeConnectors of the network, which are the NodeConnectors connected to hosts. + * @return The list of external node connectors. + */ + public List getExternalNodeConnectors() { + // External NodeConnectors = All - Internal + ArrayList externalNodeConnectors = new ArrayList(); + Set internalNodeConnectors = new HashSet<>(); + + // Read Topology -- find list of switch-to-switch internal node connectors + NetworkTopology networkTopology = + (NetworkTopology)dataService.readOperationalData( + InstanceIdentifier.builder(NetworkTopology.class).toInstance()); + + for (Topology topology : networkTopology.getTopology()) { + Topology completeTopology = + (Topology)dataService.readOperationalData( + InstanceIdentifierUtils.generateTopologyInstanceIdentifier( + topology.getTopologyId().getValue())); + + for (Link link : completeTopology.getLink()) { + internalNodeConnectors.add(link.getDestination().getDestTp().getValue()); + internalNodeConnectors.add(link.getSource().getSourceTp().getValue()); + } + } + + // Read Inventory -- contains list of all nodeConnectors + InstanceIdentifier.InstanceIdentifierBuilder nodesInsIdBuilder = InstanceIdentifier.builder(Nodes.class); + Nodes nodes = (Nodes)dataService.readOperationalData(nodesInsIdBuilder.toInstance()); + if (nodes != null) { + for (Node node : nodes.getNode()) { + Node completeNode = (Node)dataService.readOperationalData(InstanceIdentifierUtils.createNodePath(node.getId())); + for (NodeConnector nodeConnector : completeNode.getNodeConnector()) { + // NodeConnector isn't switch-to-switch, so it must be controller-to-switch (internal) or external + if (!internalNodeConnectors.contains(nodeConnector.getId().getValue())) { + NodeConnectorRef ncRef = new NodeConnectorRef( + InstanceIdentifier.builder(Nodes.class).child(Node.class, node.getKey()) + .child(NodeConnector.class, nodeConnector.getKey()).toInstance()); + + // External node connectors have "-" in their name for mininet, i.e. "s1-eth1" + if (nodeConnector.getAugmentation(FlowCapableNodeConnector.class).getName().contains("-")) { + externalNodeConnectors.add(ncRef); + } + // Controller-to-switch internal node connectors + else { + controllerSwitchConnectors.put(node.getId().getValue(), ncRef); + } + } + } + } + } + + return externalNodeConnectors; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/packet/PacketHandler.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/packet/PacketHandler.java new file mode 100644 index 0000000000..753de4aa85 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/packet/PacketHandler.java @@ -0,0 +1,223 @@ +/* + * 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.controller.sample.l2switch.md.packet; + +import org.opendaylight.controller.sample.l2switch.md.addresstracker.AddressTracker; +import org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterService; +import org.opendaylight.controller.sample.l2switch.md.inventory.InventoryService; +import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils; +import org.opendaylight.controller.sal.packet.Ethernet; +import org.opendaylight.controller.sal.packet.LLDP; +import org.opendaylight.controller.sal.packet.LinkEncap; +import org.opendaylight.controller.sal.packet.Packet; +import org.opendaylight.controller.sal.packet.RawPacket; +import org.opendaylight.controller.sal.utils.HexEncode; +import org.opendaylight.controller.sal.utils.NetUtils; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.*; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.address.tracker.rev140402.l2.addresses.L2Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; + +/** + * PacketHandler examines Ethernet packets to find L2Addresses (mac, nodeConnector) pairings + * of the sender and learns them. + * It also forwards the data packets appropriately dependending upon whether it knows about the + * target or not. + */ +public class PacketHandler implements PacketProcessingListener { + + private final static Logger _logger = LoggerFactory.getLogger(PacketHandler.class); + + private PacketProcessingService packetProcessingService; + private AddressTracker addressTracker; + private FlowWriterService flowWriterService; + private InventoryService inventoryService; + + public void setAddressTracker(AddressTracker addressTracker) { + this.addressTracker = addressTracker; + } + + public void setPacketProcessingService(PacketProcessingService packetProcessingService) { + this.packetProcessingService = packetProcessingService; + } + + public void setFlowWriterService(FlowWriterService flowWriterService) { + this.flowWriterService = flowWriterService; + } + + public void setInventoryService(InventoryService inventoryService) { + this.inventoryService = inventoryService; + } + + /** + * The handler function for all incoming packets. + * @param packetReceived The incoming packet. + */ + @Override + public void onPacketReceived(PacketReceived packetReceived) { + + if(packetReceived == null) return; + + try { + byte[] payload = packetReceived.getPayload(); + RawPacket rawPacket = new RawPacket(payload); + NodeConnectorRef ingress = packetReceived.getIngress(); + + Packet packet = decodeDataPacket(rawPacket); + + if(!(packet instanceof Ethernet)) return; + + handleEthernetPacket(packet, ingress); + + } catch(Throwable _e) { + _e.printStackTrace(); + } + } + + /** + * The handler function for Ethernet packets. + * @param packet The incoming Ethernet packet. + * @param ingress The NodeConnector where the Ethernet packet came from. + */ + private void handleEthernetPacket(Packet packet, NodeConnectorRef ingress) { + byte[] srcMac = ((Ethernet) packet).getSourceMACAddress(); + byte[] destMac = ((Ethernet) packet).getDestinationMACAddress(); + + if (srcMac == null || srcMac.length == 0) return; + + Object enclosedPacket = packet.getPayload(); + + if (enclosedPacket instanceof LLDP) + return; // LLDP packets are handled by OpenFlowPlugin + + // get l2address by src mac + // if unknown, add l2address + MacAddress srcMacAddress = toMacAddress(srcMac); + L2Address src = addressTracker.getAddress(srcMacAddress); + boolean isSrcKnown = (src != null); + if (!isSrcKnown) { + addressTracker.addAddress(srcMacAddress, ingress); + } + + // get host by dest mac + // if known set dest known to true + MacAddress destMacAddress = toMacAddress(destMac); + L2Address dest = addressTracker.getAddress(destMacAddress); + boolean isDestKnown = (dest != null); + + byte[] payload = packet.getRawPayload(); + // if (src and dest known) + // sendpacket to dest and add src<->dest flow + if(isSrcKnown & isDestKnown) { + flowWriterService.addMacToMacFlowsUsingShortestPath(srcMacAddress, src.getNodeConnectorRef(), + destMacAddress, dest.getNodeConnectorRef()); + sendPacketOut(payload, getControllerNodeConnector(dest.getNodeConnectorRef()), dest.getNodeConnectorRef()); + } else { + // if (dest unknown) + // sendpacket to external links minus ingress + floodExternalPorts(payload, ingress); + } + } + + /** + * Floods the specified payload on external ports, which are ports not connected to switches. + * @param payload The payload to be flooded. + * @param ingress The NodeConnector where the payload came from. + */ + private void floodExternalPorts(byte[] payload, NodeConnectorRef ingress) { + List externalPorts = inventoryService.getExternalNodeConnectors(); + externalPorts.remove(ingress); + + for (NodeConnectorRef egress : externalPorts) { + sendPacketOut(payload, getControllerNodeConnector(egress), egress); + } + } + + /** + * Sends the specified packet on the specified port. + * @param payload The payload to be sent. + * @param ingress The NodeConnector where the payload came from. + * @param egress The NodeConnector where the payload will go. + */ + private void sendPacketOut(byte[] payload, NodeConnectorRef ingress, NodeConnectorRef egress) { + if (ingress == null || egress == null) return; + InstanceIdentifier egressNodePath = InstanceIdentifierUtils.getNodePath(egress.getValue()); + TransmitPacketInput input = new TransmitPacketInputBuilder() // + .setPayload(payload) // + .setNode(new NodeRef(egressNodePath)) // + .setEgress(egress) // + .setIngress(ingress) // + .build(); + packetProcessingService.transmitPacket(input); + } + + /** + * Decodes an incoming packet. + * @param raw The raw packet to be decoded. + * @return The decoded form of the raw packet. + */ + private Packet decodeDataPacket(RawPacket raw) { + if(raw == null) { + return null; + } + byte[] data = raw.getPacketData(); + if(data.length <= 0) { + return null; + } + if(raw.getEncap().equals(LinkEncap.ETHERNET)) { + Ethernet res = new Ethernet(); + try { + res.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte); + res.setRawPayload(raw.getPacketData()); + } catch(Exception e) { + _logger.warn("Failed to decode packet: {}", e.getMessage()); + } + return res; + } + return null; + } + + /** + * Creates a MacAddress object out of a byte array. + * @param dataLinkAddress The byte-array form of a MacAddress + * @return MacAddress of the specified dataLinkAddress. + */ + private MacAddress toMacAddress(byte[] dataLinkAddress) { + return new MacAddress(HexEncode.bytesToHexStringFormat(dataLinkAddress)); + } + + /** + * Gets the NodeConnector that connects the controller & switch for a specified switch port/node connector. + * @param nodeConnectorRef The nodeConnector of a switch. + * @return The NodeConnector that that connects the controller & switch. + */ + private NodeConnectorRef getControllerNodeConnector(NodeConnectorRef nodeConnectorRef) { + NodeConnectorRef controllerSwitchNodeConnector = null; + HashMap controllerSwitchConnectors = inventoryService.getControllerSwitchConnectors(); + InstanceIdentifier nodePath = InstanceIdentifierUtils.getNodePath(nodeConnectorRef.getValue()); + if (nodePath != null) { + NodeKey nodeKey = InstanceIdentifierUtils.getNodeKey(nodePath); + if (nodeKey != null) { + controllerSwitchNodeConnector = controllerSwitchConnectors.get(nodeKey.getId().getValue()); + } + } + return controllerSwitchNodeConnector; + } +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstra.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstra.java new file mode 100644 index 0000000000..a90ac5a007 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstra.java @@ -0,0 +1,112 @@ +/* + * 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.controller.sample.l2switch.md.topology; + +import com.google.common.base.Preconditions; +import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath; +import edu.uci.ics.jung.graph.DirectedSparseGraph; +import edu.uci.ics.jung.graph.Graph; +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.Link; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * Implementation of NetworkGraphService{@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService}. + * It uses Jung graph library internally to maintain a graph and optimum way to return shortest path using + * Dijkstra algorithm. + */ +public class NetworkGraphDijkstra implements NetworkGraphService { + + private static final Logger _logger = LoggerFactory.getLogger(NetworkGraphDijkstra.class); + + DijkstraShortestPath shortestPath = null; + Graph networkGraph = null; + + /** + * Adds links to existing graph or creates new directed graph with given links if graph was not initialized. + * @param links + */ + @Override + public synchronized void addLinks(List links) { + if(links == null || links.isEmpty()) { + _logger.info("In addLinks: No link added as links is null or empty."); + return; + } + + if(networkGraph == null) { + networkGraph = new DirectedSparseGraph<>(); + } + + for(Link link : links) { + NodeId sourceNodeId = link.getSource().getSourceNode(); + NodeId destinationNodeId = link.getDestination().getDestNode(); + networkGraph.addVertex(sourceNodeId); + networkGraph.addVertex(destinationNodeId); + networkGraph.addEdge(link, sourceNodeId, destinationNodeId); + } + if(shortestPath == null) { + shortestPath = new DijkstraShortestPath<>(networkGraph); + } else { + shortestPath.reset(); + } + } + + /** + * removes links from existing graph. + * @param links + */ + @Override + public synchronized void removeLinks(List links) { + Preconditions.checkNotNull(networkGraph, "Graph is not initialized, add links first."); + + if(links == null || links.isEmpty()) { + _logger.info("In removeLinks: No link removed as links is null or empty."); + return; + } + + for(Link link : links) { + networkGraph.removeEdge(link); + } + + if(shortestPath == null) { + shortestPath = new DijkstraShortestPath<>(networkGraph); + } else { + shortestPath.reset(); + } + } + + /** + * returns a path between 2 nodes. Uses Dijkstra's algorithm to return shortest path. + * @param sourceNodeId + * @param destinationNodeId + * @return + */ + @Override + public synchronized List getPath(NodeId sourceNodeId, NodeId destinationNodeId) { + Preconditions.checkNotNull(shortestPath, "Graph is not initialized, add links first."); + + if(sourceNodeId == null || destinationNodeId == null) { + _logger.info("In getPath: returning null, as sourceNodeId or destinationNodeId is null."); + return null; + } + + return shortestPath.getPath(sourceNodeId, destinationNodeId); + } + + /** + * Clears the prebuilt graph, in case same service instance is required to process a new graph. + */ + @Override + public synchronized void clear() { + networkGraph = null; + shortestPath = null; + } +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphService.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphService.java new file mode 100644 index 0000000000..173be342c4 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphService.java @@ -0,0 +1,46 @@ +/* + * 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.controller.sample.l2switch.md.topology; + +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.Link; + +import java.util.List; + +/** + * Service that allows to build a network graph using Topology links + * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link} + * and exposes operation that can be performed on such graph. + */ +public interface NetworkGraphService { + + /** + * Adds links to existing graph or creates new graph with given links if graph was not initialized. + * @param links + */ + public void addLinks(List links); + + /** + * removes links from existing graph. + * @param links + */ + public void removeLinks(List links); + + /** + * returns a path between 2 nodes. Implementation should ideally return shortest path. + * @param sourceNodeId + * @param destinationNodeId + * @return + */ + public List getPath(NodeId sourceNodeId, NodeId destinationNodeId); + + /** + * Clears the prebuilt graph, in case same service instance is required to process a new graph. + */ + public void clear(); +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandler.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandler.java new file mode 100644 index 0000000000..254ebf8b4a --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandler.java @@ -0,0 +1,143 @@ +/* + * 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.controller.sample.l2switch.md.topology; + +import com.google.common.base.Preconditions; +import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Listens to data change events on topology links + * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link} + * and maintains a topology graph using provided NetworkGraphService + * {@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService}. + * It refreshes the graph after a delay(default 10 sec) to accommodate burst of change events if they come in bulk. + * This is to avoid continuous refresh of graph on a series of change events in short time. + */ +public class TopologyLinkDataChangeHandler implements DataChangeListener { + private static final Logger _logger = LoggerFactory.getLogger(TopologyLinkDataChangeHandler.class); + private static final String DEFAULT_TOPOLOGY_ID = "flow:1"; + + private boolean networkGraphRefreshScheduled = false; + private final ScheduledExecutorService networkGraphRefreshScheduler = Executors.newScheduledThreadPool(1); + private final long DEFAULT_GRAPH_REFRESH_DELAY = 10; + private final long graphRefreshDelayInSec; + + private final NetworkGraphService networkGraphService; + private final DataBrokerService dataBrokerService; + + /** + * Uses default delay to refresh topology graph if this constructor is used. + * @param dataBrokerService + * @param networkGraphService + */ + public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService) { + Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null."); + Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null."); + this.dataBrokerService = dataBrokerService; + this.networkGraphService = networkGraphService; + this.graphRefreshDelayInSec = DEFAULT_GRAPH_REFRESH_DELAY; + } + + /** + * + * @param dataBrokerService + * @param networkGraphService + * @param graphRefreshDelayInSec + */ + public TopologyLinkDataChangeHandler(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService, + long graphRefreshDelayInSec) { + Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null."); + Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null."); + this.dataBrokerService = dataBrokerService; + this.networkGraphService = networkGraphService; + this.graphRefreshDelayInSec = graphRefreshDelayInSec; + } + + /** + * Based on if links have been added or removed in topology data store, schedules a refresh of network graph. + * @param dataChangeEvent + */ + @Override + public void onDataChanged(DataChangeEvent, DataObject> dataChangeEvent) { + if(dataChangeEvent == null) { + _logger.info("In onDataChanged: No Processing done as dataChangeEvent is null."); + } + Map, DataObject> linkOriginalData = dataChangeEvent.getOriginalOperationalData(); + Map, DataObject> linkUpdatedData = dataChangeEvent.getUpdatedOperationalData(); + // change this logic, once MD-SAL start populating DeletedOperationData Set + if(linkOriginalData != null && linkUpdatedData != null + && (linkOriginalData.size() != 0 || linkUpdatedData.size() != 0) + && !networkGraphRefreshScheduled) { + networkGraphRefreshScheduled = linkOriginalData.size() != linkUpdatedData.size(); + if(networkGraphRefreshScheduled) { + networkGraphRefreshScheduler.schedule(new NetworkGraphRefresher(), graphRefreshDelayInSec, TimeUnit.SECONDS); + } + } + + } + + /** + * Registers as a data listener to receive changes done to + * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link} + * under {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology} + * operation data root. + */ + + public void registerAsDataChangeListener() { + InstanceIdentifier linkInstance = InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, new TopologyKey(new TopologyId(DEFAULT_TOPOLOGY_ID))).child(Link.class).toInstance(); + dataBrokerService.registerDataChangeListener(linkInstance, this); + } + + /** + * + */ + private class NetworkGraphRefresher implements Runnable { + /** + * + */ + @Override + public void run() { + networkGraphRefreshScheduled = false; + //TODO: it should refer to changed links only from DataChangeEvent above. + List links = getLinksFromTopology(DEFAULT_TOPOLOGY_ID); + networkGraphService.clear();// can remove this once changed links are addressed + if(links != null && !links.isEmpty()) { + networkGraphService.addLinks(links); + } + } + + /** + * @param topologyId + * @return + */ + private List getLinksFromTopology(String topologyId) { + InstanceIdentifier topologyInstanceIdentifier = InstanceIdentifierUtils.generateTopologyInstanceIdentifier(topologyId); + Topology topology = (Topology) dataBrokerService.readOperationalData(topologyInstanceIdentifier); + return topology.getLink(); + } + } +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/util/InstanceIdentifierUtils.java b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/util/InstanceIdentifierUtils.java new file mode 100644 index 0000000000..ea08f94ebc --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/main/java/org/opendaylight/controller/sample/l2switch/md/util/InstanceIdentifierUtils.java @@ -0,0 +1,157 @@ +/* + * 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.controller.sample.l2switch.md.util; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/* InstanceIdentifierUtils provides utility functions related to InstanceIdentifiers. + */ +public class InstanceIdentifierUtils { + + /** + * Creates an Instance Identifier (path) for node with specified id + * + * @param nodeId + * @return + */ + public static final InstanceIdentifier createNodePath(NodeId nodeId) { + return InstanceIdentifier.builder(Nodes.class) // + .child(Node.class, new NodeKey(nodeId)) // + .build(); + } + + /** + * Shorten's node child path to node path. + * + * @param nodeChild child of node, from which we want node path. + * @return + */ + public static final InstanceIdentifier getNodePath(InstanceIdentifier nodeChild) { + return nodeChild.firstIdentifierOf(Node.class); + } + + + /** + * Creates a table path by appending table specific location to node path + * + * @param nodePath + * @param tableKey + * @return + */ + public static final InstanceIdentifier createTablePath(InstanceIdentifier nodePath, TableKey tableKey) { + return InstanceIdentifier.builder(nodePath) + .augmentation(FlowCapableNode.class) + .child(Table.class, tableKey) + .build(); + } + + /** + * Creates a path for particular flow, by appending flow-specific information + * to table path. + * + * @param table + * @param flowKey + * @return + */ + public static InstanceIdentifier createFlowPath(InstanceIdentifier
table, FlowKey flowKey) { + return InstanceIdentifier.builder(table) + .child(Flow.class, flowKey) + .build(); + } + + /** + * Extract table id from table path. + * + * @param tablePath + * @return + */ + public static Short getTableId(InstanceIdentifier
tablePath) { + return tablePath.firstKeyOf(Table.class, TableKey.class).getId(); + } + + /** + * Extracts NodeConnectorKey from node connector path. + */ + public static NodeConnectorKey getNodeConnectorKey(InstanceIdentifier nodeConnectorPath) { + return nodeConnectorPath.firstKeyOf(NodeConnector.class, NodeConnectorKey.class); + } + + /** + * Extracts NodeKey from node path. + */ + public static NodeKey getNodeKey(InstanceIdentifier nodePath) { + return nodePath.firstKeyOf(Node.class, NodeKey.class); + } + + + // + public static final InstanceIdentifier createNodeConnectorIdentifier(String nodeIdValue, + String nodeConnectorIdValue) { + return InstanceIdentifier.builder(createNodePath(new NodeId(nodeIdValue))) // + .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(nodeConnectorIdValue))) // + .build(); + } + + /** + * @param nodeConnectorRef + * @return + */ + public static InstanceIdentifier generateNodeInstanceIdentifier(NodeConnectorRef nodeConnectorRef) { + return nodeConnectorRef.getValue().firstIdentifierOf(Node.class); + } + + /** + * @param nodeConnectorRef + * @param flowTableKey + * @return + */ + public static InstanceIdentifier
generateFlowTableInstanceIdentifier(NodeConnectorRef nodeConnectorRef, TableKey flowTableKey) { + return InstanceIdentifier.builder(generateNodeInstanceIdentifier(nodeConnectorRef)) + .augmentation(FlowCapableNode.class) + .child(Table.class, flowTableKey) + .build(); + } + + /** + * @param nodeConnectorRef + * @param flowTableKey + * @param flowKey + * @return + */ + public static InstanceIdentifier generateFlowInstanceIdentifier(NodeConnectorRef nodeConnectorRef, + TableKey flowTableKey, + FlowKey flowKey) { + return InstanceIdentifier.builder(generateFlowTableInstanceIdentifier(nodeConnectorRef, flowTableKey)) + .child(Flow.class, flowKey) + .build(); + } + + public static InstanceIdentifier generateTopologyInstanceIdentifier(String topologyId) { + return InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, new TopologyKey(new TopologyId(topologyId))) + .build(); + } +} + diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImplTest.java b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImplTest.java new file mode 100644 index 0000000000..3520d812d7 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/flow/FlowWriterServiceImplTest.java @@ -0,0 +1,150 @@ +/** + * 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.controller.sample.l2switch.md.flow; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + */ +public class FlowWriterServiceImplTest { + private DataBrokerService dataBrokerService; + private NodeConnectorRef srcNodeConnectorRef; + private NodeConnectorRef destNodeConnectorRef; + private MacAddress destMacAddress; + private MacAddress srcMacAddress; + private DataModificationTransaction dataModificationTransaction; + private NetworkGraphService networkGraphService; + + @Before + public void init() { + dataBrokerService = mock(DataBrokerService.class); + networkGraphService = mock(NetworkGraphService.class); + //build source node connector ref + InstanceIdentifier srcNodesInstanceIdentifier + = InstanceIdentifier.builder(Nodes.class) + .build(); + InstanceIdentifier srcNodeInstanceIdentifier + = InstanceIdentifier.builder(srcNodesInstanceIdentifier) + .child(Node.class, new NodeKey(new NodeId("openflow:1"))) + .build(); + InstanceIdentifier srcNodeConnectorInstanceIdentifier + = InstanceIdentifier.builder(srcNodeInstanceIdentifier) + .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId("openflow:1:2"))) + .build(); + srcNodeConnectorRef = new NodeConnectorRef(srcNodeConnectorInstanceIdentifier); + + //build dest node connector ref + InstanceIdentifier nodesInstanceIdentifier + = InstanceIdentifier.builder(Nodes.class) + .build(); + InstanceIdentifier nodeInstanceIdentifier + = InstanceIdentifier.builder(nodesInstanceIdentifier) + .child(Node.class, new NodeKey(new NodeId("openflow:2"))) + .build(); + InstanceIdentifier nodeConnectorInstanceIdentifier + = InstanceIdentifier.builder(nodeInstanceIdentifier) + .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId("openflow:2:2"))) + .build(); + destNodeConnectorRef = new NodeConnectorRef(nodeConnectorInstanceIdentifier); + destMacAddress = new MacAddress("00:0a:95:9d:68:16"); + srcMacAddress = new MacAddress("00:0a:95:8c:97:24"); + dataModificationTransaction = mock(DataModificationTransaction.class); + when(dataBrokerService.beginTransaction()).thenReturn(dataModificationTransaction); + } + + @Test + public void testFlowWriterServiceImpl_NPEWhenDataBrokerServiceIsNull() throws Exception { + try { + new FlowWriterServiceImpl(null, networkGraphService); + fail("Expected null pointer exception."); + } catch(NullPointerException npe) { + assertEquals("dataBrokerService should not be null.", npe.getMessage()); + } + } + + @Test + public void testAddMacToMacFlow_NPEWhenNullSourceMacDestMacAndNodeConnectorRef() throws Exception { + FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService); + try { + flowWriterService.addMacToMacFlow(null, null, null); + fail("Expected null pointer exception."); + } catch(NullPointerException npe) { + assertEquals("Destination mac address should not be null.", npe.getMessage()); + } + } + + @Test + public void testAddMacToMacFlow_NPEWhenSourceMacNullMac() throws Exception { + FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService); + try { + flowWriterService.addMacToMacFlow(null, null, destNodeConnectorRef); + fail("Expected null pointer exception."); + } catch(NullPointerException npe) { + assertEquals("Destination mac address should not be null.", npe.getMessage()); + } + } + + @Test + public void testAddMacToMacFlow_NPEWhenNullSourceMacNodeConnectorRef() throws Exception { + FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService); + try { + flowWriterService.addMacToMacFlow(null, destMacAddress, null); + fail("Expected null pointer exception."); + } catch(NullPointerException npe) { + assertEquals("Destination port should not be null.", npe.getMessage()); + } + } + + @Test + public void testAddMacToMacFlow_WhenNullSourceMac() throws Exception { + FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService); + flowWriterService.addMacToMacFlow(null, destMacAddress, destNodeConnectorRef); + verify(dataBrokerService, times(1)).beginTransaction(); + verify(dataModificationTransaction, times(1)).commit(); + } + + @Test + public void testAddMacToMacFlow_WhenSrcAndDestMacAreSame() throws Exception { + FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService); + flowWriterService.addMacToMacFlow(new MacAddress(destMacAddress.getValue()), destMacAddress, destNodeConnectorRef); + verify(dataBrokerService, never()).beginTransaction(); + verify(dataModificationTransaction, never()).commit(); + + } + + @Test + public void testAddMacToMacFlow_SunnyDay() throws Exception { + FlowWriterService flowWriterService = new FlowWriterServiceImpl(dataBrokerService, networkGraphService); + flowWriterService.addMacToMacFlow(srcMacAddress, destMacAddress, destNodeConnectorRef); + verify(dataBrokerService, times(1)).beginTransaction(); + verify(dataModificationTransaction, times(1)).commit(); + } + +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstraTest.java b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstraTest.java new file mode 100644 index 0000000000..3669a5c979 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/NetworkGraphDijkstraTest.java @@ -0,0 +1,158 @@ +/** + * 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.controller.sample.l2switch.md.topology; + +import org.junit.Before; +import org.junit.Test; +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.link.attributes.Destination; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + */ +public class NetworkGraphDijkstraTest { + Link link1, link2, link3, link4, link5, link6, link7, link8, link9, link10,link11,link12; + Destination dest1, dest2, dest3, dest4, dest5, dest6,dest7,dest8,dest9,dest10,dest11,dest12; + Source src1, src2, src3, src4, src5, src6,src7,src8,src9,src10,src11,src12; + NodeId nodeId1 = new NodeId("openflow:1"); + NodeId nodeId2 = new NodeId("openflow:2"); + NodeId nodeId3 = new NodeId("openflow:3"); + NodeId nodeId4 = new NodeId("openflow:4"); + NodeId nodeId5 = new NodeId("openflow:5"); + NodeId nodeId6 = new NodeId("openflow:6"); + NodeId nodeId7 = new NodeId("openflow:7"); + List links = new ArrayList<>(); + + @Before + public void init() { + link1 = mock(Link.class); + link2 = mock(Link.class); + link3 = mock(Link.class); + link4 = mock(Link.class); + link5 = mock(Link.class); + link6 = mock(Link.class); + link7 = mock(Link.class); + link8 = mock(Link.class); + link9 = mock(Link.class); + link10 = mock(Link.class); + link11 = mock(Link.class); + link12 = mock(Link.class); + dest1 = mock(Destination.class); + dest2 = mock(Destination.class); + dest3 = mock(Destination.class); + dest4 = mock(Destination.class); + dest5 = mock(Destination.class); + dest6 = mock(Destination.class); + dest7 = mock(Destination.class); + dest8 = mock(Destination.class); + dest9 = mock(Destination.class); + dest10 = mock(Destination.class); + dest11 = mock(Destination.class); + dest12 = mock(Destination.class); + src1 = mock(Source.class); + src2 = mock(Source.class); + src3 = mock(Source.class); + src4 = mock(Source.class); + src5 = mock(Source.class); + src6 = mock(Source.class); + src7 = mock(Source.class); + src8 = mock(Source.class); + src9 = mock(Source.class); + src10 = mock(Source.class); + src11 = mock(Source.class); + src12 = mock(Source.class); + when(link1.getSource()).thenReturn(src1); + when(link2.getSource()).thenReturn(src2); + when(link3.getSource()).thenReturn(src3); + when(link4.getSource()).thenReturn(src4); + when(link5.getSource()).thenReturn(src5); + when(link6.getSource()).thenReturn(src6); + when(link7.getSource()).thenReturn(src7); + when(link8.getSource()).thenReturn(src8); + when(link9.getSource()).thenReturn(src9); + when(link10.getSource()).thenReturn(src10); + when(link11.getSource()).thenReturn(src11); + when(link12.getSource()).thenReturn(src12); + when(link1.getDestination()).thenReturn(dest1); + when(link2.getDestination()).thenReturn(dest2); + when(link3.getDestination()).thenReturn(dest3); + when(link4.getDestination()).thenReturn(dest4); + when(link5.getDestination()).thenReturn(dest5); + when(link6.getDestination()).thenReturn(dest6); + when(link7.getDestination()).thenReturn(dest7); + when(link8.getDestination()).thenReturn(dest8); + when(link9.getDestination()).thenReturn(dest9); + when(link10.getDestination()).thenReturn(dest10); + when(link11.getDestination()).thenReturn(dest11); + when(link12.getDestination()).thenReturn(dest12); + when(src1.getSourceNode()).thenReturn(nodeId1); + when(dest1.getDestNode()).thenReturn(nodeId2); + when(src2.getSourceNode()).thenReturn(nodeId2); + when(dest2.getDestNode()).thenReturn(nodeId1); + when(src3.getSourceNode()).thenReturn(nodeId1); + when(dest3.getDestNode()).thenReturn(nodeId3); + when(src4.getSourceNode()).thenReturn(nodeId3); + when(dest4.getDestNode()).thenReturn(nodeId1); + when(src5.getSourceNode()).thenReturn(nodeId2); + when(dest5.getDestNode()).thenReturn(nodeId4); + when(src6.getSourceNode()).thenReturn(nodeId4); + when(dest6.getDestNode()).thenReturn(nodeId2); + when(src7.getSourceNode()).thenReturn(nodeId2); + when(dest7.getDestNode()).thenReturn(nodeId5); + when(src8.getSourceNode()).thenReturn(nodeId5); + when(dest8.getDestNode()).thenReturn(nodeId2); + when(src9.getSourceNode()).thenReturn(nodeId6); + when(dest9.getDestNode()).thenReturn(nodeId3); + when(src10.getSourceNode()).thenReturn(nodeId3); + when(dest10.getDestNode()).thenReturn(nodeId6); + when(src11.getSourceNode()).thenReturn(nodeId7); + when(dest11.getDestNode()).thenReturn(nodeId3); + when(src12.getSourceNode()).thenReturn(nodeId3); + when(dest12.getDestNode()).thenReturn(nodeId7); + links.add(link1); + links.add(link2); + links.add(link3); + links.add(link4); + links.add(link5); + links.add(link6); + links.add(link7); + links.add(link8); + links.add(link9); + links.add(link10); + links.add(link11); + links.add(link12); + + } + + @Test + public void testAddLinksAndGetPath() throws Exception { + NetworkGraphService networkGraphService = new NetworkGraphDijkstra(); + networkGraphService.addLinks(links); + List path = networkGraphService.getPath(nodeId2, nodeId3); + assertEquals("path size is not as expected.", 2, path.size()); + assertEquals("link source is not as expected.", nodeId2, path.get(0).getSource().getSourceNode()); + assertEquals("link destination is not as expected.", nodeId1, path.get(0).getDestination().getDestNode()); + path = networkGraphService.getPath(nodeId3, nodeId2); + assertEquals("path size is not as expected.", 2, path.size()); + assertEquals("link source is not as expected.", nodeId3, path.get(0).getSource().getSourceNode()); + assertEquals("link destination is not as expected.", nodeId1, path.get(0).getDestination().getDestNode()); + + path = networkGraphService.getPath(nodeId4, nodeId6); + assertEquals("path size is not as expected.", 4, path.size()); + assertEquals("link source is not as expected.", nodeId4, path.get(0).getSource().getSourceNode()); + assertEquals("link destination is not as expected.", nodeId2, path.get(0).getDestination().getDestNode()); + } +} diff --git a/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandlerTest.java b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandlerTest.java new file mode 100644 index 0000000000..9ecd25651a --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/implementation/src/test/java/org/opendaylight/controller/sample/l2switch/md/topology/TopologyLinkDataChangeHandlerTest.java @@ -0,0 +1,67 @@ +/** + * 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.controller.sample.l2switch.md.topology; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + */ +public class TopologyLinkDataChangeHandlerTest { + NetworkGraphService networkGraphService; + DataBrokerService dataBrokerService; + DataChangeEvent dataChangeEvent; + Topology topology; + Link link; + + @Before + public void init() { + networkGraphService = mock(NetworkGraphService.class); + dataBrokerService = mock(DataBrokerService.class); + dataChangeEvent = mock(DataChangeEvent.class); + link = mock(Link.class); + topology = mock(Topology.class); + } + + @Test + public void testOnDataChange() throws Exception { + TopologyLinkDataChangeHandler topologyLinkDataChangeHandler = new TopologyLinkDataChangeHandler(dataBrokerService, networkGraphService, 2); + Map, DataObject> original = new HashMap, DataObject>(); + InstanceIdentifier instanceIdentifier = InstanceIdentifierUtils.generateTopologyInstanceIdentifier("flow:1"); + DataObject dataObject = mock(DataObject.class); + Map, DataObject> updated = new HashMap, DataObject>(); + updated.put(instanceIdentifier, dataObject); + when(dataChangeEvent.getUpdatedOperationalData()).thenReturn(updated); + when(dataChangeEvent.getOriginalOperationalData()).thenReturn(original); + List links = new ArrayList<>(); + links.add(link); + when(dataBrokerService.readOperationalData(instanceIdentifier)).thenReturn(topology); + when(topology.getLink()).thenReturn(links); + + topologyLinkDataChangeHandler.onDataChanged(dataChangeEvent); + Thread.sleep(2100); + verify(networkGraphService, times(1)).addLinks(links); + } +} diff --git a/opendaylight/md-sal/samples/l2switch/model/pom.xml b/opendaylight/md-sal/samples/l2switch/model/pom.xml new file mode 100644 index 0000000000..d0ef2e0c65 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/model/pom.xml @@ -0,0 +1,97 @@ + + 4.0.0 + + sal-samples + org.opendaylight.controller.samples + 1.1-SNAPSHOT + ../.. + + org.opendaylight.controller.samples.l2switch.md + l2switch-model + bundle + + + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + org.opendaylight.yangtools.yang.binding.annotations, * + ${project.basedir}/META-INF + + + + + org.opendaylight.yangtools + yang-maven-plugin + ${yangtools.version} + + + + generate-sources + + + src/main/yang + + + + org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl + + + target/generated-sources/sal + + + + org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl + target/site/models + + + org.opendaylight.yangtools.yang.wadl.generator.maven.WadlGenerator + target/site/models + + + true + + + + + + org.opendaylight.yangtools + maven-sal-api-gen-plugin + ${yangtools.version} + jar + + + org.opendaylight.yangtools + yang-binding + ${yangtools.version} + jar + + + + + + + + + + org.opendaylight.yangtools + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.yangtools.model + ietf-yang-types + + + org.opendaylight.controller.model + model-inventory + + + diff --git a/opendaylight/md-sal/samples/l2switch/model/src/main/yang/l2-address-tracker.yang b/opendaylight/md-sal/samples/l2switch/model/src/main/yang/l2-address-tracker.yang new file mode 100644 index 0000000000..d694c6883d --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/model/src/main/yang/l2-address-tracker.yang @@ -0,0 +1,45 @@ +module l2-address-tracker { + yang-version 1; + namespace "urn:opendaylight:l2-address-tracker"; + prefix l2-address-tracker; + + import ietf-yang-types { + prefix yang; + revision-date 2010-09-24; + } + import opendaylight-inventory { + prefix inv; + revision-date 2013-08-19; + } + + organization "Cisco Systems Inc"; + contact + "Alex Fan "; + description + "YANG version of the L2 Address Tracker Data Model"; + + revision 2014-04-02 { + description + "L2 Address Tracker module draft."; + } + + grouping l2-address { + leaf mac { + type yang:mac-address; + mandatory true; + description + "the mac address of the host."; + } + leaf node-connector-ref { + type inv:node-connector-ref; + } + } + + container l2-addresses { + config false; + list l2-address { + key "mac"; + uses l2-address; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/samples/l2switch/pom.xml b/opendaylight/md-sal/samples/l2switch/pom.xml new file mode 100644 index 0000000000..2e2100b287 --- /dev/null +++ b/opendaylight/md-sal/samples/l2switch/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + + l2switch.aggregator + org.opendaylight.controller.samples.l2switch + 1.0.0-SNAPSHOT + pom + + + model + implementation + + + diff --git a/opendaylight/md-sal/samples/pom.xml b/opendaylight/md-sal/samples/pom.xml index 54810266a7..9f9d9d35c7 100644 --- a/opendaylight/md-sal/samples/pom.xml +++ b/opendaylight/md-sal/samples/pom.xml @@ -19,6 +19,7 @@ toaster toaster-consumer toaster-provider + l2switch diff --git a/opendaylight/md-sal/test/sal-rest-connector-it/pom.xml b/opendaylight/md-sal/test/sal-rest-connector-it/pom.xml index a9fc739456..f0a8584730 100644 --- a/opendaylight/md-sal/test/sal-rest-connector-it/pom.xml +++ b/opendaylight/md-sal/test/sal-rest-connector-it/pom.xml @@ -43,7 +43,7 @@ - org.eclipse.m2e @@ -605,7 +605,7 @@ jersey-core ${jersey.version} - com.sun.jersey @@ -667,7 +667,7 @@ org.opendaylight.controller - config-persister-file-adapter + config-persister-file-xml-adapter ${config.version} diff --git a/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java b/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java index 8400bc1835..4a43e0cf82 100644 --- a/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java +++ b/opendaylight/md-sal/test/sal-rest-connector-it/src/test/java/org/opendaylight/controller/test/restconf/it/ServiceProviderController.java @@ -75,9 +75,9 @@ public class ServiceProviderController { InstanceIdentifier path = InstanceIdentifier.builder(InventoryUtils.INVENTORY_PATH) .nodeWithKey(InventoryUtils.INVENTORY_NODE, InventoryUtils.INVENTORY_ID, "foo").toInstance(); - + InstanceIdentifier mountPointPath = path; - + /** We retrive a mountpoint **/ MountProvisionInstance mountPoint = mountService.getMountPoint(mountPointPath); CompositeNode data = mountPoint.readOperationalData(InstanceIdentifier.builder().node(CONFIG_MODULES) @@ -215,7 +215,7 @@ public class ServiceProviderController { mavenBundle(ODL, "yang-jmx-generator").versionAsInProject(), mavenBundle(ODL, "logback-config").versionAsInProject(), mavenBundle(ODL, "config-persister-api").versionAsInProject(), - // mavenBundle(ODL,"config-persister-file-adapter").versionAsInProject(), + // mavenBundle(ODL,"config-persister-file-xml-adapter").versionAsInProject(), mavenBundle(ODL, "protocol-framework").versionAsInProject(), mavenBundle(ODL, "netconf-api").versionAsInProject(), mavenBundle(ODL, "netconf-impl").versionAsInProject(), diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java index c1cad4a8dd..31a4f08036 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java @@ -37,12 +37,12 @@ import java.util.ListIterator; netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter netconf.config.persister.1.properties.fileStorage=configuration/initial/ - netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter + netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter netconf.config.persister.2.readonly=true - netconf.config.persister.2.properties.fileStorage=configuration/current/controller.config.1.txt + netconf.config.persister.2.properties.fileStorage=configuration/current/controller.config.1.xml - netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.FileStorageAdapter - netconf.config.persister.3.properties.fileStorage=configuration/current/controller.config.2.txt + netconf.config.persister.3.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter + netconf.config.persister.3.properties.fileStorage=configuration/current/controller.config.2.xml netconf.config.persister.3.properties.numberOfBackups=3 diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java index 677d0dff8c..4ca9690211 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java @@ -8,33 +8,13 @@ package org.opendaylight.controller.netconf.it; -import static java.util.Collections.emptyList; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import io.netty.channel.ChannelFuture; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import javax.management.ObjectName; -import javax.xml.parsers.ParserConfigurationException; - import junit.framework.Assert; - +import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -42,7 +22,6 @@ import org.junit.Test; import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver; import org.opendaylight.controller.config.spi.ModuleFactory; import org.opendaylight.controller.config.util.ConfigTransactionJMXClient; -import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException; import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory; import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory; import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean; @@ -52,6 +31,7 @@ import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.client.NetconfClient; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl; +import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException; import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher; import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl; @@ -72,17 +52,34 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; -import ch.ethz.ssh2.Connection; -import ch.ethz.ssh2.Session; +import javax.management.ObjectName; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.management.ManagementFactory; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import static java.util.Collections.emptyList; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; public class NetconfITTest extends AbstractNetconfConfigTest { // TODO refactor, pull common code up to AbstractNetconfITTest - private static final Logger logger = LoggerFactory.getLogger(NetconfITTest.class); + private static final Logger logger = LoggerFactory.getLogger(NetconfITTest.class); private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023); private static final InetSocketAddress sshAddress = new InetSocketAddress("127.0.0.1", 10830); @@ -90,7 +87,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { private static final String PASSWORD = "netconf"; private NetconfMessage getConfig, getConfigCandidate, editConfig, - closeSession, startExi, stopExi; + closeSession, startExi, stopExi; private DefaultCommitNotificationProducer commitNot; private NetconfServerDispatcher dispatch; @@ -113,7 +110,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { ChannelFuture s = dispatch.createServer(tcpAddress); s.await(); - clientDispatcher = new NetconfClientDispatcher( nettyThreadgroup, nettyThreadgroup, 5000); + clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000); } private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) { @@ -164,13 +161,14 @@ public class NetconfITTest extends AbstractNetconfConfigTest { yangDependencies.add(resourceAsStream); } } - assertEquals("Some yang files were not found",emptyList(), failedToFind); + assertEquals("Some yang files were not found", emptyList(), failedToFind); return yangDependencies; } protected List getModuleFactories() { return getModuleFactoriesS(); } + static List getModuleFactoriesS() { return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(), new NetconfTestImplModuleFactory()); @@ -193,7 +191,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { @Test public void testTwoSessions() throws Exception { - try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher)) { + try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher)) { try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 10000, clientDispatcher)) { } } @@ -258,7 +256,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { NetconfTestImplModuleMXBean proxy = configRegistryClient .newMXBeanProxy(impl, NetconfTestImplModuleMXBean.class); proxy.setTestingDep(dep); - proxy.setSimpleShort((short)0); + proxy.setSimpleShort((short) 0); transaction.commit(); @@ -400,12 +398,15 @@ public class NetconfITTest extends AbstractNetconfConfigTest { return netconfClient; } - private void startSSHServer() throws Exception{ + private void startSSHServer() throws Exception { logger.info("Creating SSH server"); - StubUserManager um = new StubUserManager(USERNAME,PASSWORD); - InputStream is = getClass().getResourceAsStream("/RSA.pk"); - AuthProvider ap = new AuthProvider(um, is); - Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress,ap)); + StubUserManager um = new StubUserManager(USERNAME, PASSWORD); + String pem; + try (InputStream is = getClass().getResourceAsStream("/RSA.pk")) { + pem = IOUtils.toString(is); + } + AuthProvider ap = new AuthProvider(um, pem); + Thread sshServerThread = new Thread(NetconfSSHServer.start(10830, tcpAddress, ap)); sshServerThread.setDaemon(true); sshServerThread.start(); logger.info("SSH server on"); @@ -415,11 +416,11 @@ public class NetconfITTest extends AbstractNetconfConfigTest { public void sshTest() throws Exception { startSSHServer(); logger.info("creating connection"); - Connection conn = new Connection(sshAddress.getHostName(),sshAddress.getPort()); + Connection conn = new Connection(sshAddress.getHostName(), sshAddress.getPort()); Assert.assertNotNull(conn); logger.info("connection created"); conn.connect(); - boolean isAuthenticated = conn.authenticateWithPassword(USERNAME,PASSWORD); + boolean isAuthenticated = conn.authenticateWithPassword(USERNAME, PASSWORD); assertTrue(isAuthenticated); logger.info("user authenticated"); final Session sess = conn.openSession(); @@ -427,10 +428,10 @@ public class NetconfITTest extends AbstractNetconfConfigTest { logger.info("user authenticated"); sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes()); - new Thread(){ + new Thread() { @Override - public void run(){ - while (true){ + public void run() { + while (true) { byte[] bytes = new byte[1024]; int c = 0; try { @@ -438,8 +439,10 @@ public class NetconfITTest extends AbstractNetconfConfigTest { } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } - logger.info("got data:"+bytes); - if (c == 0) break; + logger.info("got data:" + bytes); + if (c == 0) { + break; + } } } }.join(); diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml index 73e0a467c0..23a69b23fc 100644 --- a/opendaylight/netconf/netconf-ssh/pom.xml +++ b/opendaylight/netconf/netconf-ssh/pom.xml @@ -1,4 +1,5 @@ - + netconf-subsystem org.opendaylight.controller @@ -36,6 +37,19 @@ org.opendaylight.controller usermanager + + org.bouncycastle + bcprov-jdk15on + + + org.bouncycastle + bcpkix-jdk15on + + + org.opendaylight.yangtools + mockito-configuration + test + @@ -58,7 +72,8 @@ maven-bundle-plugin - org.opendaylight.controller.netconf.osgi.NetconfSSHActivator + org.opendaylight.controller.netconf.ssh.osgi.NetconfSSHActivator + com.google.common.base, ch.ethz.ssh2, @@ -71,6 +86,7 @@ org.osgi.framework, org.osgi.util.tracker, org.slf4j, + org.bouncycastle.openssl diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java index 3d5318073d..2d380482ba 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java @@ -7,64 +7,48 @@ */ package org.opendaylight.controller.netconf.ssh.authentication; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import org.apache.commons.io.IOUtils; import org.opendaylight.controller.sal.authorization.AuthResultEnum; import org.opendaylight.controller.sal.authorization.UserLevel; import org.opendaylight.controller.usermanager.IUserManager; import org.opendaylight.controller.usermanager.UserConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; public class AuthProvider implements AuthProviderInterface { - private static IUserManager um; + private static IUserManager um; //FIXME static mutable state, no locks private static final String DEFAULT_USER = "netconf"; private static final String DEFAULT_PASSWORD = "netconf"; - private String PEM; - - private static final Logger logger = LoggerFactory.getLogger(AuthProvider.class); - - public AuthProvider(IUserManager ium,InputStream privateKeyFileInputStream) throws Exception { + private final String pem; + public AuthProvider(IUserManager ium, String pemCertificate) throws Exception { + checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null"); AuthProvider.um = ium; - if (AuthProvider.um == null){ + if (AuthProvider.um == null) { throw new Exception("No usermanager service available."); } List roles = new ArrayList(1); roles.add(UserLevel.SYSTEMADMIN.toString()); - AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); - - try { - PEM = IOUtils.toString(privateKeyFileInputStream); - } catch (IOException e) { - logger.error("Error reading RSA key from file."); - throw new IllegalStateException("Error reading RSA key from file."); - } + AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); //FIXME hardcoded auth + pem = pemCertificate; } + @Override - public boolean authenticated(String username, String password) throws Exception { - if (AuthProvider.um == null){ + public boolean authenticated(String username, String password) throws Exception { + if (AuthProvider.um == null) { throw new Exception("No usermanager service available."); } - AuthResultEnum authResult = AuthProvider.um.authenticate(username,password); - if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){ - return true; - } - return false; + AuthResultEnum authResult = AuthProvider.um.authenticate(username, password); + return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC); } @Override - public char[] getPEMAsCharArray() throws Exception { - if (null == PEM){ - logger.error("Missing RSA key string."); - throw new Exception("Missing RSA key."); - } - return PEM.toCharArray(); + public char[] getPEMAsCharArray() { + return pem.toCharArray(); } @Override @@ -76,6 +60,4 @@ public class AuthProvider implements AuthProviderInterface { public void addUserManagerService(IUserManager userManagerService) { AuthProvider.um = userManagerService; } - - } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java new file mode 100644 index 0000000000..73886c4f46 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.ssh.authentication; + +import org.apache.commons.io.FileUtils; +import org.bouncycastle.openssl.PEMWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; + +public class PEMGenerator { + private static final Logger logger = LoggerFactory.getLogger(PEMGenerator.class); + private static final int KEY_SIZE = 4096; + + public static String generateTo(File privateFile) throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + SecureRandom sr = new SecureRandom(); + keyGen.initialize(KEY_SIZE, sr); + KeyPair keypair = keyGen.generateKeyPair(); + logger.info("Generating private key to {}", privateFile.getAbsolutePath()); + String privatePEM = toString(keypair.getPrivate()); + FileUtils.write(privateFile, privatePEM); + return privatePEM; + } + + private static String toString(Key key) throws IOException { + try (StringWriter writer = new StringWriter()) { + try (PEMWriter pemWriter = new PEMWriter(writer)) { + pemWriter.writeObject(key); + } + return writer.toString(); + } + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java similarity index 80% rename from opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java rename to opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java index 91624007d0..112bf67f69 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java @@ -5,13 +5,13 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.netconf.osgi; +package org.opendaylight.controller.netconf.ssh.osgi; import com.google.common.base.Optional; -import java.io.FileInputStream; -import java.net.InetSocketAddress; +import org.apache.commons.io.IOUtils; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.usermanager.IUserManager; import org.osgi.framework.BundleActivator; @@ -22,6 +22,11 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetSocketAddress; + /** * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket @@ -60,7 +65,7 @@ public class NetconfSSHActivator implements BundleActivator{ @Override public void removedService(ServiceReference reference, IUserManager service) { logger.trace("Removing service {} from netconf SSH. " + - "SSH won't authenticate users until IUserManeger service will be started.", reference); + "SSH won't authenticate users until IUserManager service will be started.", reference); removeUserManagerService(); } }; @@ -87,15 +92,27 @@ public class NetconfSSHActivator implements BundleActivator{ if (sshSocketAddressOptional.isPresent()){ String path = NetconfConfigUtil.getPrivateKeyPath(context); - path = path.replace("\\", "/"); + path = path.replace("\\", "/"); // FIXME: shouldn't this convert lines to system dependent path separator? if (path.equals("")){ throw new Exception("Missing netconf.ssh.pk.path key in configuration file."); } - try (FileInputStream fis = new FileInputStream(path)){ - AuthProvider authProvider = new AuthProvider(iUserManager,fis); - this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider); + File privateKeyFile = new File(path); + String privateKeyPEMString; + if (privateKeyFile.exists() == false) { + // generate & save to file + privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile); + } else { + // read from file + try (FileInputStream fis = new FileInputStream(path)) { + privateKeyPEMString = IOUtils.toString(fis); + } catch (IOException e) { + logger.error("Error reading RSA key from file '{}'", path); + throw new IllegalStateException("Error reading RSA key from file " + path); + } } + AuthProvider authProvider = new AuthProvider(iUserManager, privateKeyPEMString); + this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider); Thread serverThread = new Thread(server,"netconf SSH server thread"); serverThread.setDaemon(true); diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java index e07c7ed6ac..ce26910b97 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java @@ -8,16 +8,6 @@ package org.opendaylight.controller.netconf.ssh.threads; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import javax.annotation.concurrent.ThreadSafe; - -import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ch.ethz.ssh2.AuthenticationResult; import ch.ethz.ssh2.PtySettings; import ch.ethz.ssh2.ServerAuthenticationCallback; @@ -26,10 +16,18 @@ import ch.ethz.ssh2.ServerConnectionCallback; import ch.ethz.ssh2.ServerSession; import ch.ethz.ssh2.ServerSessionCallback; import ch.ethz.ssh2.SimpleServerSessionCallback; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.concurrent.ThreadSafe; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; @ThreadSafe public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback { - private static final Logger logger = LoggerFactory.getLogger(SocketThread.class); + private static final Logger logger = LoggerFactory.getLogger(SocketThread.class); private final Socket socket; private final InetSocketAddress clientAddress; @@ -43,11 +41,12 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser public static void start(Socket socket, InetSocketAddress clientAddress, long sessionId, - AuthProvider authProvider) throws IOException{ - Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId,authProvider)); + AuthProvider authProvider) throws IOException { + Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket, clientAddress, sessionId, authProvider)); netconf_ssh_socket_thread.setDaemon(true); netconf_ssh_socket_thread.start(); } + private SocketThread(Socket socket, InetSocketAddress clientAddress, long sessionId, @@ -56,7 +55,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser this.socket = socket; this.clientAddress = clientAddress; this.sessionId = sessionId; - this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/",""); + this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/", ""); this.authProvider = authProvider; } @@ -65,7 +64,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser public void run() { conn = new ServerConnection(socket); try { - conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf"); + conn.setPEMHostKey(authProvider.getPEMAsCharArray(), "netconf"); } catch (Exception e) { logger.debug("Server authentication setup failed."); } @@ -74,24 +73,21 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser try { conn.connect(); } catch (IOException e) { - logger.error("SocketThread error ",e); + logger.error("SocketThread error ", e); } } + @Override - public ServerSessionCallback acceptSession(final ServerSession session) - { - SimpleServerSessionCallback cb = new SimpleServerSessionCallback() - { + public ServerSessionCallback acceptSession(final ServerSession session) { + SimpleServerSessionCallback cb = new SimpleServerSessionCallback() { @Override - public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException - { - return new Runnable(){ + public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException { + return new Runnable() { @Override - public void run() - { - if (subsystem.equals("netconf")){ + public void run() { + if (subsystem.equals("netconf")) { IOThread netconf_ssh_input = null; - IOThread netconf_ssh_output = null; + IOThread netconf_ssh_output = null; try { String hostName = clientAddress.getHostName(); int portNumber = clientAddress.getPort(); @@ -99,13 +95,13 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser logger.trace("echo socket created"); logger.trace("starting netconf_ssh_input thread"); - netconf_ssh_input = new IOThread(echoSocket.getInputStream(),ss.getStdin(),"input_thread_"+sessionId,ss,conn); + netconf_ssh_input = new IOThread(echoSocket.getInputStream(), ss.getStdin(), "input_thread_" + sessionId, ss, conn); netconf_ssh_input.setDaemon(false); netconf_ssh_input.start(); logger.trace("starting netconf_ssh_output thread"); - final String customHeader = "["+currentUser+";"+remoteAddressWithPort+";ssh;;;;;;]\n"; - netconf_ssh_output = new IOThread(ss.getStdout(),echoSocket.getOutputStream(),"output_thread_"+sessionId,ss,conn,customHeader); + final String customHeader = "[" + currentUser + ";" + remoteAddressWithPort + ";ssh;;;;;;]\n"; + netconf_ssh_output = new IOThread(ss.getStdout(), echoSocket.getOutputStream(), "output_thread_" + sessionId, ss, conn, customHeader); netconf_ssh_output.setDaemon(false); netconf_ssh_output.start(); @@ -113,56 +109,57 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser logger.error("SSH bridge could not create echo socket: {}", t.getMessage(), t); try { - if (netconf_ssh_input!=null){ + if (netconf_ssh_input != null) { netconf_ssh_input.join(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); - logger.error("netconf_ssh_input join error ",e); + logger.error("netconf_ssh_input join error ", e); } try { - if (netconf_ssh_output!=null){ + if (netconf_ssh_output != null) { netconf_ssh_output.join(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); - logger.error("netconf_ssh_output join error ",e); + logger.error("netconf_ssh_output join error ", e); } } } else { - try { - ss.getStdin().write("wrong subsystem requested - closing connection".getBytes()); - ss.close(); - } catch (IOException e) { - logger.debug("excpetion while sending bad subsystem response",e); - } + String reason = "Only netconf subsystem is supported, requested:" + subsystem; + closeSession(ss, reason); } } }; } + + public void closeSession(ServerSession ss, String reason) { + logger.trace("Closing session - {}", reason); + try { + ss.getStdin().write(reason.getBytes()); + } catch (IOException e) { + logger.debug("Exception while closing session", e); + } + ss.close(); + } + @Override - public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException - { - return new Runnable() - { + public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException { + return new Runnable() { @Override - public void run() - { - //noop + public void run() { + closeSession(ss, "PTY request not supported"); } }; } @Override - public Runnable requestShell(final ServerSession ss) throws IOException - { - return new Runnable() - { + public Runnable requestShell(final ServerSession ss) throws IOException { + return new Runnable() { @Override - public void run() - { - //noop + public void run() { + closeSession(ss, "Shell not supported"); } }; } @@ -172,35 +169,31 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser } @Override - public String initAuthentication(ServerConnection sc) - { - logger.trace("Established connection with host {}",remoteAddressWithPort); - return "Established connection with host "+remoteAddressWithPort+"\r\n"; + public String initAuthentication(ServerConnection sc) { + logger.trace("Established connection with host {}", remoteAddressWithPort); + return "Established connection with host " + remoteAddressWithPort + "\r\n"; } @Override - public String[] getRemainingAuthMethods(ServerConnection sc) - { - return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD }; + public String[] getRemainingAuthMethods(ServerConnection sc) { + return new String[]{ServerAuthenticationCallback.METHOD_PASSWORD}; } @Override - public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) - { + public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) { return AuthenticationResult.FAILURE; } @Override - public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) - { + public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) { try { - if (authProvider.authenticated(username,password)){ + if (authProvider.authenticated(username, password)) { currentUser = username; - logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort); + logger.trace("user {}@{} authenticated", currentUser, remoteAddressWithPort); return AuthenticationResult.SUCCESS; } - } catch (Exception e){ + } catch (Exception e) { logger.warn("Authentication failed due to :" + e.getLocalizedMessage()); } return AuthenticationResult.FAILURE; @@ -208,8 +201,7 @@ public class SocketThread implements Runnable, ServerAuthenticationCallback, Ser @Override public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm, - byte[] publickey, byte[] signature) - { + byte[] publickey, byte[] signature) { return AuthenticationResult.FAILURE; } diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java new file mode 100644 index 0000000000..298f91ce8d --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; +import org.opendaylight.controller.usermanager.IUserManager; +import org.opendaylight.controller.usermanager.UserConfig; + +import java.io.File; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetSocketAddress; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; + +// This test is intended to be verified using ssh +@Ignore +public class KeyGeneratorTest { + + @Mock + private IUserManager iUserManager; + File tempFile; + + @Before + public void setUp() throws IOException { + MockitoAnnotations.initMocks(this); + doReturn(null).when(iUserManager).addLocalUser(any(UserConfig.class)); + tempFile = File.createTempFile("odltest", ".tmp"); + tempFile.deleteOnExit(); + } + + @After + public void tearDown() { + assertTrue(tempFile.delete()); + } + + @Test + public void test() throws Exception { + String pem = PEMGenerator.generateTo(tempFile); + + AuthProvider authProvider = new AuthProvider(iUserManager, pem); + InetSocketAddress inetSocketAddress = new InetSocketAddress(Inet4Address.getLoopbackAddress().getHostAddress(), 8383); + NetconfSSHServer server = NetconfSSHServer.start(1830, inetSocketAddress, authProvider); + + Thread serverThread = new Thread(server,"netconf SSH server thread"); + serverThread.start(); + serverThread.join(); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java index 91783ff755..663a0b4a82 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java @@ -8,15 +8,17 @@ package org.opendaylight.controller.netconf; import ch.ethz.ssh2.Connection; -import java.io.InputStream; -import java.net.InetSocketAddress; import junit.framework.Assert; +import org.apache.commons.io.IOUtils; import org.junit.Test; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.InputStream; +import java.net.InetSocketAddress; + public class SSHServerTest { @@ -34,8 +36,11 @@ public class SSHServerTest { public void startSSHServer() throws Exception{ logger.info("Creating SSH server"); StubUserManager um = new StubUserManager(USER,PASSWORD); - InputStream is = getClass().getResourceAsStream("/RSA.pk"); - AuthProvider ap = new AuthProvider(um, is); + String pem; + try(InputStream is = getClass().getResourceAsStream("/RSA.pk")) { + pem = IOUtils.toString(is); + } + AuthProvider ap = new AuthProvider(um, pem); NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress,ap); sshServerThread = new Thread(server); sshServerThread.setDaemon(true); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java index 2e3100f8b2..6b12a19992 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java @@ -8,8 +8,6 @@ package org.opendaylight.controller.netconf.util.mapping; -import java.util.Map; - import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; @@ -22,6 +20,8 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import java.util.Map; + public abstract class AbstractNetconfOperation implements NetconfOperation { private final String netconfSessionIdForReporting; @@ -118,8 +118,12 @@ public abstract class AbstractNetconfOperation implements NetconfOperation { @Override public String toString() { - final StringBuffer sb = new StringBuffer("AbstractConfigNetconfOperation{"); - sb.append("name=").append(getOperationName()); + final StringBuffer sb = new StringBuffer(getClass().getName()); + try { + sb.append("{name=").append(getOperationName()); + } catch(UnsupportedOperationException e) { + // no problem + } sb.append(", namespace=").append(getOperationNamespace()); sb.append(", session=").append(netconfSessionIdForReporting); sb.append('}'); diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index 586366f41a..2be64a8a98 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -153,11 +153,6 @@ config-persister-api ${config.version} - - org.opendaylight.controller - config-persister-file-adapter - ${config.version} - ${project.groupId} netconf-client diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java index 6582d8c021..ae84a72bba 100644 --- a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java @@ -1,5 +1,5 @@ /* - * Copyright IBM Corporation, 2013. All rights reserved. + * Copyright IBM Corporation and others, 2013. 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, @@ -64,6 +64,12 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable { @XmlElement (name="tenant_id") String tenantID; + @XmlElement (name="ipv6_address_mode", nillable=true) + String ipV6AddressMode; + + @XmlElement (name="ipv6_ra_mode", nillable=true) + String ipV6RaMode; + /* stores the OpenStackPorts associated with an instance * used to determine if that instance can be deleted. */ @@ -170,6 +176,14 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable { this.tenantID = tenantID; } + public String getIpV6AddressMode() { return ipV6AddressMode; } + + public void setIpV6AddressMode(String ipV6AddressMode) { this.ipV6AddressMode = ipV6AddressMode; } + + public String getIpV6RaMode() { return ipV6RaMode; } + + public void setIpV6RaMode(String ipV6RaMode) { this.ipV6RaMode = ipV6RaMode; } + /** * This method copies selected fields from the object and returns them * as a new object, suitable for marshaling. @@ -224,6 +238,12 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable { if (s.equals("tenant_id")) { ans.setTenantID(this.getTenantID()); } + if (s.equals("ipv6_address_mode")) { + ans.setIpV6AddressMode(this.getIpV6AddressMode()); + } + if (s.equals("ipv6_ra_mode")) { + ans.setIpV6RaMode(this.getIpV6RaMode()); + } } return ans; } @@ -444,6 +464,7 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable { + ", ipVersion=" + ipVersion + ", cidr=" + cidr + ", gatewayIP=" + gatewayIP + ", dnsNameservers=" + dnsNameservers + ", allocationPools=" + allocationPools + ", hostRoutes=" + hostRoutes + ", enableDHCP=" + enableDHCP + ", tenantID=" + tenantID + ", myPorts=" + myPorts - + ", gatewayIPAssigned=" + gatewayIPAssigned + "]"; + + ", gatewayIPAssigned=" + gatewayIPAssigned + ", ipv6AddressMode=" + ipV6AddressMode + + ", ipv6RaMode=" + ipV6RaMode + "]"; } } diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java index 224fcb5f01..f397eb3a97 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java @@ -1,5 +1,5 @@ /* - * Copyright IBM Corporation, 2013. All rights reserved. + * Copyright IBM Corporation and others, 2013. 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, @@ -87,6 +87,8 @@ public class NeutronSubnetsNorthbound { @QueryParam("gateway_ip") String queryGatewayIP, @QueryParam("enable_dhcp") String queryEnableDHCP, @QueryParam("tenant_id") String queryTenantID, + @QueryParam("ipv6_address_mode") String queryIpV6AddressMode, + @QueryParam("ipv6_ra_mode") String queryIpV6RaMode, // pagination @QueryParam("limit") String limit, @QueryParam("marker") String marker, @@ -110,7 +112,9 @@ public class NeutronSubnetsNorthbound { (queryCIDR == null || queryCIDR.equals(oSS.getCidr())) && (queryGatewayIP == null || queryGatewayIP.equals(oSS.getGatewayIP())) && (queryEnableDHCP == null || queryEnableDHCP.equals(oSS.getEnableDHCP())) && - (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) { + (queryTenantID == null || queryTenantID.equals(oSS.getTenantID())) && + (queryIpV6AddressMode == null || queryIpV6AddressMode.equals(oSS.getIpV6AddressMode())) && + (queryIpV6RaMode == null || queryIpV6RaMode.equals(oSS.getIpV6RaMode()))){ if (fields.size() > 0) { ans.add(extractFields(oSS,fields)); } else {