diff options
author | Jan Srnicek <jsrnicek@cisco.com> | 2017-07-11 17:56:04 +0200 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2017-07-14 12:20:49 +0000 |
commit | 7d22608d89d8ff8c32e72d15039f1f27b7d659a8 (patch) | |
tree | a189335e86d6321b3fd3ba708f3c686ef1b2c566 /infra/northbound | |
parent | b65cd89989ead7082089bf6f333e56b03f619606 (diff) |
HONEYCOMB-360 - Netconf Northbound Intefaces provider separation
- Netconf configuration included under netconf.json
Change-Id: If2a51d689e9bfc950da73f15a438277839140f8a
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'infra/northbound')
20 files changed, 1326 insertions, 0 deletions
diff --git a/infra/northbound/common/src/main/java/io/fd/honeycomb/northbound/NetconfConfiguration.java b/infra/northbound/common/src/main/java/io/fd/honeycomb/northbound/NetconfConfiguration.java new file mode 100644 index 000000000..98d64d017 --- /dev/null +++ b/infra/northbound/common/src/main/java/io/fd/honeycomb/northbound/NetconfConfiguration.java @@ -0,0 +1,69 @@ +/* + * 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.northbound; + +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 = "netconf", syntax = Syntax.JSON) +public class NetconfConfiguration { + + public boolean isNetconfTcpEnabled() { + return Boolean.valueOf(netconfTcp); + } + + public boolean isNetconfSshEnabled() { + return Boolean.valueOf(netconfSsh); + } + + public boolean isNetconfEnabled() { + return isNetconfTcpEnabled() || isNetconfSshEnabled(); + } + + @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"); + + @Override + public String toString() { + return "NetconfConfiguration{" + + "netconfNettyThreads=" + netconfNettyThreads + + ", netconfTcp='" + netconfTcp + '\'' + + ", netconfTcpBindingAddress=" + netconfTcpBindingAddress + + ", netconfTcpBindingPort=" + netconfTcpBindingPort + + ", netconfSsh='" + netconfSsh + '\'' + + ", netconfSshBindingAddress=" + netconfSshBindingAddress + + ", netconfSshBindingPort=" + netconfSshBindingPort + + ", netconfNotificationStreamName=" + netconfNotificationStreamName + + '}'; + } +} diff --git a/infra/northbound/netconf/asciidoc/Readme.adoc b/infra/northbound/netconf/asciidoc/Readme.adoc new file mode 100644 index 000000000..58ba105bf --- /dev/null +++ b/infra/northbound/netconf/asciidoc/Readme.adoc @@ -0,0 +1,3 @@ += netconf + +Overview of netconf
\ No newline at end of file diff --git a/infra/northbound/netconf/pom.xml b/infra/northbound/netconf/pom.xml new file mode 100644 index 000000000..562073b03 --- /dev/null +++ b/infra/northbound/netconf/pom.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>impl-parent</artifactId> + <groupId>io.fd.honeycomb.common</groupId> + <version>1.17.10-SNAPSHOT</version> + <relativePath>../../../common/impl-parent</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <groupId>io.fd.honeycomb.northbound</groupId> + <artifactId>netconf</artifactId> + <version>1.17.10-SNAPSHOT</version> + + <dependencies> + <!-- DI--> + <dependency> + <groupId>com.google.inject</groupId> + <artifactId>guice</artifactId> + </dependency> + <dependency> + <groupId>net.jmob</groupId> + <artifactId>guice.conf</artifactId> + </dependency> + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-multibindings</artifactId> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>binding-init</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>minimal-distribution-core</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- Northbound --> + <dependency> + <groupId>io.fd.honeycomb.northbound</groupId> + <artifactId>common</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- ODL-Netconf --> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>netconf-impl</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>netconf-ssh</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>mdsal-netconf-notification</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>mdsal-netconf-monitoring</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>mdsal-netconf-connector</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>ietf-netconf-monitoring</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.netconf</groupId> + <artifactId>ietf-netconf-monitoring-extension</artifactId> + </dependency> + + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>data-impl</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>honeycomb-impl</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>notification-impl</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + +</project>
\ No newline at end of file diff --git a/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/HoneycombNotification2NetconfProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/HoneycombNotification2NetconfProvider.java new file mode 100644 index 000000000..26ecf3a44 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.binding.init.ProviderTrait; +import io.fd.honeycomb.northbound.NetconfConfiguration; +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 NetconfConfiguration 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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfBindingBrokerProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfBindingBrokerProvider.java new file mode 100644 index 000000000..bafd4ea3c --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.binding.init.ProviderTrait; +import io.fd.honeycomb.impl.FakeBindingAwareBroker; +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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfConfigurationModule.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfConfigurationModule.java new file mode 100644 index 000000000..aba254b8a --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfConfigurationModule.java @@ -0,0 +1,29 @@ +/* + * 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.northbound.netconf; + +import com.google.inject.AbstractModule; +import io.fd.honeycomb.northbound.NetconfConfiguration; +import net.jmob.guice.conf.core.ConfigurationModule; + +public class NetconfConfigurationModule extends AbstractModule { + @Override + protected void configure() { + install(ConfigurationModule.create()); + requireBinding(NetconfConfiguration.class); + } +} diff --git a/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMdsalMapperProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMdsalMapperProvider.java new file mode 100644 index 000000000..4f0c00655 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.binding.init.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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfModule.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfModule.java new file mode 100644 index 000000000..01f57ed73 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfModule.java @@ -0,0 +1,145 @@ +/* + * 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.northbound.netconf; + +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.northbound.NetconfConfiguration; +import io.fd.honeycomb.northbound.NorthboundPrivateModule; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfModule extends NorthboundPrivateModule<NetconfConfiguration> { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfModule.class); + + 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"; + + public NetconfModule() { + super(new NetconfConfigurationModule(), NetconfConfiguration.class); + } + + @Override + protected void configure() { + if (!getConfiguration().isNetconfEnabled()) { + LOG.debug("Netconf disabled, skipping initialization"); + return; + } + install(getConfigurationModule()); + LOG.info("Starting NETCONF Northbound"); + // 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).asEagerSingleton(); + 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).asEagerSingleton(); + 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).asEagerSingleton(); + 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) + .asEagerSingleton(); + expose(NetconfTcpServerProvider.NetconfTcpServer.class); + bind(NetconfSshServerProvider.NetconfSshServer.class).toProvider(NetconfSshServerProvider.class) + .asEagerSingleton(); + return expose(NetconfSshServerProvider.NetconfSshServer.class); + } +} diff --git a/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMonitoringMapperProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMonitoringMapperProvider.java new file mode 100644 index 000000000..516df2aa5 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.binding.init.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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMonitoringReaderFactoryProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMonitoringReaderFactoryProvider.java new file mode 100644 index 000000000..50e0e8ac6 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.binding.init.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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMonitoringServiceProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfMonitoringServiceProvider.java new file mode 100644 index 000000000..1a99dd140 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.binding.init.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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfNotificationMapperProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfNotificationMapperProvider.java new file mode 100644 index 000000000..b2155fac1 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.binding.init.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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfNotificationsReaderFactoryProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfNotificationsReaderFactoryProvider.java new file mode 100644 index 000000000..4ed682ff0 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.binding.init.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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfReadersModule.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfReadersModule.java new file mode 100644 index 000000000..88d7a1c02 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfReadersModule.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.northbound.netconf; + +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import io.fd.honeycomb.northbound.NetconfConfiguration; +import io.fd.honeycomb.northbound.NorthboundAbstractModule; +import io.fd.honeycomb.translate.read.ReaderFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfReadersModule extends NorthboundAbstractModule<NetconfConfiguration> { + + private static final Logger LOG = LoggerFactory.getLogger(NetconfReadersModule.class); + + public NetconfReadersModule() { + super(new NetconfConfigurationModule(), NetconfConfiguration.class); + } + + protected void configure() { + if (!getConfiguration().isNetconfEnabled()) { + LOG.debug("NETCONF Northbound disabled, skipping readers initialization"); + return; + } + LOG.info("Initializing NETCONF Northbound readers"); + // 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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfServerDispatcherProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfServerDispatcherProvider.java new file mode 100644 index 000000000..b6c22bfd8 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.honeycomb.binding.init.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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfSshServerProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfSshServerProvider.java new file mode 100644 index 000000000..bc1d95c09 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfSshServerProvider.java @@ -0,0 +1,160 @@ +/* + * 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.northbound.netconf; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.inject.Inject; +import io.fd.honeycomb.binding.init.ProviderTrait; +import io.fd.honeycomb.infra.distro.InitializationException; +import io.fd.honeycomb.northbound.CredentialsConfiguration; +import io.fd.honeycomb.northbound.NetconfConfiguration; +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 NetconfConfiguration cfgAttributes; + @Inject + private NioEventLoopGroup nettyThreadgroup; + @Inject + private CredentialsConfiguration credentialsCfg; + + private ScheduledExecutorService pool = + Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().setNameFormat("netconf-ssh-%d").build()); + + @Override + protected NetconfSshServer create() { + if (!cfgAttributes.isNetconfSshEnabled()) { + LOG.info("NETCONF SSH disabled, skipping initialization"); + return null; + } + LOG.info("Starting NETCONF SSH"); + 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(credentialsCfg)); + 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 CredentialsConfiguration cfgAttributes; + + SimplelAuthProvider(final CredentialsConfiguration 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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfTcpServerProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfTcpServerProvider.java new file mode 100644 index 000000000..c1fc0a594 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NetconfTcpServerProvider.java @@ -0,0 +1,91 @@ +/* + * 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.northbound.netconf; + +import com.google.inject.Inject; +import io.fd.honeycomb.binding.init.ProviderTrait; +import io.fd.honeycomb.infra.distro.InitializationException; +import io.fd.honeycomb.northbound.NetconfConfiguration; +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 NetconfConfiguration cfgAttributes; + + @Override + protected NetconfTcpServer create() { + if (!cfgAttributes.isNetconfTcpEnabled()) { + LOG.debug("NETCONF TCP disabled, skipping initalization"); + return null; + } + LOG.info("Starting NETCONF TCP"); + 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/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NettyThreadGroupProvider.java b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/netconf/NettyThreadGroupProvider.java new file mode 100644 index 000000000..b36a31d83 --- /dev/null +++ b/infra/northbound/netconf/src/main/java/io/fd/honeycomb/northbound/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.northbound.netconf; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.inject.Inject; +import io.fd.honeycomb.binding.init.ProviderTrait; +import io.fd.honeycomb.northbound.NetconfConfiguration; +import io.netty.channel.nio.NioEventLoopGroup; + +public final class NettyThreadGroupProvider extends ProviderTrait<NioEventLoopGroup> { + + @Inject + private NetconfConfiguration cfgAttributes; + + @Override + protected NioEventLoopGroup create() { + return new NioEventLoopGroup(cfgAttributes.netconfNettyThreads, + new ThreadFactoryBuilder().setNameFormat("netconf-netty-%d").build()); + } +} diff --git a/infra/northbound/netconf/src/main/resources/honeycomb-minimal-resources/config/netconf.json b/infra/northbound/netconf/src/main/resources/honeycomb-minimal-resources/config/netconf.json new file mode 100644 index 000000000..459e90235 --- /dev/null +++ b/infra/northbound/netconf/src/main/resources/honeycomb-minimal-resources/config/netconf.json @@ -0,0 +1,10 @@ +{ + "netconf-netty-threads": 2, + "netconf-tcp-enabled": "true", + "netconf-tcp-binding-address": "127.0.0.1", + "netconf-tcp-binding-port": 7777, + "netconf-ssh-enabled": "true", + "netconf-ssh-binding-address": "0.0.0.0", + "netconf-ssh-binding-port": 2831, + "netconf-notification-stream-name": "honeycomb" +}
\ No newline at end of file diff --git a/infra/northbound/pom.xml b/infra/northbound/pom.xml index e234d4c28..3f6586ca3 100644 --- a/infra/northbound/pom.xml +++ b/infra/northbound/pom.xml @@ -34,6 +34,7 @@ <module>common</module> <module>bgp</module> <module>restconf</module> + <module>netconf</module> </modules> </project>
\ No newline at end of file |