diff options
author | Jan Srnicek <jsrnicek@cisco.com> | 2017-06-30 12:46:56 +0200 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2017-06-30 13:15:59 +0000 |
commit | 84ff4e5fd52c064437d0b6dcf43b2223f440b3c5 (patch) | |
tree | 45485b3df79423a42922c946724bdc55ee075067 /infra/minimal-distribution-core/src | |
parent | a90863760d1ae1a92520ce29841aec600d25a83a (diff) |
HONEYCOMB-373 - Separate minimal distribution modules to core module
Change-Id: I5278f91ea06f57c84b44a8458ef44469ebd0cf84
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'infra/minimal-distribution-core/src')
61 files changed, 3838 insertions, 0 deletions
diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/InitializationException.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/InitializationException.java new file mode 100644 index 000000000..0ed530cdb --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/InitializationException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro; + +/** + * Exception thrown when a failure occurs during HC initialization. + */ +public class InitializationException extends RuntimeException { + + public InitializationException(final String s) { + super(s); + } + + public InitializationException(final String s, final Throwable throwable) { + super(s, throwable); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/ProviderTrait.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/ProviderTrait.java new file mode 100644 index 000000000..a762a1618 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/ProviderTrait.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro; + +import com.google.inject.Provider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class ProviderTrait<T> implements Provider<T> { + + private static final Logger LOG = LoggerFactory.getLogger(ProviderTrait.class); + + @Override + public T get() { + LOG.info("Providing: {}", this); + T create = create(); + LOG.debug("Provided: {}", create); + return create; + } + + protected abstract T create(); +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActivationConfig.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActivationConfig.java new file mode 100644 index 000000000..a17f5d632 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActivationConfig.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.activation; + +import java.util.Optional; +import net.jmob.guice.conf.core.BindConfig; +import net.jmob.guice.conf.core.InjectConfig; +import net.jmob.guice.conf.core.Syntax; + +@BindConfig(value = "activation", syntax = Syntax.JSON) +public class ActivationConfig { + + @InjectConfig("modules-resource-path") + private String modulesResourcePath; + + @InjectConfig("yang-modules-index-path") + private String yangModulesIndexPath; + + public String getModulesResourcePath() { + return Optional.ofNullable(modulesResourcePath).orElse("../modules/"); + } + + public String getYangModulesIndexPath() { + return Optional.ofNullable(yangModulesIndexPath).orElse("../yang-mapping/"); + } + +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActivationModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActivationModule.java new file mode 100644 index 000000000..00f77a66d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActivationModule.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.activation; + +import com.google.inject.AbstractModule; +import net.jmob.guice.conf.core.ConfigurationModule; + +/** + * Module that provides set of modules activated by distribution and binds this set to be available + */ +public class ActivationModule extends AbstractModule { + @Override + protected void configure() { + install(ConfigurationModule.create()); + requestInjection(ActivationConfig.class); + bind(ActiveModules.class).toProvider(ActiveModuleProvider.class).asEagerSingleton(); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActiveModuleProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActiveModuleProvider.java new file mode 100644 index 000000000..d31024ce9 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActiveModuleProvider.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.activation; + +import com.google.common.collect.ImmutableList; +import com.google.inject.Inject; +import com.google.inject.Module; +import com.google.inject.Provider; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides list of active modules for distribution + */ +class ActiveModuleProvider implements Provider<ActiveModules> { + + private static final Logger LOG = LoggerFactory.getLogger(ActiveModuleProvider.class); + + @Inject + private ActivationConfig config; + + @Override + public ActiveModules get() { + return new ActiveModules(loadActiveModules( + aggregateResources(config.getModulesResourcePath(), Thread.currentThread().getContextClassLoader()))); + } + + /** + * Provide unique set of active modules filtered from provided resources + */ + static Set<Class<? extends Module>> loadActiveModules(@Nonnull final List<String> moduleNames) { + final ClassLoader classLoader = ActiveModuleProvider.class.getClassLoader(); + LOG.info("Reading active modules configuration for distribution"); + + // process resources to resource modules + return moduleNames.stream() + .map(String::trim) + .filter(trimmedLine -> trimmedLine.length() != 0) + // filter out commented lines + .filter(nonEmptyLine -> !nonEmptyLine.startsWith("//")) + // filter duplicates + .distinct() + .map(validLine -> moduleNameToClass(validLine, classLoader)) + // filters out classes that are not modules + .filter(ActiveModuleProvider::filterNonModules) + .collect(Collectors.toSet()); + } + + /** + * Aggregate all resources from provided relative path into a {@code List<String>} + */ + public static List<String> aggregateResources(final String relativePath, final ClassLoader classLoader) { + try { + return Collections.list(classLoader.getResources(relativePath)).stream() + .map(ActiveModuleProvider::toURI) + .flatMap(ActiveModuleProvider::folderToFile) + .map(File::toURI) + .map(Paths::get) + // readAll lines and add them to iteration + .flatMap(ActiveModuleProvider::readLines) + .collect(Collectors.toList()); + } catch (IOException e) { + LOG.error("Unable to load resources from relative path {}", relativePath, e); + throw new IllegalStateException("Unable to load resources from relative path " + relativePath, e); + } + } + + private static Stream<File> folderToFile(final URI uri) { + final File[] files = new File(uri).listFiles(File::isFile); + + return files != null + ? ImmutableList.copyOf(files).stream() + : Collections.<File>emptyList().stream(); + } + + private static boolean filterNonModules(final Class<?> clazz) { + final boolean isModule = Module.class.isAssignableFrom(clazz); + if (!isModule) { + LOG.warn("Class {} is provided in modules configuration, but is not a Module and will be ignored", clazz); + } + return isModule; + } + + /** + * Read lines from {@code Path} + */ + private static Stream<String> readLines(final Path path) { + try { + return Files.readAllLines(path).stream(); + } catch (IOException e) { + LOG.error("Unable to read content of {}", path, e); + throw new IllegalStateException("Unable to read content of " + path, e); + } + } + + /** + * Converts {@code URL} to {@code URI} + */ + private static URI toURI(final URL url) { + try { + return url.toURI(); + } catch (URISyntaxException e) { + LOG.error("Unable to convert {} to uri", url); + throw new IllegalStateException("Unable to convert " + url + " to uri", e); + } + } + + /** + * Loads class by provided name + */ + private static Class<? extends Module> moduleNameToClass(final String name, + final ClassLoader classLoader) { + try { + LOG.debug("Loading module class {}", name); + return (Class<? extends Module>) classLoader.loadClass(name); + } catch (ClassNotFoundException e) { + LOG.error("Unable to convert {} to class, make sure you've provided sources to classpath", name); + throw new IllegalStateException( + "Unable to convert " + name + " to class, make sure you've provided sources to classpath", e); + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActiveModules.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActiveModules.java new file mode 100644 index 000000000..f729f00b9 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/activation/ActiveModules.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.activation; + +import static java.lang.String.format; + +import com.google.inject.Module; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Provides static set of active activeModulesClasses + */ +public class ActiveModules { + private final Set<Class<? extends Module>> activeModulesClasses; + + public ActiveModules(final Set<Class<? extends Module>> activeModulesClasses) { + this.activeModulesClasses = activeModulesClasses; + } + + public Set<Class<? extends Module>> getActiveModulesClasses() { + return activeModulesClasses; + } + + public Set<? extends Module> createModuleInstances() { + return activeModulesClasses.stream() + .map(moduleClass -> { + try { + return moduleClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(format("Unable to create instance of module %s", moduleClass), + e); + } + }).collect(Collectors.toSet()); + } + + @Override + public String toString() { + return "ActiveModules{" + + "activeModulesClasses=" + activeModulesClasses + + '}'; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/CfgAttrsModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/CfgAttrsModule.java new file mode 100644 index 000000000..b22e88593 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/CfgAttrsModule.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.cfgattrs; + +import com.google.inject.AbstractModule; +import net.jmob.guice.conf.core.ConfigurationModule; + +/** + * Load the configuration from json into HoneycombConfiguration and make it available. + */ +public class CfgAttrsModule extends AbstractModule { + + protected void configure() { + install(ConfigurationModule.create()); + // Inject non-dependency configuration + requestInjection(HoneycombConfiguration.class); + } + +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/HoneycombConfiguration.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/HoneycombConfiguration.java new file mode 100644 index 000000000..cc46f7b8e --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/HoneycombConfiguration.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.cfgattrs; + +import com.google.common.base.MoreObjects; +import java.util.Optional; +import net.jmob.guice.conf.core.BindConfig; +import net.jmob.guice.conf.core.InjectConfig; +import net.jmob.guice.conf.core.Syntax; + +/** + * This is the Java equivalent for honeyconb.json file. We use guice-config library to load all the config attributes + * into this class instance. + * + * The BindConfig annotation tells that honeycomb.json file should be looked up on classpath root. + */ +@BindConfig(value = "honeycomb", syntax = Syntax.JSON) +public class HoneycombConfiguration { + + public boolean isRestconfHttpEnabled() { + return Boolean.valueOf(restconfHttp); + } + + public boolean isRestconfHttpsEnabled() { + return Boolean.valueOf(restconfHttps); + } + + public boolean isRestconfEnabled() { + return isRestconfHttpEnabled() || isRestconfHttpsEnabled(); + } + + public boolean isNetconfTcpEnabled() { + return Boolean.valueOf(netconfTcp); + } + + public boolean isNetconfSshEnabled() { + return Boolean.valueOf(netconfSsh); + } + + public boolean isNetconfEnabled() { + return isNetconfTcpEnabled() || isNetconfSshEnabled(); + } + + public boolean isConfigPersistenceEnabled() { + return persistConfig.isPresent() && Boolean.valueOf(persistConfig.get()); + } + public boolean isContextPersistenceEnabled() { + return persistContext.isPresent() && Boolean.valueOf(persistContext.get()); + } + + @InjectConfig("persist-context") + public Optional<String> persistContext = Optional.of("true"); + @InjectConfig("persisted-context-path") + public String peristContextPath; + @InjectConfig("persisted-context-restoration-type") + public String persistedContextRestorationType; + @InjectConfig("persist-config") + public Optional<String> persistConfig = Optional.of("true"); + @InjectConfig("persisted-config-path") + public String peristConfigPath; + @InjectConfig("persisted-config-restoration-type") + public String persistedConfigRestorationType; + @InjectConfig("notification-service-queue-depth") + public int notificationServiceQueueDepth; + @InjectConfig("restconf-http-enabled") + public String restconfHttp; + @InjectConfig("restconf-binding-address") + public Optional<String> restconfBindingAddress; + @InjectConfig("restconf-port") + public Optional<Integer> restconfPort; + @InjectConfig("restconf-https-enabled") + public String restconfHttps; + @InjectConfig("restconf-https-binding-address") + public Optional<String> restconfHttpsBindingAddress; + @InjectConfig("restconf-https-port") + public Optional<Integer> restconfHttpsPort; + /** + * Restconf keystore file name. It will be loaded from the classpath so must be present in one of the folders + * packaged with the distribution e.g. cert/ + */ + @InjectConfig("restconf-keystore") + public Optional<String> restconfKeystore = Optional.of("/honeycomb-keystore"); + @InjectConfig("restconf-keystore-password") + public Optional<String> keystorePassword; + @InjectConfig("restconf-keystore-manager-password") + public Optional<String> keystoreManagerPassword; + /** + * Restconf truststore file name. It will be loaded from the classpath so must be present in one of the folders + * packaged with the distribution e.g. cert/ + */ + @InjectConfig("restconf-truststore") + public Optional<String> restconfTruststore; + @InjectConfig("restconf-truststore-password") + public Optional<String> truststorePassword; + @InjectConfig("restconf-websocket-port") + public Optional<Integer> restconfWebsocketPort = Optional.of(7779); + @InjectConfig("restconf-root-path") + public Optional<String> restconfRootPath = Optional.of("/restconf"); + @InjectConfig("restconf-pool-max-size") + public Optional<Integer> restPoolMaxSize = Optional.of(10); + @InjectConfig("restconf-pool-min-size") + public Optional<Integer> restPoolMinSize = Optional.of(1); + @InjectConfig("restconf-acceptors-size") + public Optional<Integer> acceptorsSize = Optional.of(1); + @InjectConfig("restconf-selectors-size") + public Optional<Integer> selectorsSize = Optional.of(1); + @InjectConfig("restconf-https-acceptors-size") + public Optional<Integer> httpsAcceptorsSize = Optional.of(1); + @InjectConfig("restconf-https-selectors-size") + public Optional<Integer> httpsSelectorsSize = Optional.of(1); + @InjectConfig("netconf-netty-threads") + public Integer netconfNettyThreads; + @InjectConfig("netconf-tcp-enabled") + public String netconfTcp; + @InjectConfig("netconf-tcp-binding-address") + public Optional<String> netconfTcpBindingAddress; + @InjectConfig("netconf-tcp-binding-port") + public Optional<Integer> netconfTcpBindingPort; + @InjectConfig("netconf-ssh-enabled") + public String netconfSsh; + @InjectConfig("netconf-ssh-binding-address") + public Optional<String> netconfSshBindingAddress; + @InjectConfig("netconf-ssh-binding-port") + public Optional<Integer> netconfSshBindingPort; + @InjectConfig("netconf-notification-stream-name") + public Optional<String> netconfNotificationStreamName = Optional.of("honeycomb"); + @InjectConfig("username") + public String username; + @InjectConfig("password") + public String password; + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("peristContextPath", peristContextPath) + .add("persistedContextRestorationType", persistedContextRestorationType) + .add("peristConfigPath", peristConfigPath) + .add("persistedConfigRestorationType", persistedConfigRestorationType) + .add("notificationServiceQueueDepth", notificationServiceQueueDepth) + .add("restconfHttp", restconfHttp) + .add("restconfBindingAddress", restconfBindingAddress) + .add("restconfPort", restconfPort) + .add("restconfHttps", restconfHttps) + .add("restconfHttpsBindingAddress", restconfHttpsBindingAddress) + .add("restconfHttpsPort", restconfHttpsPort) + .add("restconfKeystore", restconfKeystore) + .add("keystorePassword", keystorePassword) + .add("keystoreManagerPassword", keystoreManagerPassword) + .add("restconfTruststore", restconfTruststore) + .add("truststorePassword", truststorePassword) + .add("restconfWebsocketPort", restconfWebsocketPort) + .add("restconfRootPath", restconfRootPath) + .add("restPoolMaxSize", restPoolMaxSize) + .add("restPoolMinSize", restPoolMinSize) + .add("acceptorsSize", acceptorsSize) + .add("selectorsSize", selectorsSize) + .add("httpsAcceptorsSize", httpsAcceptorsSize) + .add("httpsSelectorsSize", httpsSelectorsSize) + .add("netconfNettyThreads", netconfNettyThreads) + .add("netconfTcp", netconfTcp) + .add("netconfTcpBindingAddress", netconfTcpBindingAddress) + .add("netconfTcpBindingPort", netconfTcpBindingPort) + .add("netconfSsh", netconfSsh) + .add("netconfSshBindingAddress", netconfSshBindingAddress) + .add("netconfSshBindingPort", netconfSshBindingPort) + .add("netconfNotificationStreamName", netconfNotificationStreamName) + .add("username", username) + .add("password", password) + .toString(); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/BindingDataBrokerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/BindingDataBrokerProvider.java new file mode 100644 index 000000000..e17355143 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/BindingDataBrokerProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.impl.BindingDOMDataBrokerAdapter; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; + +public final class BindingDataBrokerProvider extends ProviderTrait<DataBroker> { + + @Inject + private DOMDataBroker domDataBroker; + @Inject + private BindingToNormalizedNodeCodec mappingService; + + @Override + protected BindingDOMDataBrokerAdapter create() { + return new BindingDOMDataBrokerAdapter(domDataBroker, mappingService); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/ConfigAndOperationalPipelineModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/ConfigAndOperationalPipelineModule.java new file mode 100644 index 000000000..55f9d989c --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/ConfigAndOperationalPipelineModule.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.PrivateModule; +import com.google.inject.Singleton; +import com.google.inject.name.Names; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.infra.distro.data.config.WriterRegistryProvider; +import io.fd.honeycomb.infra.distro.data.oper.ReadableDTDelegProvider; +import io.fd.honeycomb.infra.distro.data.oper.ReaderRegistryProvider; +import io.fd.honeycomb.infra.distro.initializer.PersistedFileInitializerProvider; +import io.fd.honeycomb.rpc.RpcRegistry; +import io.fd.honeycomb.rpc.RpcRegistryBuilder; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; + +public class ConfigAndOperationalPipelineModule extends PrivateModule { + + public static final String HONEYCOMB_CONFIG_NONPERSIST = "honeycomb-config-nopersist"; + public static final String HONEYCOMB_CONFIG = "honeycomb-config"; + + protected void configure() { + // Expose registries for plugin reader/writer factories + bind(WriterRegistry.class).toProvider(WriterRegistryProvider.class).in(Singleton.class); + expose(WriterRegistry.class); + bind(ReaderRegistry.class).toProvider(ReaderRegistryProvider.class).in(Singleton.class); + expose(ReaderRegistry.class); + + // Non persisting data tree for config + bind(DataTree.class).annotatedWith(Names.named(HONEYCOMB_CONFIG_NONPERSIST)) + .toProvider(DataTreeProvider.ConfigDataTreeProvider.class).in(Singleton.class); + expose(DataTree.class).annotatedWith(Names.named(HONEYCOMB_CONFIG_NONPERSIST)); + // Persisting data tree wrapper for config + bind(DataTree.class).annotatedWith(Names.named(HONEYCOMB_CONFIG)) + .toProvider(PersistingDataTreeProvider.ConfigPersistingDataTreeProvider.class).in(Singleton.class); + expose(DataTree.class).annotatedWith(Names.named(HONEYCOMB_CONFIG)); + + // Config Data Tree manager working on top of config data tree + writer registry + bind(ModifiableDataManager.class).toProvider(ModifiableDTDelegProvider.class).in(Singleton.class); + // Operational Data Tree manager working on top of reader registry + bind(ReadableDataManager.class).toProvider(ReadableDTDelegProvider.class).in(Singleton.class); + expose(ReadableDataManager.class); + + // DOMDataBroker wrapper on top of data tree managers + HoneycombDOMDataBrokerProvider domBrokerProvider = new HoneycombDOMDataBrokerProvider(); + bind(DOMDataBroker.class).toProvider(domBrokerProvider).in(Singleton.class); + + // BA version of data broker + bind(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_CONFIG)).toProvider(BindingDataBrokerProvider.class) + .in(Singleton.class); + expose(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_CONFIG)); + + // Create initializer to init persisted config data + bind(DataTreeInitializer.class).annotatedWith(Names.named(HONEYCOMB_CONFIG)) + .toProvider(PersistedFileInitializerProvider.PersistedConfigInitializerProvider.class) + .in(Singleton.class); + expose(DataTreeInitializer.class).annotatedWith(Names.named(HONEYCOMB_CONFIG)); + + configureNotifications(); + configureRpcs(); + } + + private void configureNotifications() { + // Create notification service + bind(DOMNotificationRouter.class).toProvider(DOMNotificationServiceProvider.class).in(Singleton.class); + expose(DOMNotificationRouter.class); + // Wrap notification service, data broker and schema service in a Broker MD-SAL API + bind(Broker.class).toProvider(HoneycombDOMBrokerProvider.class).in(Singleton.class); + expose(Broker.class); + } + + private void configureRpcs() { + // Create rpc service + bind(DOMRpcService.class).toProvider(HoneycombDOMRpcServiceProvider.class).in(Singleton.class); + expose(DOMRpcService.class); + + bind(RpcRegistryBuilder.class).toProvider(RpcRegistryBuilderProvider.class).in(Singleton.class); + expose(RpcRegistryBuilder.class); + + bind(RpcRegistry.class).toProvider(RpcRegistryProvider.class).in(Singleton.class); + expose(RpcRegistry.class); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DOMNotificationServiceProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DOMNotificationServiceProvider.java new file mode 100644 index 000000000..424393b8d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DOMNotificationServiceProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter; + +public final class DOMNotificationServiceProvider extends ProviderTrait<DOMNotificationRouter> { + + @Inject + private HoneycombConfiguration cfg; + + @Override + protected DOMNotificationRouter create() { + return DOMNotificationRouter.create(cfg.notificationServiceQueueDepth); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DataStoreProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DataStoreProvider.java new file mode 100644 index 000000000..5b09f21f8 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DataStoreProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory; +import org.opendaylight.controller.sal.core.api.model.SchemaService; + +public final class DataStoreProvider extends ProviderTrait<InMemoryDOMDataStore> { + + @Inject + private SchemaService schemaService; + private String name; + private LogicalDatastoreType type; + + public DataStoreProvider(final String name, + final LogicalDatastoreType type) { + this.name = name; + this.type = type; + } + + @Override + protected InMemoryDOMDataStore create() { + return InMemoryDOMDataStoreFactory.create(name, type, schemaService, false, null); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DataTreeProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DataTreeProvider.java new file mode 100644 index 000000000..c5fcc050a --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/DataTreeProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; + +public abstract class DataTreeProvider extends ProviderTrait<DataTree> { + + @Inject + private SchemaService schemaService; + @Inject + private HoneycombConfiguration config; + + public TipProducingDataTree create() { + TipProducingDataTree delegate = InMemoryDataTreeFactory.getInstance().create(getType()); + delegate.setSchemaContext(schemaService.getGlobalContext()); + return delegate; + } + + public abstract TreeType getType(); + + public static class ConfigDataTreeProvider extends DataTreeProvider { + public TreeType getType() { + return TreeType.CONFIGURATION; + } + + } + + public static class ContextDataTreeProvider extends DataTreeProvider { + public TreeType getType() { + return TreeType.OPERATIONAL; + } + + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMBrokerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMBrokerProvider.java new file mode 100644 index 000000000..dd34c6c6f --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMBrokerProvider.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.impl.NorthboundFacadeHoneycombDOMBroker; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.model.SchemaService; + +public final class HoneycombDOMBrokerProvider extends ProviderTrait<Broker> { + + @Inject + private DOMDataBroker domDataBroker; + @Inject + private SchemaService schemaService; + @Inject + private DOMNotificationRouter domNotificationService; + @Inject + private DOMRpcService domRpcService; + + @Override + protected NorthboundFacadeHoneycombDOMBroker create() { + return new NorthboundFacadeHoneycombDOMBroker(domDataBroker, schemaService, domNotificationService, + domRpcService); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMDataBrokerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMDataBrokerProvider.java new file mode 100644 index 000000000..92bbc512d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMDataBrokerProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.data.impl.DataBroker; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; + +public final class HoneycombDOMDataBrokerProvider extends ProviderTrait<DOMDataBroker> { + + @Inject + private ModifiableDataManager modDataManager; + @Inject(optional = true) + private ReadableDataManager readDataManager; + + protected DataBroker create() { + return readDataManager != null + ? DataBroker.create(modDataManager, readDataManager) + : DataBroker.create(modDataManager); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMRpcServiceProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMRpcServiceProvider.java new file mode 100644 index 000000000..0459b2fef --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombDOMRpcServiceProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.rpc.HoneycombDOMRpcService; +import io.fd.honeycomb.rpc.RpcRegistry; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.md.sal.dom.api.DOMRpcService; + +public final class HoneycombDOMRpcServiceProvider extends ProviderTrait<DOMRpcService> { + + @Inject + private BindingToNormalizedNodeCodec serializer; + + @Inject + private RpcRegistry rpcRegistry; + + @Override + protected DOMRpcService create() { + return new HoneycombDOMRpcService(serializer, rpcRegistry); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombNotificationManagerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombNotificationManagerProvider.java new file mode 100644 index 000000000..f2e81a9f6 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/HoneycombNotificationManagerProvider.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.notification.ManagedNotificationProducer; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.notification.impl.HoneycombNotificationCollector; +import io.fd.honeycomb.notification.impl.NotificationProducerRegistry; +import io.fd.honeycomb.notification.impl.NotificationProducerTracker; +import java.util.HashSet; +import java.util.Set; +import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationPublishServiceAdapter; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter; + +public final class HoneycombNotificationManagerProvider extends ProviderTrait<NotificationCollector> { + + @Inject + private DOMNotificationRouter notificationRouter; + @Inject(optional = true) + private Set<ManagedNotificationProducer> notificationProducers = new HashSet<>(); + @Inject + private BindingToNormalizedNodeCodec codec; + + @Override + protected HoneycombNotificationCollector create() { + // Create the registry to keep track of what'OPERATIONAL registered + NotificationProducerRegistry notificationProducerRegistry = + new NotificationProducerRegistry(Lists.newArrayList(notificationProducers)); + + // Create BA version of notification service (implementation is free from ODL) + BindingDOMNotificationPublishServiceAdapter bindingDOMNotificationPublishServiceAdapter = + new BindingDOMNotificationPublishServiceAdapter(codec, notificationRouter); + + // Create Collector on top of BA notification service and registry + HoneycombNotificationCollector honeycombNotificationCollector = + new HoneycombNotificationCollector(bindingDOMNotificationPublishServiceAdapter, + notificationProducerRegistry); + + // Create tracker, responsible for starting and stopping registered notification producers whenever necessary + NotificationProducerTracker notificationProducerTracker = + new NotificationProducerTracker(notificationProducerRegistry, honeycombNotificationCollector, + notificationRouter); + + // DOMNotificationService is already provided by DOMBroker injected into RESTCONF, however RESTCONF + // only supports data-change notification, nothing else. So currently (Beryllium-SR2) honeycomb notifications + // won't be available over RESTCONF. + + return honeycombNotificationCollector; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/InmemoryDOMDataBrokerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/InmemoryDOMDataBrokerProvider.java new file mode 100644 index 000000000..f5f04d2a7 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/InmemoryDOMDataBrokerProvider.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitDeadlockException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.broker.impl.SerializedDOMDataBroker; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; +import org.opendaylight.controller.sal.core.spi.data.DOMStore; +import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService; +import org.opendaylight.yangtools.util.concurrent.SpecialExecutors; + +public final class InmemoryDOMDataBrokerProvider extends ProviderTrait<DOMDataBroker> { + + public static final String CONFIG = "config"; + public static final String OPERATIONAL = "operational"; + + @Inject + @Named(InmemoryDOMDataBrokerProvider.CONFIG) + private InMemoryDOMDataStore cfgDataStore; + @Inject + @Named(InmemoryDOMDataBrokerProvider.OPERATIONAL) + private InMemoryDOMDataStore operDataStore; + + @Override + protected SerializedDOMDataBroker create() { + // This Databroker is dedicated for netconf metadata, not expected to be under heavy load + ExecutorService listenableFutureExecutor = + SpecialExecutors.newBlockingBoundedCachedThreadPool(1, 100, "commits"); + ExecutorService commitExecutor = SpecialExecutors.newBoundedSingleThreadExecutor(100, "WriteTxCommit"); + // TODO HONEYCOMB-164 try to provide more lightweight implementation of DataBroker + + Map<LogicalDatastoreType, DOMStore> map = new LinkedHashMap<>(); + map.put(LogicalDatastoreType.CONFIGURATION, cfgDataStore); + map.put(LogicalDatastoreType.OPERATIONAL, operDataStore); + + return new SerializedDOMDataBroker(map, new DeadlockDetectingListeningExecutorService(commitExecutor, + TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, listenableFutureExecutor)); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/ModifiableDTDelegProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/ModifiableDTDelegProvider.java new file mode 100644 index 000000000..b49381a27 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/ModifiableDTDelegProvider.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.impl.ModifiableDataTreeDelegator; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; + +public final class ModifiableDTDelegProvider extends ProviderTrait<ModifiableDataManager> { + + @Inject + private BindingToNormalizedNodeCodec serializer; + @Inject + private SchemaService schemaService; + @Inject + @Named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG) + private DataTree dataTree; + @Inject + private WriterRegistry registry; + @Inject + @Named(ContextPipelineModule.HONEYCOMB_CONTEXT) + private DataBroker contextBroker; + + @Override + protected ModifiableDataTreeDelegator create() { + return new ModifiableDataTreeDelegator(serializer, dataTree, schemaService.getGlobalContext(), + registry, contextBroker); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/PersistingDataTreeProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/PersistingDataTreeProvider.java new file mode 100644 index 000000000..e7a654c7d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/PersistingDataTreeProvider.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.data.impl.PersistingDataTreeAdapter; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule; +import java.nio.file.Paths; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; + +public abstract class PersistingDataTreeProvider extends ProviderTrait<DataTree> { + + @Inject + private SchemaService schemaService; + @Inject + protected HoneycombConfiguration config; + + public DataTree create() { + return isEnabled() + ? new PersistingDataTreeAdapter(getDelegate(), schemaService, Paths.get(getPath())) + : getDelegate(); + } + + public abstract String getPath(); + + public abstract TreeType getType(); + + public abstract DataTree getDelegate(); + + protected abstract boolean isEnabled(); + + public static final class ConfigPersistingDataTreeProvider extends PersistingDataTreeProvider { + + @Inject + @Named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG_NONPERSIST) + private DataTree delegate; + + public String getPath() { + return config.peristConfigPath; + } + + public TreeType getType() { + return TreeType.CONFIGURATION; + } + + public DataTree getDelegate() { + return delegate; + } + + @Override + protected boolean isEnabled() { + return config.isConfigPersistenceEnabled(); + } + } + + public static final class ContextPersistingDataTreeProvider extends PersistingDataTreeProvider { + + @Inject + @Named(ContextPipelineModule.HONEYCOMB_CONTEXT_NOPERSIST) + private DataTree delegate; + + public String getPath() { + return config.peristContextPath; + } + + public TreeType getType() { + return TreeType.OPERATIONAL; + } + + public DataTree getDelegate() { + return delegate; + } + + @Override + protected boolean isEnabled() { + return config.isContextPersistenceEnabled(); + } + + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/RpcRegistryBuilderProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/RpcRegistryBuilderProvider.java new file mode 100644 index 000000000..92d9ce951 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/RpcRegistryBuilderProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.rpc.RpcRegistryBuilder; +import io.fd.honeycomb.rpc.RpcService; +import java.util.HashSet; +import java.util.Set; + +public final class RpcRegistryBuilderProvider extends ProviderTrait<RpcRegistryBuilder> { + + @Inject(optional = true) + private Set<RpcService> rpcServices = new HashSet<>(); + + @Override + protected RpcRegistryBuilder create() { + final RpcRegistryBuilder builder = new RpcRegistryBuilder(); + rpcServices.stream() + .forEach(service -> builder.addService(service)); + return builder; + } + +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/RpcRegistryProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/RpcRegistryProvider.java new file mode 100644 index 000000000..4e09a9d2d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/RpcRegistryProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.rpc.RpcRegistry; +import io.fd.honeycomb.rpc.RpcRegistryBuilder; + +public final class RpcRegistryProvider extends ProviderTrait<RpcRegistry> { + + @Inject + private RpcRegistryBuilder builder; + + @Override + protected RpcRegistry create() { + return builder.build(); + } + +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/config/WriterRegistryProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/config/WriterRegistryProvider.java new file mode 100644 index 000000000..6546ba2d2 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/config/WriterRegistryProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data.config; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder; +import io.fd.honeycomb.translate.util.YangDAG; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.HashSet; +import java.util.Set; + +public final class WriterRegistryProvider extends ProviderTrait<WriterRegistry> { + + @Inject(optional = true) + private Set<WriterFactory> writerFactories = new HashSet<>(); + + @Override + protected WriterRegistry create() { + final FlatWriterRegistryBuilder builder = new FlatWriterRegistryBuilder(new YangDAG()); + writerFactories + .stream() + .forEach(it -> it.init(builder)); + return builder.build(); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/ContextPipelineModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/ContextPipelineModule.java new file mode 100644 index 000000000..b0ded35bd --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/ContextPipelineModule.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data.context; + +import com.google.inject.PrivateModule; +import com.google.inject.Singleton; +import com.google.inject.name.Names; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.infra.distro.data.BindingDataBrokerProvider; +import io.fd.honeycomb.infra.distro.data.DataTreeProvider; +import io.fd.honeycomb.infra.distro.data.PersistingDataTreeProvider; +import io.fd.honeycomb.infra.distro.initializer.PersistedFileInitializerProvider; +import io.fd.honeycomb.translate.MappingContext; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; + +public class ContextPipelineModule extends PrivateModule { + + public static final String HONEYCOMB_CONTEXT_NOPERSIST = "honeycomb-context-nopersist"; + public static final String HONEYCOMB_CONTEXT = "honeycomb-context"; + + @Override + protected void configure() { + // Non persisting data tree for context + DataTreeProvider.ContextDataTreeProvider noPersistDataTreeProvider = + new DataTreeProvider.ContextDataTreeProvider(); + bind(DataTree.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT_NOPERSIST)) + .toProvider(noPersistDataTreeProvider).in(Singleton.class); + expose(DataTree.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT_NOPERSIST)); + // Persisting data tree wrapper for context + PersistingDataTreeProvider.ContextPersistingDataTreeProvider dataTreeProvider = + new PersistingDataTreeProvider.ContextPersistingDataTreeProvider(); + bind(DataTree.class).toProvider(dataTreeProvider).in(Singleton.class); + + // Data Tree manager (without any delegation) on top of context data tree + bind(ModifiableDataManager.class).toProvider(ModifiableDTMgrProvider.class).in(Singleton.class); + + // DOMDataBroker interface on top of data tree manager + HoneycombContextDOMDataBrokerProvider domBrokerProvider = new HoneycombContextDOMDataBrokerProvider(); + bind(DOMDataBroker.class).toProvider(domBrokerProvider).in(Singleton.class); + + // BA version of data broker for context + bind(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT)).toProvider(BindingDataBrokerProvider.class) + .in(Singleton.class); + expose(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT)); + + // Create initializer to init persisted config data + bind(DataTreeInitializer.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT)) + .toProvider(PersistedFileInitializerProvider.PersistedContextInitializerProvider.class) + .in(Singleton.class); + expose(DataTreeInitializer.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT)); + + // Mapping context is just a small adapter on top of BA data broker to simplify CRUD of context data + bind(MappingContext.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT)) + .toProvider(RealtimeMappingContextProvider.class).in(Singleton.class); + expose(MappingContext.class).annotatedWith(Names.named(HONEYCOMB_CONTEXT)); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/HoneycombContextDOMDataBrokerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/HoneycombContextDOMDataBrokerProvider.java new file mode 100644 index 000000000..8e178203d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/HoneycombContextDOMDataBrokerProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data.context; + +import com.google.inject.Inject; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.impl.DataBroker; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; + +public final class HoneycombContextDOMDataBrokerProvider extends ProviderTrait<DOMDataBroker> { + + @Inject + private ModifiableDataManager modDataManager; + + public DataBroker create() { + return DataBroker.create(modDataManager); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/ModifiableDTMgrProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/ModifiableDTMgrProvider.java new file mode 100644 index 000000000..9da97a8e4 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/ModifiableDTMgrProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data.context; + +import com.google.inject.Inject; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.impl.ModifiableDataTreeManager; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; + +public final class ModifiableDTMgrProvider extends ProviderTrait<ModifiableDataManager> { + + @Inject + private DataTree dataTree; + + @Override + public ModifiableDataTreeManager create() { + return new ModifiableDataTreeManager(dataTree); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/RealtimeMappingContextProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/RealtimeMappingContextProvider.java new file mode 100644 index 000000000..cc1a8b1b8 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/context/RealtimeMappingContextProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data.context; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.util.RealtimeMappingContext; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; + +public final class RealtimeMappingContextProvider extends ProviderTrait<MappingContext> { + + @Inject + @Named(ContextPipelineModule.HONEYCOMB_CONTEXT) + private DataBroker contextDataBroker; + + @Override + public RealtimeMappingContext create() { + return new RealtimeMappingContext(contextDataBroker); + } + +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReadableDTDelegProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReadableDTDelegProvider.java new file mode 100644 index 000000000..caac736b5 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReadableDTDelegProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data.oper; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.data.ReadableDataManager; +import io.fd.honeycomb.data.impl.ReadableDataTreeDelegator; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.sal.core.api.model.SchemaService; + +public final class ReadableDTDelegProvider extends ProviderTrait<ReadableDataManager> { + + @Inject + private BindingToNormalizedNodeCodec serializer; + @Inject + private SchemaService schemaService; + @Inject + private ReaderRegistry registry; + @Inject + @Named(ContextPipelineModule.HONEYCOMB_CONTEXT) + private DataBroker contextBroker; + + @Override + protected ReadableDataTreeDelegator create() { + return new ReadableDataTreeDelegator(serializer, schemaService.getGlobalContext(), + registry, contextBroker); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReaderRegistryProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReaderRegistryProvider.java new file mode 100644 index 000000000..8f6bb0e6e --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReaderRegistryProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.data.oper; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import io.fd.honeycomb.translate.util.YangDAG; +import java.util.HashSet; +import java.util.Set; + +public final class ReaderRegistryProvider extends ProviderTrait<ReaderRegistry> { + + @Inject(optional = true) + private Set<ReaderFactory> readerFactories = new HashSet<>(); + + @Override + protected ReaderRegistry create() { + final CompositeReaderRegistryBuilder builder = new CompositeReaderRegistryBuilder(new YangDAG()); + readerFactories.stream() + .forEach(it -> it.init(builder)); + return builder.build(); + } + +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerPipelineModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerPipelineModule.java new file mode 100644 index 000000000..e0c38f38b --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerPipelineModule.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.initializer; + +import com.google.inject.PrivateModule; +import com.google.inject.Singleton; +import com.google.inject.name.Names; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.init.InitializerRegistry; +import io.fd.honeycomb.infra.distro.data.BindingDataBrokerProvider; +import io.fd.honeycomb.infra.distro.data.HoneycombDOMDataBrokerProvider; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; + +public final class InitializerPipelineModule extends PrivateModule { + + public static final String HONEYCOMB_INITIALIZER = "honeycomb-initializer"; + + protected void configure() { + // Create data tree manager on top of non-persisting config data tree + bind(ModifiableDataManager.class).toProvider(ModifiableDTDelegInitProvider.class).in(Singleton.class); + // Wrap as DOMDataBroker + bind(DOMDataBroker.class).toProvider(HoneycombDOMDataBrokerProvider.class).in(Singleton.class); + // Wrap as BA data broker + bind(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_INITIALIZER)) + .toProvider(BindingDataBrokerProvider.class).in(Singleton.class); + expose(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_INITIALIZER)); + + // Create initializer registry so that plugins can provide their initializers + bind(InitializerRegistry.class).annotatedWith(Names.named(HONEYCOMB_INITIALIZER)) + .toProvider(InitializerRegistryAdapterProvider.class).in(Singleton.class); + expose(InitializerRegistry.class).annotatedWith(Names.named(HONEYCOMB_INITIALIZER)); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerRegistryAdapter.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerRegistryAdapter.java new file mode 100644 index 000000000..85fb7772c --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerRegistryAdapter.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.initializer; + +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.data.init.InitializerRegistry; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.registry.InitRegistry; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class InitializerRegistryAdapter implements InitializerRegistry { + + private static final Logger LOG = LoggerFactory.getLogger(InitializerRegistryAdapter.class); + + private final DataTreeInitializer configInitializer; + private final DataTreeInitializer contextInitializer; + private final InitRegistry initRegistry; + private final DataBroker dataBroker; + private final MappingContext realtimeMappingContext; + + InitializerRegistryAdapter(final DataTreeInitializer configInitializer, + final DataTreeInitializer contextInitializer, + final InitRegistry initRegistry, + final DataBroker noopConfigDataBroker, + final MappingContext realtimeMappingContext) { + this.configInitializer = configInitializer; + this.contextInitializer = contextInitializer; + this.initRegistry = initRegistry; + this.dataBroker = noopConfigDataBroker; + this.realtimeMappingContext = realtimeMappingContext; + } + + @Override + public void initialize() throws DataTreeInitializer.InitializeException { + LOG.info("Config initialization started"); + + try { + // Initialize contexts first so that other initializers can find any relevant mapping before initializing + // configuration to what is already in VPP + contextInitializer.initialize(); + LOG.info("Persisted context restored successfully"); + // Initialize all registered initializers + initRegistry.initAll(dataBroker, new InitReadContext(realtimeMappingContext)); + LOG.info("Configuration initialized successfully"); + // Initialize stored configuration on top + configInitializer.initialize(); + LOG.info("Persisted configuration restored successfully"); + } catch (Exception e) { + LOG.warn("Failed to initialize config", e); + } + + LOG.info("Honeycomb initialized"); + } + + private static final class InitReadContext implements ReadContext { + + private final ModificationCache modificationCache; + private final MappingContext realtimeMappingContext; + + InitReadContext(final MappingContext realtimeMappingContext) { + modificationCache = new ModificationCache(); + this.realtimeMappingContext = realtimeMappingContext; + } + + @Nonnull + @Override + public ModificationCache getModificationCache() { + return modificationCache; + } + + @Nonnull + @Override + public MappingContext getMappingContext() { + return realtimeMappingContext; + } + + @Override + public void close() { + modificationCache.close(); + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerRegistryAdapterProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerRegistryAdapterProvider.java new file mode 100644 index 000000000..4f5185c40 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/InitializerRegistryAdapterProvider.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.initializer; + +import static io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG; +import static io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule.HONEYCOMB_CONTEXT; +import static io.fd.honeycomb.infra.distro.initializer.InitializerPipelineModule.HONEYCOMB_INITIALIZER; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.data.init.InitializerRegistry; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.read.registry.ReaderRegistry; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; + +public final class InitializerRegistryAdapterProvider extends ProviderTrait<InitializerRegistry> { + + @Inject + @Named(HONEYCOMB_CONTEXT) + private DataTreeInitializer contextInitializer; + @Inject + @Named(HONEYCOMB_CONFIG) + private DataTreeInitializer configInitializer; + @Inject + private ReaderRegistry initRegistry; + @Inject + @Named(HONEYCOMB_INITIALIZER) + private DataBroker noopConfigDataBroker; + @Inject + @Named(HONEYCOMB_CONTEXT) + private MappingContext realtimeMappingContext; + + @Override + protected InitializerRegistryAdapter create() { + return new InitializerRegistryAdapter(configInitializer, contextInitializer, initRegistry, + noopConfigDataBroker, realtimeMappingContext); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/ModifiableDTDelegInitProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/ModifiableDTDelegInitProvider.java new file mode 100644 index 000000000..3579ff11d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/ModifiableDTDelegInitProvider.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.initializer; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.data.ModifiableDataManager; +import io.fd.honeycomb.data.impl.ModifiableDataTreeDelegator; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.data.ConfigAndOperationalPipelineModule; +import io.fd.honeycomb.infra.distro.data.context.ContextPipelineModule; +import io.fd.honeycomb.translate.util.write.NoopWriterRegistry; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; + +public final class ModifiableDTDelegInitProvider extends ProviderTrait<ModifiableDataManager> { + + @Inject + private BindingToNormalizedNodeCodec serializer; + @Inject + @Named(ConfigAndOperationalPipelineModule.HONEYCOMB_CONFIG_NONPERSIST) + private DataTree dataTree; + @Inject + @Named(ContextPipelineModule.HONEYCOMB_CONTEXT) + private DataBroker contextBroker; + @Inject + private SchemaService schemaService; + + @Override + public ModifiableDataTreeDelegator create() { + return new ModifiableDataTreeDelegator(serializer, dataTree, schemaService.getGlobalContext(), + new NoopWriterRegistry(), contextBroker); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/PersistedFileInitializerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/PersistedFileInitializerProvider.java new file mode 100644 index 000000000..58d63cfb3 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/initializer/PersistedFileInitializerProvider.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.initializer; + +import com.google.inject.Inject; +import io.fd.honeycomb.data.init.RestoringInitializer; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import java.nio.file.Paths; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.sal.core.api.model.SchemaService; + +public abstract class PersistedFileInitializerProvider extends ProviderTrait<RestoringInitializer> { + + @Inject + private SchemaService schemaService; + @Inject + protected HoneycombConfiguration cfgAttributes; + @Inject + private DOMDataBroker domDataBroker; + + @Override + public RestoringInitializer create() { + return new RestoringInitializer(schemaService, Paths.get(getPersistPath()), domDataBroker, + RestoringInitializer.RestorationType.valueOf(getRestorationType()), getDataStoreType()); + } + + public abstract String getPersistPath(); + + public abstract LogicalDatastoreType getDataStoreType(); + + public abstract String getRestorationType(); + + public static class PersistedContextInitializerProvider extends PersistedFileInitializerProvider { + public String getPersistPath() { + return cfgAttributes.peristContextPath; + } + + public LogicalDatastoreType getDataStoreType() { + return LogicalDatastoreType.OPERATIONAL; + } + + public String getRestorationType() { + return cfgAttributes.persistedContextRestorationType; + } + + } + + public static class PersistedConfigInitializerProvider extends PersistedFileInitializerProvider { + public String getPersistPath() { + return cfgAttributes.peristConfigPath; + } + + public LogicalDatastoreType getDataStoreType() { + return LogicalDatastoreType.CONFIGURATION; + } + + public String getRestorationType() { + return cfgAttributes.persistedConfigRestorationType; + } + + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/HoneycombNotification2NetconfProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/HoneycombNotification2NetconfProvider.java new file mode 100644 index 000000000..f60366c7e --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/HoneycombNotification2NetconfProvider.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import io.fd.honeycomb.notification.NotificationCollector; +import io.fd.honeycomb.notification.impl.NotificationProducerRegistry; +import io.fd.honeycomb.notification.impl.TranslationUtil; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.dom.api.DOMNotification; +import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener; +import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.netconf.notifications.NetconfNotificationCollector; +import org.opendaylight.netconf.notifications.NotificationPublisherRegistration; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.streams.StreamBuilder; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class HoneycombNotification2NetconfProvider + extends ProviderTrait<HoneycombNotification2NetconfProvider.HoneycombNotification2Netconf> { + + private static final Logger LOG = LoggerFactory.getLogger(HoneycombNotification2NetconfProvider.class); + + @Inject + private DOMNotificationRouter notificationRouter; + @Inject + private SchemaService schemaService; + @Inject + private HoneycombConfiguration cfgAttributes; + @Inject + private NotificationCollector hcNotificationCollector; + @Inject + private NetconfNotificationCollector netconfNotificationCollector; + + @Override + protected HoneycombNotification2Netconf create() { + final StreamNameType streamType = new StreamNameType(cfgAttributes.netconfNotificationStreamName.get()); + + // Register as HONEYCOMB_NETCONF notification publisher under configured name + final NotificationPublisherRegistration netconfNotifReg = netconfNotificationCollector + .registerNotificationPublisher(new StreamBuilder().setName(streamType).setReplaySupport(false) + .setDescription(cfgAttributes.netconfNotificationStreamName.get()).build()); + + // Notification Translator, get notification from HC producers and put into HONEYCOMB_NETCONF notification collector + final DOMNotificationListener domNotificationListener = + new TranslatingNotificationListener(netconfNotifReg, streamType, schemaService); + + // NotificationManager is used to provide list of available notifications (which are all of the notifications registered) + // TODO HONEYCOMB-165 make available notifications configurable here so that any number of notification streams for netconf + // can be configured on top of a single notification manager + LOG.debug("Current notifications to be exposed over HONEYCOMB_NETCONF: {}", + hcNotificationCollector.getNotificationTypes()); + List<SchemaPath> currentNotificationSchemaPaths = hcNotificationCollector.getNotificationTypes().stream() + .map(notifType -> SchemaPath.create(true, NotificationProducerRegistry.getQName(notifType))) + .collect(Collectors.toList()); + + // Register as listener to HC'OPERATIONAL DOM notification service + // TODO HONEYCOMB-166 This should only be triggered when HONEYCOMB_NETCONF notifications are activated + // Because this way we actually start all notification producers + // final Collection<QName> notificationQNames = + ListenerRegistration<DOMNotificationListener> domNotifListenerReg = notificationRouter + .registerNotificationListener(domNotificationListener, currentNotificationSchemaPaths); + + LOG.info("Exposing HONEYCOMB_NETCONF notification stream: {}", streamType.getValue()); + return new HoneycombNotification2Netconf(domNotifListenerReg, netconfNotifReg); + } + + public static final class HoneycombNotification2Netconf { + private final ListenerRegistration<DOMNotificationListener> domNotifListenerReg; + private final NotificationPublisherRegistration netconfNotifReg; + + public HoneycombNotification2Netconf(final ListenerRegistration<DOMNotificationListener> domNotifListenerReg, + final NotificationPublisherRegistration netconfNotifReg) { + this.domNotifListenerReg = domNotifListenerReg; + this.netconfNotifReg = netconfNotifReg; + } + + public ListenerRegistration<DOMNotificationListener> getDomNotifListenerReg() { + return domNotifListenerReg; + } + + public NotificationPublisherRegistration getNetconfNotifReg() { + return netconfNotifReg; + } + } + + private static final class TranslatingNotificationListener implements DOMNotificationListener { + + private static final Logger LOG = LoggerFactory.getLogger(TranslatingNotificationListener.class); + + private final NotificationPublisherRegistration netconfNotifReg; + private final StreamNameType streamType; + private final SchemaService schemaService; + + TranslatingNotificationListener(final NotificationPublisherRegistration netconfNotifReg, + final StreamNameType streamType, final SchemaService schemaService) { + this.netconfNotifReg = netconfNotifReg; + this.streamType = streamType; + this.schemaService = schemaService; + } + + @Override + public void onNotification(@Nonnull final DOMNotification notif) { + LOG.debug("Propagating notification: {} into HONEYCOMB_NETCONF", notif.getType()); + netconfNotifReg.onNotification(streamType, TranslationUtil.notificationToXml(notif, schemaService.getGlobalContext())); + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfBindingBrokerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfBindingBrokerProvider.java new file mode 100644 index 000000000..3d06b8d27 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfBindingBrokerProvider.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.impl.FakeBindingAwareBroker; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; + +public final class NetconfBindingBrokerProvider extends ProviderTrait<BindingAwareBroker> { + + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF) + private DataBroker dataBroker; + + @Override + protected FakeBindingAwareBroker create() { + return new FakeBindingAwareBroker(dataBroker); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMdsalMapperProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMdsalMapperProvider.java new file mode 100644 index 000000000..9ede54f72 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMdsalMapperProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactoryListener; +import org.opendaylight.netconf.mdsal.connector.MdsalNetconfOperationServiceFactory; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; + +public final class NetconfMdsalMapperProvider extends ProviderTrait<NetconfOperationServiceFactory> { + + @Inject + private SchemaService schemaService; + @Inject + private NetconfOperationServiceFactoryListener aggregator; + @Inject + private ModuleInfoBackedContext moduleInfoBackedContext; + @Inject + private Broker domBroker; + + @Override + protected MdsalNetconfOperationServiceFactory create() { + MdsalNetconfOperationServiceFactory mdsalNetconfOperationServiceFactory = + new MdsalNetconfOperationServiceFactory(schemaService, moduleInfoBackedContext); + domBroker.registerConsumer(mdsalNetconfOperationServiceFactory); + aggregator.onAddNetconfOperationServiceFactory(mdsalNetconfOperationServiceFactory); + return mdsalNetconfOperationServiceFactory; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfModule.java new file mode 100644 index 000000000..f3fddf36b --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfModule.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import static io.fd.honeycomb.infra.distro.data.InmemoryDOMDataBrokerProvider.CONFIG; +import static io.fd.honeycomb.infra.distro.data.InmemoryDOMDataBrokerProvider.OPERATIONAL; + +import com.google.inject.PrivateModule; +import com.google.inject.Singleton; +import com.google.inject.binder.AnnotatedElementBuilder; +import com.google.inject.name.Names; +import io.fd.honeycomb.infra.distro.data.BindingDataBrokerProvider; +import io.fd.honeycomb.infra.distro.data.DataStoreProvider; +import io.fd.honeycomb.infra.distro.data.HoneycombNotificationManagerProvider; +import io.fd.honeycomb.infra.distro.data.InmemoryDOMDataBrokerProvider; +import io.fd.honeycomb.notification.NotificationCollector; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timer; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.netconf.api.NetconfServerDispatcher; +import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactoryListener; +import org.opendaylight.netconf.notifications.NetconfNotificationCollector; +import org.opendaylight.netconf.notifications.NetconfNotificationListener; +import org.opendaylight.netconf.notifications.NetconfNotificationRegistry; +import org.opendaylight.netconf.notifications.impl.NetconfNotificationManager; + +public class NetconfModule extends PrivateModule { + + public static final String HONEYCOMB_NETCONF = "honeycomb-netconf"; + public static final String HONEYCOMB_NETCONF_MAPPER_AGGR = "netconf-mapper-aggregator"; + public static final String HONEYCOMB_NETCONF_MAPPER_NOTIF = "netconf-mapper-notification"; + public static final String HONEYCOMB_NETCONF_MAPPER_CORE = "netconf-mapper-honeycomb"; + public static final String HONEYCOMB_NETCONF_MAPPER_OPER = "netconf-mapper-monitoring"; + + @Override + protected void configure() { + // Create inmemory data store for HONEYCOMB_NETCONF config metadata + bind(InMemoryDOMDataStore.class).annotatedWith(Names.named(InmemoryDOMDataBrokerProvider.CONFIG)) + .toProvider(new DataStoreProvider(InmemoryDOMDataBrokerProvider.CONFIG, LogicalDatastoreType.CONFIGURATION)) + .in(Singleton.class); + + // Create inmemory data store for HONEYCOMB_NETCONF operational metadata + bind(InMemoryDOMDataStore.class).annotatedWith(Names.named(InmemoryDOMDataBrokerProvider.OPERATIONAL)) + .toProvider(new DataStoreProvider(InmemoryDOMDataBrokerProvider.OPERATIONAL, LogicalDatastoreType.OPERATIONAL)) + .in(Singleton.class); + // Wrap datastores as DOMDataBroker + bind(DOMDataBroker.class).toProvider(InmemoryDOMDataBrokerProvider.class).in(Singleton.class); + + // Wrap DOMDataBroker as BA data broker + bind(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_NETCONF)).toProvider(BindingDataBrokerProvider.class) + .in(Singleton.class); + expose(DataBroker.class).annotatedWith(Names.named(HONEYCOMB_NETCONF)); + + // Wrap BA data broker as BindingAwareBroker (requied by HONEYCOMB_NETCONF) + bind(BindingAwareBroker.class).annotatedWith(Names.named(HONEYCOMB_NETCONF)) + .toProvider(NetconfBindingBrokerProvider.class).in(Singleton.class); + + // Create netconf operation service factory aggregator to aggregate different services + AggregatedNetconfOperationServiceFactory factory = new AggregatedNetconfOperationServiceFactory(); + bind(NetconfOperationServiceFactory.class).annotatedWith(Names.named(HONEYCOMB_NETCONF_MAPPER_AGGR)) + .toInstance(factory); + bind(NetconfOperationServiceFactoryListener.class).toInstance(factory); + + // Create netconf notification manager + NetconfNotificationManager manager = new NetconfNotificationManager(); + bind(NetconfNotificationCollector.class).toInstance(manager); + bind(NetconfNotificationRegistry.class).toInstance(manager); + bind(NetconfNotificationListener.class).toInstance(manager); + + // Netconf notification service factory + bind(NetconfOperationServiceFactory.class).annotatedWith(Names.named(HONEYCOMB_NETCONF_MAPPER_NOTIF)) + .toProvider(NetconfNotificationMapperProvider.class).in(Singleton.class); + expose(NetconfOperationServiceFactory.class).annotatedWith(Names.named(HONEYCOMB_NETCONF_MAPPER_NOTIF)); + + // Netconf core part - mapping between Honeycomb and Netconf + bind(NetconfOperationServiceFactory.class).annotatedWith(Names.named(HONEYCOMB_NETCONF_MAPPER_CORE)) + .toProvider(NetconfMdsalMapperProvider.class).in(Singleton.class); + expose(NetconfOperationServiceFactory.class).annotatedWith(Names.named(HONEYCOMB_NETCONF_MAPPER_CORE)); + + // Netconf monitoring service factory + bind(NetconfMonitoringService.class).toProvider(NetconfMonitoringServiceProvider.class).in(Singleton.class); + bind(NetconfOperationServiceFactory.class).annotatedWith(Names.named(HONEYCOMB_NETCONF_MAPPER_OPER)) + .toProvider(NetconfMonitoringMapperProvider.class).in(Singleton.class); + expose(NetconfOperationServiceFactory.class).annotatedWith(Names.named(HONEYCOMB_NETCONF_MAPPER_OPER)); + + // Create HC notification manager + HC2Netconf translator + bind(NotificationCollector.class).toProvider(HoneycombNotificationManagerProvider.class).in(Singleton.class); + bind(HoneycombNotification2NetconfProvider.HoneycombNotification2Netconf.class) + .toProvider(HoneycombNotification2NetconfProvider.class).in(Singleton.class); + expose(HoneycombNotification2NetconfProvider.HoneycombNotification2Netconf.class); + + configureServer(); + } + + /** + * Provide HONEYCOMB_NETCONF TCP and SSH servers. + */ + private AnnotatedElementBuilder configureServer() { + bind(NioEventLoopGroup.class).toProvider(NettyThreadGroupProvider.class).in(Singleton.class); + bind(Timer.class).toInstance(new HashedWheelTimer()); + bind(NetconfServerDispatcher.class).toProvider(NetconfServerDispatcherProvider.class).in(Singleton.class); + bind(NetconfTcpServerProvider.NetconfTcpServer.class).toProvider(NetconfTcpServerProvider.class) + .in(Singleton.class); + expose(NetconfTcpServerProvider.NetconfTcpServer.class); + bind(NetconfSshServerProvider.NetconfSshServer.class).toProvider(NetconfSshServerProvider.class) + .in(Singleton.class); + return expose(NetconfSshServerProvider.NetconfSshServer.class); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringMapperProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringMapperProvider.java new file mode 100644 index 000000000..f617ded44 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringMapperProvider.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import java.lang.reflect.Constructor; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.netconf.mapping.api.NetconfOperationService; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactoryListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public final class NetconfMonitoringMapperProvider extends ProviderTrait<NetconfOperationServiceFactory> { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfMonitoringMapperProvider.class); + + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF) + private BindingAwareBroker bindingAwareBroker; + @Inject + private NetconfOperationServiceFactoryListener aggregator; + @Inject + private NetconfMonitoringService monitoringService; + + @Override + protected NetconfOperationServiceFactory create() { + try { + final Class<?> monitoringWriterCls = Class.forName( + "org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.MonitoringToMdsalWriter"); + Constructor<?> declaredConstructor = + monitoringWriterCls.getDeclaredConstructor(NetconfMonitoringService.class); + declaredConstructor.setAccessible(true); + final BindingAwareProvider writer = (BindingAwareProvider) declaredConstructor.newInstance(monitoringService); + bindingAwareBroker.registerProvider(writer); + + final Class<?> moduleClass = Class.forName( + "org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.NetconfMdsalMonitoringMapperModule"); + final Class<?> monitoringMapperCls = Class.forName( + "org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.NetconfMdsalMonitoringMapperModule$MdsalMonitoringMapper"); + declaredConstructor = + monitoringMapperCls.getDeclaredConstructor(NetconfMonitoringService.class); + declaredConstructor.setAccessible(true); + final NetconfOperationService mdSalMonitoringMapper = + (NetconfOperationService) declaredConstructor.newInstance(monitoringService); + + final Class<?> monitoringMpperFactory = Class.forName( + "org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.NetconfMdsalMonitoringMapperModule$MdSalMonitoringMapperFactory"); + declaredConstructor = + monitoringMpperFactory.getDeclaredConstructor(NetconfOperationService.class, moduleClass, monitoringWriterCls); + declaredConstructor.setAccessible(true); + // The second argument is null, it should be the parent cfg-subsystem module class instance, that we dont have + // it's used only during close so dont close the factory using its close() method + final NetconfOperationServiceFactory mdSalMonitoringMapperFactory = + (NetconfOperationServiceFactory) declaredConstructor.newInstance(mdSalMonitoringMapper, null, writer); + aggregator.onAddNetconfOperationServiceFactory(mdSalMonitoringMapperFactory); + return mdSalMonitoringMapperFactory; + } catch (final ReflectiveOperationException e) { + final String msg = "Unable to instantiate operation service factory using reflection"; + LOG.error(msg, e); + throw new IllegalStateException(msg, e); + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringReaderFactoryProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringReaderFactoryProvider.java new file mode 100644 index 000000000..3a4c13697 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringReaderFactoryProvider.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.BindingBrokerReader; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfStateBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + +public final class NetconfMonitoringReaderFactoryProvider extends ProviderTrait<ReaderFactory> { + + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF) + private DataBroker netconfDataBroker; + + @Override + protected NetconfMonitoringReaderFactory create() { + return new NetconfMonitoringReaderFactory(netconfDataBroker); + } + + /** + * {@link io.fd.honeycomb.translate.read.ReaderFactory} initiating reader into NETCONF's dedicated data store. + * Making NETCONF operational data available over NETCONF/RESTCONF + */ + private static final class NetconfMonitoringReaderFactory implements ReaderFactory { + + private final DataBroker netconfMonitoringBindingBrokerDependency; + + NetconfMonitoringReaderFactory(final DataBroker netconfMonitoringBindingBrokerDependency) { + this.netconfMonitoringBindingBrokerDependency = netconfMonitoringBindingBrokerDependency; + } + + @Override + public void init(final ModifiableReaderRegistryBuilder registry) { + registry.add(new BindingBrokerReader<>(InstanceIdentifier.create(NetconfState.class), + netconfMonitoringBindingBrokerDependency, + LogicalDatastoreType.OPERATIONAL, NetconfStateBuilder.class)); + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringServiceProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringServiceProvider.java new file mode 100644 index 000000000..9858003f5 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfMonitoringServiceProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.netconf.impl.osgi.NetconfMonitoringServiceImpl; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; + + +public class NetconfMonitoringServiceProvider extends ProviderTrait<NetconfMonitoringService> { + + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF_MAPPER_AGGR) + private NetconfOperationServiceFactory aggregator; + + @Override + protected NetconfMonitoringServiceImpl create() { + return new NetconfMonitoringServiceImpl(aggregator); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfNotificationMapperProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfNotificationMapperProvider.java new file mode 100644 index 000000000..2554d026c --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfNotificationMapperProvider.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import java.lang.reflect.Constructor; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactoryListener; +import org.opendaylight.netconf.mdsal.notification.NetconfNotificationOperationServiceFactory; +import org.opendaylight.netconf.notifications.BaseNotificationPublisherRegistration; +import org.opendaylight.netconf.notifications.NetconfNotificationCollector; +import org.opendaylight.netconf.notifications.NetconfNotificationRegistry; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Capabilities; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class NetconfNotificationMapperProvider extends ProviderTrait<NetconfOperationServiceFactory> { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfNotificationMapperProvider.class); + + public static final InstanceIdentifier<Capabilities> capabilitiesIdentifier = + InstanceIdentifier.create(NetconfState.class).child(Capabilities.class).builder().build(); + @Inject + private NetconfNotificationCollector notificationCollector; + @Inject + private NetconfNotificationRegistry notificationRegistry; + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF) + private BindingAwareBroker bindingAwareBroker; + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF) + private DataBroker dataBroker; + @Inject + private NetconfOperationServiceFactoryListener aggregator; + + @Override + protected NetconfNotificationOperationServiceFactory create() { + try { + final Class<?> notificationWriter = Class.forName( + "org.opendaylight.controller.config.yang.netconf.mdsal.notification.NotificationToMdsalWriter"); + Constructor<?> declaredConstructor = + notificationWriter.getDeclaredConstructor(NetconfNotificationCollector.class); + declaredConstructor.setAccessible(true); + final BindingAwareProvider writer = + (BindingAwareProvider) declaredConstructor.newInstance(notificationCollector); + bindingAwareBroker.registerProvider(writer); + + final Class<?> notifPublisherCls = Class.forName( + "org.opendaylight.controller.config.yang.netconf.mdsal.notification.CapabilityChangeNotificationProducer"); + declaredConstructor = + notifPublisherCls.getDeclaredConstructor(BaseNotificationPublisherRegistration.class); + declaredConstructor.setAccessible(true); + final DataTreeChangeListener<Capabilities> publisher = + (DataTreeChangeListener<Capabilities>) declaredConstructor.newInstance( + notificationCollector.registerBaseNotificationPublisher()); + + ListenerRegistration<DataTreeChangeListener<Capabilities>> capabilityChangeListenerRegistration = dataBroker + .registerDataTreeChangeListener( + new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, capabilitiesIdentifier), + publisher); + NetconfNotificationOperationServiceFactory netconfNotificationOperationServiceFactory = + new NetconfNotificationOperationServiceFactory(notificationRegistry); + aggregator.onAddNetconfOperationServiceFactory(netconfNotificationOperationServiceFactory); + + return netconfNotificationOperationServiceFactory; + } catch (final ReflectiveOperationException e) { + final String msg = "Unable to instantiate notification mapper using reflection"; + LOG.error(msg, e); + throw new IllegalStateException(msg, e); + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfNotificationsReaderFactoryProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfNotificationsReaderFactoryProvider.java new file mode 100644 index 000000000..b699439b4 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfNotificationsReaderFactoryProvider.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.honeycomb.translate.util.read.BindingBrokerReader; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.Netconf; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.NetconfBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class NetconfNotificationsReaderFactoryProvider extends ProviderTrait<ReaderFactory> { + + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF) + private DataBroker netconfDataBroker; + + @Override + protected ReaderFactory create() { + return new NotificationReaderFactory(netconfDataBroker); + } + + private static final class NotificationReaderFactory implements ReaderFactory { + private final DataBroker netconfDataBroker; + + NotificationReaderFactory(final DataBroker netconfDataBroker) { + this.netconfDataBroker = netconfDataBroker; + } + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + registry.add(new BindingBrokerReader<>(InstanceIdentifier.create(Netconf.class), netconfDataBroker, + LogicalDatastoreType.OPERATIONAL, NetconfBuilder.class)); + } + + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfReadersModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfReadersModule.java new file mode 100644 index 000000000..cb45f5d6d --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfReadersModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import io.fd.honeycomb.translate.read.ReaderFactory; + +public class NetconfReadersModule extends AbstractModule { + + protected void configure() { + // This should be part of NetconfModule, but that one is Private and Multibinders + private BASE_MODULES + // do not work together, that's why there's a dedicated module here + // https://github.com/google/guice/issues/906 + final Multibinder<ReaderFactory> binder = Multibinder.newSetBinder(binder(), ReaderFactory.class); + binder.addBinding().toProvider(NetconfMonitoringReaderFactoryProvider.class).in(Singleton.class); + binder.addBinding().toProvider(NetconfNotificationsReaderFactoryProvider.class).in(Singleton.class); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfServerDispatcherProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfServerDispatcherProvider.java new file mode 100644 index 000000000..00c2d1617 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfServerDispatcherProvider.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.Timer; +import java.util.concurrent.TimeUnit; +import org.opendaylight.netconf.api.NetconfServerDispatcher; +import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService; +import org.opendaylight.netconf.impl.NetconfServerDispatcherImpl; +import org.opendaylight.netconf.impl.SessionIdProvider; +import org.opendaylight.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; + +public final class NetconfServerDispatcherProvider extends ProviderTrait<NetconfServerDispatcher> { + private static final long CONNECTION_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(20); + + @Inject + @Named(NetconfModule.HONEYCOMB_NETCONF_MAPPER_AGGR) + private NetconfOperationServiceFactory aggregator; + @Inject + private NetconfMonitoringService monitoringService; + @Inject + private Timer timer; + @Inject + private NioEventLoopGroup nettyThreadgroup; + + @Override + protected NetconfServerDispatcherImpl create() { + AggregatedNetconfOperationServiceFactory netconfOperationProvider = + new AggregatedNetconfOperationServiceFactory(); + netconfOperationProvider.onAddNetconfOperationServiceFactory(aggregator); + + NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = + new NetconfServerSessionNegotiatorFactory(timer, netconfOperationProvider, new SessionIdProvider(), + CONNECTION_TIMEOUT_MILLIS, monitoringService); + NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = + new NetconfServerDispatcherImpl.ServerChannelInitializer(serverNegotiatorFactory); + + return new NetconfServerDispatcherImpl(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup); + } + + private static final class NetconfServerSessionNegotiatorFactory extends + org.opendaylight.netconf.impl.NetconfServerSessionNegotiatorFactory { + + NetconfServerSessionNegotiatorFactory(final Timer timer, + final AggregatedNetconfOperationServiceFactory netconfOperationProvider, + final SessionIdProvider sessionIdProvider, + final long connectionTimeoutMillis, + final NetconfMonitoringService monitoringService) { + super(timer, netconfOperationProvider, sessionIdProvider, connectionTimeoutMillis, monitoringService, + org.opendaylight.netconf.impl.NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES); + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfSshServerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfSshServerProvider.java new file mode 100644 index 000000000..ba36a266b --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfSshServerProvider.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.InitializationException; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import io.netty.channel.ChannelFuture; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.concurrent.GenericFutureListener; +import io.netty.util.concurrent.GlobalEventExecutor; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; +import org.opendaylight.netconf.api.NetconfServerDispatcher; +import org.opendaylight.netconf.auth.AuthProvider; +import org.opendaylight.netconf.ssh.SshProxyServer; +import org.opendaylight.netconf.ssh.SshProxyServerConfigurationBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public final class NetconfSshServerProvider extends ProviderTrait<NetconfSshServerProvider.NetconfSshServer> { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfSshServerProvider.class); + + @Inject + private NetconfServerDispatcher dispatcher; + @Inject + private HoneycombConfiguration cfgAttributes; + @Inject + private NioEventLoopGroup nettyThreadgroup; + + private ScheduledExecutorService pool = + Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().setNameFormat("netconf-ssh-%d").build()); + + @Override + protected NetconfSshServer create() { + InetAddress sshBindingAddress = null; + try { + sshBindingAddress = InetAddress.getByName(cfgAttributes.netconfSshBindingAddress.get()); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Illegal binding address", e); + } + + final InetSocketAddress bindingAddress = + new InetSocketAddress(sshBindingAddress, cfgAttributes.netconfSshBindingPort.get()); + + LocalAddress localAddress = new LocalAddress(cfgAttributes.netconfSshBindingPort.toString()); + ChannelFuture localServer = dispatcher.createLocalServer(localAddress); + + final SshProxyServer sshProxyServer = new SshProxyServer(pool, nettyThreadgroup, GlobalEventExecutor.INSTANCE); + + final SshProxyServerConfigurationBuilder sshConfigBuilder = new SshProxyServerConfigurationBuilder(); + sshConfigBuilder.setBindingAddress(bindingAddress); + sshConfigBuilder.setLocalAddress(localAddress); + // Only simple authProvider checking ConfigAttributes, checking the config file + sshConfigBuilder.setAuthenticator(new SimplelAuthProvider(cfgAttributes)); + sshConfigBuilder.setIdleTimeout(Integer.MAX_VALUE); + sshConfigBuilder.setKeyPairProvider(new PEMGeneratorHostKeyProvider()); + + localServer.addListener(new SshServerBinder(sshProxyServer, sshConfigBuilder, bindingAddress)); + + return new NetconfSshServer(localServer, sshProxyServer); + } + + public static final class NetconfSshServer { + private ChannelFuture localServer; + private SshProxyServer sshProxyServer; + + NetconfSshServer(final ChannelFuture localServer, + final SshProxyServer sshProxyServer) { + this.localServer = localServer; + this.sshProxyServer = sshProxyServer; + } + + public Object getLocalServer() { + return localServer; + } + + public Object getSshProxyServer() { + return sshProxyServer; + } + } + + private static final class SimplelAuthProvider implements AuthProvider { + + private final HoneycombConfiguration cfgAttributes; + + SimplelAuthProvider(final HoneycombConfiguration cfgAttributes) { + this.cfgAttributes = cfgAttributes; + } + + @Override + public boolean authenticated(final String uname, final String passwd) { + return cfgAttributes.username.equals(uname) && cfgAttributes.password.equals(passwd); + } + } + + private static final class SshServerBinder implements GenericFutureListener<ChannelFuture> { + private final SshProxyServer sshProxyServer; + private final SshProxyServerConfigurationBuilder sshConfigBuilder; + private final InetSocketAddress bindingAddress; + + SshServerBinder(final SshProxyServer sshProxyServer, + final SshProxyServerConfigurationBuilder sshConfigBuilder, + final InetSocketAddress bindingAddress) { + this.sshProxyServer = sshProxyServer; + this.sshConfigBuilder = sshConfigBuilder; + this.bindingAddress = bindingAddress; + } + + @Override + public void operationComplete(final ChannelFuture future) { + if (future.isDone() && !future.isCancelled()) { + try { + sshProxyServer.bind(sshConfigBuilder.createSshProxyServerConfiguration()); + LOG.info("Netconf SSH endpoint started successfully at {}", bindingAddress); + } catch (final IOException e) { + throw new InitializationException("Unable to start SSH netconf server", e); + } + + } else { + LOG.warn("Unable to start SSH netconf server at {}", bindingAddress, future.cause()); + throw new InitializationException("Unable to start SSH netconf server", future.cause()); + } + + } + + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfTcpServerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfTcpServerProvider.java new file mode 100644 index 000000000..66b82eed9 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfTcpServerProvider.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.InitializationException; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import io.netty.channel.ChannelFuture; +import io.netty.util.concurrent.GenericFutureListener; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import org.opendaylight.netconf.api.NetconfServerDispatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class NetconfTcpServerProvider extends ProviderTrait<NetconfTcpServerProvider.NetconfTcpServer> { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfTcpServerProvider.class); + + @Inject + private NetconfServerDispatcher dispatcher; + @Inject + private HoneycombConfiguration cfgAttributes; + + @Override + protected NetconfTcpServer create() { + InetAddress name = null; + try { + name = InetAddress.getByName(cfgAttributes.netconfTcpBindingAddress.get()); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Illegal binding address", e); + } + + final InetSocketAddress unresolved = new InetSocketAddress(name, cfgAttributes.netconfTcpBindingPort.get()); + + ChannelFuture tcpServer = dispatcher.createServer(unresolved); + tcpServer.addListener(new TcpLoggingListener(unresolved)); + return new NetconfTcpServer(tcpServer); + } + + public static final class NetconfTcpServer { + private Object tcpServer; + + NetconfTcpServer(final ChannelFuture tcpServer) { + this.tcpServer = tcpServer; + } + + public Object getTcpServer() { + return tcpServer; + } + } + + private static final class TcpLoggingListener implements GenericFutureListener<ChannelFuture> { + private final InetSocketAddress unresolved; + + TcpLoggingListener(final InetSocketAddress unresolved) { + this.unresolved = unresolved; + } + + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isDone() && future.isSuccess()) { + LOG.info("Netconf TCP endpoint started successfully at {}", unresolved); + } else { + LOG.warn("Unable to start TCP netconf server at {}", unresolved, future.cause()); + throw new InitializationException("Unable to start TCP netconf server", future.cause()); + } + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NettyThreadGroupProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NettyThreadGroupProvider.java new file mode 100644 index 000000000..e14952bba --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/netconf/NettyThreadGroupProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.netconf; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import io.netty.channel.nio.NioEventLoopGroup; + +public final class NettyThreadGroupProvider extends ProviderTrait<NioEventLoopGroup> { + + @Inject + private HoneycombConfiguration cfgAttributes; + + @Override + protected NioEventLoopGroup create() { + return new NioEventLoopGroup(cfgAttributes.netconfNettyThreads, + new ThreadFactoryBuilder().setNameFormat("netconf-netty-%d").build()); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpConnectorProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpConnectorProvider.java new file mode 100644 index 000000000..f298df1d5 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpConnectorProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.restconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; + +final class HttpConnectorProvider extends ProviderTrait<ServerConnector> { + + @Inject + private HoneycombConfiguration cfg; + @Inject + private Server server; + + @Override + protected ServerConnector create() { + ServerConnector httpConnector = + new ServerConnector(server, cfg.acceptorsSize.get(), cfg.selectorsSize.get()); + httpConnector.setHost(cfg.restconfBindingAddress.get()); + httpConnector.setPort(cfg.restconfPort.get()); + server.addConnector(httpConnector); + return httpConnector; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpsConnectorProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpsConnectorProvider.java new file mode 100644 index 000000000..68c0fb5ac --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpsConnectorProvider.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.restconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import java.net.URL; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +final class HttpsConnectorProvider extends ProviderTrait<ServerConnector> { + + @Inject + private HoneycombConfiguration cfg; + @Inject + private Server server; + + @Override + protected ServerConnector create() { + // SSL Context Factory + // Based on: + // https://github.com/eclipse/jetty.project/blob/jetty-9.3.x/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java + // https://wiki.eclipse.org/Jetty/Howto/Configure_SSL#Loading_Keys_and_Certificates_via_PKCS12 + // Keystore created with: + // openssl genrsa -des3 -out honeycomb.key + // openssl req -new -x509 -key honeycomb.key -out honeycomb.crt + // openssl pkcs12 -inkey honeycomb.key -in honeycomb.crt -export -out honeycomb.pkcs12 + // keytool -importkeystore -srckeystore honeycomb.pkcs12 -srcstoretype PKCS12 -destkeystore honeycomb-keystore + SslContextFactory sslContextFactory = new SslContextFactory(); + URL keystoreURL = getClass().getResource(cfg.restconfKeystore.get()); + sslContextFactory.setKeyStorePath(keystoreURL.getPath()); + sslContextFactory.setKeyStorePassword(cfg.keystorePassword.get()); + sslContextFactory.setKeyManagerPassword((cfg.keystoreManagerPassword.get())); + URL truststoreURL = getClass().getResource(cfg.restconfTruststore.get()); + sslContextFactory.setTrustStorePath(truststoreURL.getPath()); + sslContextFactory.setTrustStorePassword((cfg.truststorePassword.get())); + // TODO HONEYCOMB-167 make this more configurable + sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + + // SSL Connector + ServerConnector sslConnector = + new ServerConnector(server, cfg.httpsAcceptorsSize.get(), cfg.httpsSelectorsSize.get(), + // The ssl connection factory delegates the real processing to http connection factory + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + // That's why http connection factory is also required here + // Order is IMPORTANT here + new HttpConnectionFactory() + ); + sslConnector.setHost(cfg.restconfHttpsBindingAddress.get()); + sslConnector.setPort(cfg.restconfHttpsPort.get()); + server.addConnector(sslConnector); + return sslConnector; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/JettyServerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/JettyServerProvider.java new file mode 100644 index 000000000..bc5fe8bc3 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/JettyServerProvider.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.restconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import java.net.URL; +import java.util.Collections; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.gzip.GzipHandler; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.security.Password; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.webapp.WebAppContext; + +final class JettyServerProvider extends ProviderTrait<Server> { + + private static final String REALM = "HCRealm"; + // Mime types to be compressed when requested + private static final String[] GZIP_MIME_TYPES = {"application/xml", + "xml", + "application/yang.data+xml", + "application/json", + "application/yang.data+json"}; + + @Inject + private HoneycombConfiguration cfg; + + @Override + protected Server create() { + Server server = new Server(new QueuedThreadPool(cfg.restPoolMaxSize.get(), cfg.restPoolMinSize.get())); + + // Load Realm for basic auth + HashLoginService service = new HashLoginService(REALM); + // Reusing the name as role + service.putUser(cfg.username, new Password(cfg.password), new String[]{cfg.username}); + server.addBean(service); + + final URL resource = getClass().getResource("/"); + WebAppContext webapp = new WebAppContext(resource.getPath(), cfg.restconfRootPath.get()); + + server.setHandler(getGzip(service, webapp)); + return server; + } + + private GzipHandler getGzip(final HashLoginService service, final WebAppContext webapp) { + final GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.setIncludedMimeTypes(GZIP_MIME_TYPES); + gzipHandler.setHandler(getBaseAuth(service, webapp)); + return gzipHandler; + } + + private ConstraintSecurityHandler getBaseAuth(HashLoginService service, WebAppContext webapp) { + Constraint constraint = new Constraint(); + constraint.setName("auth"); + constraint.setAuthenticate(true); + constraint.setRoles(new String[]{cfg.username}); + + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec("/*"); + mapping.setConstraint(constraint); + + ConstraintSecurityHandler security = new ConstraintSecurityHandler(); + security.setConstraintMappings(Collections.singletonList(mapping)); + security.setAuthenticator(new BasicAuthenticator()); + security.setLoginService(service); + + security.setHandler(webapp); + return security; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfModule.java new file mode 100644 index 000000000..7799d7fde --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfModule.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.restconf; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import com.google.inject.name.Names; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.opendaylight.netconf.sal.rest.api.RestConnector; + +public class RestconfModule extends AbstractModule { + + public static final String RESTCONF_HTTP = "restconf-http"; + public static final String RESTCONF_HTTPS = "restconf-https"; + + protected void configure() { + bind(Server.class).toProvider(JettyServerProvider.class).in(Singleton.class); + bind(ServerConnector.class).annotatedWith(Names.named(RESTCONF_HTTP)).toProvider(HttpConnectorProvider.class) + .in(Singleton.class); + bind(ServerConnector.class).annotatedWith(Names.named(RESTCONF_HTTPS)).toProvider(HttpsConnectorProvider.class) + .in(Singleton.class); + bind(RestConnector.class).toProvider(RestconfProvider.class).in(Singleton.class); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfProvider.java new file mode 100644 index 000000000..6664c7d33 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.restconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.netconf.sal.rest.api.RestConnector; +import org.opendaylight.netconf.sal.restconf.impl.RestconfProviderImpl; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; + +final class RestconfProvider extends ProviderTrait<RestConnector> { + + @Inject + private HoneycombConfiguration cfg; + @Inject + private Broker domBroker; + + @Override + protected RestconfProviderImpl create() { + RestconfProviderImpl instance = new RestconfProviderImpl(); + instance.setWebsocketPort(new PortNumber(cfg.restconfWebsocketPort.get())); + domBroker.registerProvider(instance); + return instance; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/ModuleInfoBackedCtxProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/ModuleInfoBackedCtxProvider.java new file mode 100644 index 000000000..e2d0fbfaa --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/ModuleInfoBackedCtxProvider.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + +import static io.fd.honeycomb.infra.distro.schema.YangModulesProvider.YangModules; + +import com.google.common.base.MoreObjects; +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import java.util.stream.Collectors; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class ModuleInfoBackedCtxProvider extends ProviderTrait<ModuleInfoBackedContext> { + private static final Logger LOG = LoggerFactory.getLogger(ModuleInfoBackedCtxProvider.class); + + // optional in sense that list of modules inside can be empty if none was found + @Inject + private YangModules moduleInfos; + + @Override + protected ModuleInfoBackedContext create() { + ModuleInfoBackedContext create = ModuleInfoBackedContext.create(); + create.addModuleInfos(moduleInfos.getYangBindings().stream() + .map(YangModelBindingProvider::getModuleInfo) + .collect(Collectors.toList())); + LOG.debug("ModuleInfoBackedContext created from {}", moduleInfos); + return create; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("writerFactories", moduleInfos).toString(); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/ResourceLoader.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/ResourceLoader.java new file mode 100644 index 000000000..c851dab1b --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/ResourceLoader.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.lang.String.format; + +import com.google.common.base.Charsets; +import com.google.common.base.Strings; +import com.google.common.io.Resources; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Collectors; +import org.apache.commons.io.IOUtils; + +interface ResourceLoader { + + default Set<String> loadResourceContentsOnPath(final String path) { + final URL folderUrl = getClass().getClassLoader().getResource(path); + checkNotNull(folderUrl, "Resources %s not found", path); + + if (ResourceLoaderIml.urlToUri(folderUrl).getScheme().equals("jar")) { + return ResourceLoaderIml.readFromJar(path, folderUrl); + } else { + return ResourceLoaderIml.readFromFolder(folderUrl); + } + + } + + final class ResourceLoaderIml { + + private static Set<String> readFromFolder(final URL folderUrl) { + final File folder = new File(folderUrl.getPath()); + final File[] files = checkNotNull(folder.listFiles(), "No files present on path %s", folderUrl); + return Arrays.stream(files) + .map(ResourceLoaderIml::fileToUrl) + .map(ResourceLoaderIml::urlToContentString) + .flatMap(content -> Arrays.stream(content.split(System.lineSeparator()))) + .filter(ResourceLoaderIml::filterNonEmpty) + .collect(Collectors.toSet()); + } + + private static Set<String> readFromJar(final String path, final URL url) { + final String uriString = urlToUri(url).toString(); + final String fileReference = extractJarFilePath(uriString); + try (JarFile jar = new JarFile(new File(fileReference))) { + return Collections.list(jar.entries()) + .stream() + .filter(jarEntry -> jarEntry.getName().contains(path)) + .map(jarEntry -> getJarEntryStream(jar, jarEntry)) + .map(ResourceLoaderIml::readJarEntryStream) + .flatMap(content -> Arrays.stream(content.split(System.lineSeparator()))) + .filter(ResourceLoaderIml::filterNonEmpty) + .collect(Collectors.toSet()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static String extractJarFilePath(final String uriString) { + return uriString.substring(0, uriString.indexOf("!")).replace("jar:file:", ""); + } + + private static boolean filterNonEmpty(final String line) { + return !Strings.isNullOrEmpty(line.trim()); + } + + private static String readJarEntryStream(final InputStream inputStream) { + try { + final String value = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + IOUtils.closeQuietly(inputStream); + return value; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static InputStream getJarEntryStream(final JarFile jar, final JarEntry jarEntry) { + try { + return jar.getInputStream(jarEntry); + } catch (IOException e) { + throw new IllegalStateException(format("Unable to get stream for entry %s | jar %s", jar, jarEntry)); + } + } + + private static URI urlToUri(final URL url) { + try { + return url.toURI(); + } catch (URISyntaxException e) { + throw new IllegalStateException(format("Unable to convert URL %s to URI", url)); + } + } + + private static String urlToContentString(final URL url) { + try { + return Resources.toString(url, Charsets.UTF_8); + } catch (IOException e) { + throw new IllegalArgumentException("Unable to read resource from: " + url, e); + } + } + + private static URL fileToUrl(final File file) { + try { + return file.toURI().toURL(); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SchemaModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SchemaModule.java new file mode 100644 index 000000000..0799a06f3 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SchemaModule.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; + +public class SchemaModule extends AbstractModule { + + protected void configure() { + bind(ModuleInfoBackedContext.class).toProvider(ModuleInfoBackedCtxProvider.class).in(Singleton.class); + bind(SchemaService.class).toProvider(SchemaServiceProvider.class).in(Singleton.class); + bind(BindingToNormalizedNodeCodec.class).toProvider(SerializerProvider.class).in(Singleton.class); + } + +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SchemaServiceProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SchemaServiceProvider.java new file mode 100644 index 000000000..eb3552c12 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SchemaServiceProvider.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; + +public final class SchemaServiceProvider extends ProviderTrait<SchemaService> { + + @Inject + private ModuleInfoBackedContext mibCtx; + + public StaticSchemaService create() { + return new StaticSchemaService(mibCtx.getSchemaContext()); + } + + /** + * Static schema context provider service. + */ + private static final class StaticSchemaService implements SchemaService { + private final SchemaContext schemaContext; + + StaticSchemaService(SchemaContext schemaContext) { + this.schemaContext = schemaContext; + } + + @Override + public void addModule(final Module module) { + throw new UnsupportedOperationException("Static service"); + } + + @Override + public void removeModule(final Module module) { + throw new UnsupportedOperationException("Static service"); + } + + @Override + public SchemaContext getSessionContext() { + return schemaContext; + } + + @Override + public SchemaContext getGlobalContext() { + return schemaContext; + } + + @Override + public ListenerRegistration<SchemaContextListener> registerSchemaContextListener( + final SchemaContextListener listener) { + listener.onGlobalContextUpdated(schemaContext); + return new ListenerRegistration<SchemaContextListener>() { + public void close() {} + + public SchemaContextListener getInstance() { + return listener; + } + + }; + } + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SerializerProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SerializerProvider.java new file mode 100644 index 000000000..2a1963c0a --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/SerializerProvider.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + +import com.google.inject.Inject; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import javassist.ClassPool; +import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; + +public class SerializerProvider extends ProviderTrait<BindingToNormalizedNodeCodec> { + + @Inject + private ModuleInfoBackedContext mibCtx; + + @Override + protected BindingToNormalizedNodeCodec create() { + final DataObjectSerializerGenerator serializerGenerator = + StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())); + BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(serializerGenerator); + BindingRuntimeContext ctx = BindingRuntimeContext.create(mibCtx, mibCtx.getSchemaContext()); + codecRegistry.onBindingRuntimeContextUpdated(ctx); + BindingToNormalizedNodeCodec codec = new BindingToNormalizedNodeCodec(mibCtx, codecRegistry); + codec.onGlobalContextUpdated(mibCtx.getSchemaContext()); + return codec; + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangBindingProviderModule.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangBindingProviderModule.java new file mode 100644 index 000000000..d705226bf --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangBindingProviderModule.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + +import com.google.inject.AbstractModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class YangBindingProviderModule extends AbstractModule { + private static final Logger LOG = LoggerFactory.getLogger(YangBindingProviderModule.class); + + protected void configure() { + LOG.info("Configuring YangBindingProviderModule"); + bind(YangModulesProvider.YangModules.class).toProvider(YangModulesProvider.class).asEagerSingleton(); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModuleMappingIndex.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModuleMappingIndex.java new file mode 100644 index 000000000..a483cfd9c --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModuleMappingIndex.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Stream; +import javax.annotation.Nonnull; + +/** + * Index from guice module to yang module providers + */ +class YangModuleMappingIndex implements ResourceLoader { + + private static final String G_MODULE_TOKEN = "GUICE_MODULE:"; + private static final String KEY_VALUE_SEPARATOR = "|"; + private static final String Y_MODULE_TOKEN = "YANG_MODULES:"; + private static final String Y_MODULE_SEPARATOR = ","; + + /** + * key - module class name + * value - yang module provider + */ + private final Multimap<String, String> index; + + YangModuleMappingIndex(final String indexPath) { + this.index = LinkedListMultimap.create(); + loadResourceContentsOnPath(indexPath) + .forEach(line -> { + final String moduleName = parseModuleName(line); + parseYangModules(line).forEach(yModuleProvider -> index.put(moduleName, yModuleProvider)); + }); + } + + Set<String> getByModuleName(@Nonnull final String moduleName) { + return ImmutableSet.copyOf(index.get(moduleName)); + } + + int applicationModulesCount() { + return index.keySet().size(); + } + + private static String parseModuleName(final String rawLine) { + return rawLine.substring(rawLine.indexOf(G_MODULE_TOKEN) + G_MODULE_TOKEN.length(), + rawLine.indexOf(KEY_VALUE_SEPARATOR)); + } + + private static Stream<String> parseYangModules(final String rawLine) { + return Arrays.stream(rawLine.substring(rawLine.indexOf(Y_MODULE_TOKEN) + Y_MODULE_TOKEN.length()) + .split(Y_MODULE_SEPARATOR)); + } +} diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModulesProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModulesProvider.java new file mode 100644 index 000000000..f6d8ea0c1 --- /dev/null +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModulesProvider.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.infra.distro.schema; + + +import static java.lang.String.format; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import com.google.inject.Inject; +import com.google.inject.Provider; +import io.fd.honeycomb.infra.distro.activation.ActivationConfig; +import io.fd.honeycomb.infra.distro.activation.ActiveModules; +import java.io.IOException; +import java.net.URL; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider; + +/** + * Loads active yang modules + * Relying on generate yang-module-index + */ +public class YangModulesProvider implements Provider<YangModulesProvider.YangModules> { + + @Inject + private ActiveModules activeModules; + + @Inject + private ActivationConfig config; + + @Override + public YangModules get() { + // no need to bind this, pretty big map and its needed just here + final YangModuleMappingIndex index = new YangModuleMappingIndex(config.getYangModulesIndexPath()); + + return new YangModules(activeModules.getActiveModulesClasses().stream() + .map(Class::getName) + .map(index::getByModuleName) + .flatMap(Collection::stream) + .map(YangModulesProvider::loadClass) + .map(aClass -> (Class<? extends YangModelBindingProvider>) aClass) + .collect(Collectors.toSet())); + } + + static class YangModules { + private final Set<Class<? extends YangModelBindingProvider>> yangBindings; + + YangModules(final Set<Class<? extends YangModelBindingProvider>> yangBindings) { + this.yangBindings = yangBindings; + } + + Set<YangModelBindingProvider> getYangBindings() { + return yangBindings.stream() + .map(providerClass -> { + try { + return providerClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(format("Unable to create instance of %s", providerClass), + e); + } + }).collect(Collectors.toSet()); + } + } + + private static Class<?> loadClass(@Nonnull final String className) { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Unable to load class: " + className, e); + } + } + + static String urlToString(@Nonnull final URL url) { + try { + return Resources.toString(url, Charsets.UTF_8); + } catch (IOException e) { + throw new IllegalArgumentException("Unable to read resource from: " + url, e); + } + } +} |