diff options
author | Maros Marsalek <mmarsale@cisco.com> | 2016-08-17 15:38:01 +0200 |
---|---|---|
committer | Maros Marsalek <mmarsale@cisco.com> | 2016-08-19 12:49:56 +0200 |
commit | 3341ac467cc08ac95f937945c7502ac4a019d805 (patch) | |
tree | 1b13df9f8709d123c6fe50a9fa21d3686554e65f /infra/minimal-distribution/src/main/java/io | |
parent | 672f0c90fdbf4b5dc60cbfaaaf262e16561fdb7a (diff) |
Make Restconf thread pools configurable
Change-Id: Ie03a1fde5181cfd8457e36d67afc2cc0c69c1e1d
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'infra/minimal-distribution/src/main/java/io')
10 files changed, 275 insertions, 133 deletions
diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java index 6c63c213d..278f0b104 100644 --- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/Main.java @@ -16,6 +16,7 @@ package io.fd.honeycomb.infra.distro; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.inject.ConfigurationException; import com.google.inject.CreationException; @@ -42,6 +43,8 @@ import io.fd.honeycomb.infra.distro.restconf.RestconfModule; import io.fd.honeycomb.infra.distro.schema.SchemaModule; import io.fd.honeycomb.infra.distro.schema.YangBindingProviderModule; import java.util.List; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; import org.opendaylight.netconf.sal.rest.api.RestConnector; import org.slf4j.Logger; @@ -70,6 +73,9 @@ public final class Main { init(BASE_MODULES); } + /** + * Initialize the Honeycomb infrastructure + all wired plugins. + */ public static Injector init(final List<? extends Module> modules) { try { LOG.info("Starting honeycomb"); @@ -82,26 +88,50 @@ public final class Main { .forEach(e -> LOG.trace("Component available under: {} is {}", e.getKey(), e.getValue())); final HoneycombConfiguration cfgAttributes = injector.getInstance(HoneycombConfiguration.class); - + Preconditions.checkArgument(cfgAttributes.isRestconfEnabled() || cfgAttributes.isNetconfEnabled(), + "At least one interface(Restconf|Netconf) has to be enabled for Honeycomb"); // Now get instances for all dependency roots - LOG.info("Starting RESTCONF"); - injector.getInstance(RestConnector.class); - - LOG.info("Starting NETCONF"); - injector.getInstance( - Key.get(NetconfOperationServiceFactory.class, Names.named("netconf-mapper-honeycomb"))); - injector.getInstance( - Key.get(NetconfOperationServiceFactory.class, Names.named("netconf-mapper-notification"))); - injector.getInstance( - Key.get(NetconfOperationServiceFactory.class, Names.named("netconf-mapper-monitoring"))); - - if (cfgAttributes.isNetconfTcpServerEnabled()) { - injector.getInstance(NetconfTcpServerProvider.NetconfTcpServer.class); + if (cfgAttributes.isRestconfEnabled()) { + LOG.info("Starting RESTCONF"); + final Server server = injector.getInstance(Server.class); + final RestConnector instance = injector.getInstance(RestConnector.class); + + if (cfgAttributes.isRestconfHttpEnabled()) { + injector.getInstance(Key.get(ServerConnector.class, Names.named("restconf-http"))); + } + if (cfgAttributes.isRestconfHttpsEnabled()) { + injector.getInstance(Key.get(ServerConnector.class, Names.named("restconf-https"))); + } + + try { + server.start(); + } catch (Exception e) { + LOG.error("Unable to start Restconf", e); + throw new RuntimeException("Unable to start Restconf", e); + } } - injector.getInstance(NetconfSshServerProvider.NetconfSshServer.class); - injector.getInstance(HoneycombNotification2NetconfProvider.HoneycombNotification2Netconf.class); + if (cfgAttributes.isNetconfEnabled()) { + LOG.info("Starting NETCONF"); + injector.getInstance( + Key.get(NetconfOperationServiceFactory.class, Names.named("netconf-mapper-honeycomb"))); + injector.getInstance( + Key.get(NetconfOperationServiceFactory.class, Names.named("netconf-mapper-notification"))); + injector.getInstance( + Key.get(NetconfOperationServiceFactory.class, Names.named("netconf-mapper-monitoring"))); + + if (cfgAttributes.isNetconfTcpEnabled()) { + LOG.info("Starting NETCONF TCP"); + injector.getInstance(NetconfTcpServerProvider.NetconfTcpServer.class); + } + + if (cfgAttributes.isNetconfSshEnabled()) { + LOG.info("Starting NETCONF SSH"); + injector.getInstance(NetconfSshServerProvider.NetconfSshServer.class); + } + injector.getInstance(HoneycombNotification2NetconfProvider.HoneycombNotification2Netconf.class); + } LOG.info("Honeycomb started successfully!"); diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/HoneycombConfiguration.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/HoneycombConfiguration.groovy index 422c84435..85708f11e 100644 --- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/HoneycombConfiguration.groovy +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/cfgattrs/HoneycombConfiguration.groovy @@ -41,37 +41,72 @@ class HoneycombConfiguration { int notificationServiceQueueDepth // RESTCONF + // HTTP + @InjectConfig("restconf-http-enabled") + String restconfHttp + @InjectConfig("restconf-binding-address") - String restconfBindingAddress + Optional<String> restconfBindingAddress @InjectConfig("restconf-port") - int restconfPort + Optional<Integer> restconfPort + // HTTPS + @InjectConfig("restconf-https-enabled") + String restconfHttps @InjectConfig("restconf-https-binding-address") - String restconfHttpsBindingAddress + Optional<String> restconfHttpsBindingAddress @InjectConfig("restconf-https-port") - int restconfHttpsPort + Optional<Integer> restconfHttpsPort + @InjectConfig("restconf-websocket-port") - int restconfWebsocketPort + Optional<Integer> restconfWebsocketPort = Optional.of(7779) + @InjectConfig("restconf-root-path") - String restconfRootPath + Optional<String> restconfRootPath = Optional.of("/restconf") + @InjectConfig("restconf-pool-max-size") + Optional<Integer> restPoolMaxSize = Optional.of(10) + @InjectConfig("restconf-pool-min-size") + Optional<Integer> restPoolMinSize = Optional.of(1) + + @InjectConfig("restconf-acceptors-size") + Optional<Integer> acceptorsSize = Optional.of(1) + @InjectConfig("restconf-selectors-size") + Optional<Integer> selectorsSize = Optional.of(1) + @InjectConfig("restconf-https-acceptors-size") + Optional<Integer> httpsAcceptorsSize = Optional.of(1) + @InjectConfig("restconf-https-selectors-size") + Optional<Integer> httpsSelectorsSize = Optional.of(1) + + // Booleans not supported + boolean isRestconfHttpEnabled() { Boolean.valueOf(restconfHttp) } + boolean isRestconfHttpsEnabled() { Boolean.valueOf(restconfHttps) } + boolean isRestconfEnabled() { isRestconfHttpEnabled() || isRestconfHttpsEnabled() } // NETCONF @InjectConfig("netconf-netty-threads") - Optional<Integer> netconfNettyThreads - // NETCONF TCP optional + Integer netconfNettyThreads + + // NETCONF TCP + @InjectConfig("netconf-tcp-enabled") + String netconfTcp @InjectConfig("netconf-tcp-binding-address") Optional<String> netconfTcpBindingAddress @InjectConfig("netconf-tcp-binding-port") Optional<Integer> netconfTcpBindingPort + // NETCONF SSH + @InjectConfig("netconf-ssh-enabled") + String netconfSsh @InjectConfig("netconf-ssh-binding-address") - String netconfSshBindingAddress + Optional<String> netconfSshBindingAddress @InjectConfig("netconf-ssh-binding-port") - Integer netconfSshBindingPort + Optional<Integer> netconfSshBindingPort @InjectConfig("netconf-notification-stream-name") - String netconfNotificationStreamName + Optional<String> netconfNotificationStreamName = Optional.of("honeycomb") - boolean isNetconfTcpServerEnabled() { netconfTcpBindingAddress.isPresent() && netconfTcpBindingPort.isPresent() } + boolean isNetconfTcpEnabled() { Boolean.valueOf(netconfTcp) } + boolean isNetconfSshEnabled() { Boolean.valueOf(netconfSsh) } + boolean isNetconfEnabled() { isNetconfTcpEnabled() || isNetconfSshEnabled() } @InjectConfig("username") String username diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/HoneycombNotification2NetconfProvider.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/HoneycombNotification2NetconfProvider.groovy index 7e4453ef1..f8c9aaae3 100644 --- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/HoneycombNotification2NetconfProvider.groovy +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/HoneycombNotification2NetconfProvider.groovy @@ -52,13 +52,13 @@ class HoneycombNotification2NetconfProvider extends ProviderTrait<HoneycombNotif @Override def create() { - def streamType = new StreamNameType(cfgAttributes.netconfNotificationStreamName); + def streamType = new StreamNameType(cfgAttributes.netconfNotificationStreamName.get()); // Register as NETCONF notification publisher under configured name def netconfNotifReg = netconfNotificationCollector.registerNotificationPublisher(new StreamBuilder() .setName(streamType) .setReplaySupport(false) - .setDescription(cfgAttributes.netconfNotificationStreamName).build()); + .setDescription(cfgAttributes.netconfNotificationStreamName.get()).build()); // Notification Translator, get notification from HC producers and put into NETCONF notification collector def domNotificationListener = { notif -> diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfSshServerProvider.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfSshServerProvider.groovy index bce4f261a..8b1b5bec2 100644 --- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfSshServerProvider.groovy +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NetconfSshServerProvider.groovy @@ -16,6 +16,7 @@ package io.fd.honeycomb.infra.distro.netconf +import com.google.common.util.concurrent.ThreadFactoryBuilder import com.google.inject.Inject import groovy.transform.ToString import groovy.util.logging.Slf4j @@ -48,12 +49,13 @@ class NetconfSshServerProvider extends ProviderTrait<NetconfSshServer> { NioEventLoopGroup nettyThreadgroup // TODO merge with other executors .. one of the brokers creates also 2 internal executors - private ScheduledExecutorService pool = Executors.newScheduledThreadPool(1) + private ScheduledExecutorService pool = + Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().setNameFormat("netconf-ssh-%d").build()) @Override def create() { - def name = InetAddress.getByName(cfgAttributes.netconfSshBindingAddress) - def bindingAddress = new InetSocketAddress(name, cfgAttributes.netconfSshBindingPort) + def name = InetAddress.getByName(cfgAttributes.netconfSshBindingAddress.get()) + def bindingAddress = new InetSocketAddress(name, cfgAttributes.netconfSshBindingPort.get()) def localAddress = new LocalAddress(cfgAttributes.netconfSshBindingPort.toString()) def localServer = dispatcher.createLocalServer(localAddress) diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NettyThreadGroupProvider.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NettyThreadGroupProvider.groovy index da5f3d5b2..bff8e3d8e 100644 --- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NettyThreadGroupProvider.groovy +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/netconf/NettyThreadGroupProvider.groovy @@ -16,13 +16,13 @@ package io.fd.honeycomb.infra.distro.netconf +import com.google.common.util.concurrent.ThreadFactoryBuilder import com.google.inject.Inject import groovy.transform.ToString import groovy.util.logging.Slf4j -import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration import io.fd.honeycomb.infra.distro.ProviderTrait +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration import io.netty.channel.nio.NioEventLoopGroup - /** * Mirror of org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModule */ @@ -35,8 +35,7 @@ class NettyThreadGroupProvider extends ProviderTrait<NioEventLoopGroup> { @Override def create() { - cfgAttributes.netconfNettyThreads.isPresent() ? - new NioEventLoopGroup(cfgAttributes.netconfNettyThreads.get()) : - new NioEventLoopGroup() + new NioEventLoopGroup(cfgAttributes.netconfNettyThreads, + new ThreadFactoryBuilder().setNameFormat("netconf-netty-%d").build()) } } diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpConnectorProvider.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpConnectorProvider.groovy new file mode 100644 index 000000000..0be4a3264 --- /dev/null +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpConnectorProvider.groovy @@ -0,0 +1,24 @@ +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 + +class HttpConnectorProvider extends ProviderTrait<ServerConnector> { + + @Inject + HoneycombConfiguration cfg + @Inject + Server server + + @Override + def create() { + def httpConnector = new ServerConnector(server, cfg.acceptorsSize.get(), cfg.selectorsSize.get()) + httpConnector.setHost(cfg.restconfBindingAddress.get()) + httpConnector.setPort(cfg.restconfPort.get()) + server.addConnector(httpConnector) + httpConnector + } +} diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpsConnectorProvider.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpsConnectorProvider.groovy new file mode 100644 index 000000000..6ce5a1555 --- /dev/null +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/HttpsConnectorProvider.groovy @@ -0,0 +1,58 @@ +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.http.HttpVersion +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 + +class HttpsConnectorProvider extends ProviderTrait<ServerConnector> { + + public static final String KEYSTORE_PASSWORD = "OBF:1v9s1unr1unn1vv51zlk1t331vg91x1b1vgl1t331zly1vu51uob1uo71v8u" + public static final String KEYSTORE_NAME = "/honeycomb-keystore" + + @Inject + HoneycombConfiguration cfg + @Inject + Server server + + @Override + def 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 + def sslContextFactory = new SslContextFactory() + def keystoreURL = getClass().getResource(KEYSTORE_NAME) + sslContextFactory.setKeyStorePath(keystoreURL.path) + sslContextFactory.setKeyStorePassword(KEYSTORE_PASSWORD) + sslContextFactory.setKeyManagerPassword(KEYSTORE_PASSWORD) + sslContextFactory.setTrustStorePath(keystoreURL.path) + sslContextFactory.setTrustStorePassword(KEYSTORE_PASSWORD) + 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 + def sslConnector = new ServerConnector(server, cfg.httpsAcceptorsSize.get(), cfg.httpsSelectorsSize.get(), + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString())) + sslConnector.setHost(cfg.restconfHttpsBindingAddress.get()) + sslConnector.setPort(cfg.restconfHttpsPort.get()) + server.addConnector(sslConnector) + return sslConnector + } +} diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/JettyServerProvider.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/JettyServerProvider.groovy new file mode 100644 index 000000000..ff6c300ea --- /dev/null +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/JettyServerProvider.groovy @@ -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.restconf + +import com.google.inject.Inject +import groovy.transform.ToString +import groovy.util.logging.Slf4j +import io.fd.honeycomb.infra.distro.ProviderTrait +import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration +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.util.security.Constraint +import org.eclipse.jetty.util.security.Password +import org.eclipse.jetty.util.thread.QueuedThreadPool +import org.eclipse.jetty.webapp.WebAppContext + +@Slf4j +@ToString +class JettyServerProvider extends ProviderTrait<Server> { + + public static final String REALM = "HCRealm" + + @Inject + HoneycombConfiguration cfg + + def create() { + def server = new Server(new QueuedThreadPool(cfg.restPoolMaxSize.get(), cfg.restPoolMinSize.get())) + + // Load Realm for basic auth + def service = new HashLoginService(REALM) + // Reusing the name as role + // TODO make this more configurable + service.putUser(cfg.username, new Password(cfg.password), cfg.username) + server.addBean(service) + + final URL resource = getClass().getResource("/") + WebAppContext webapp = new WebAppContext(resource.getPath(), cfg.restconfRootPath.get()) + + ConstraintSecurityHandler security = getBaseAuth(service, webapp) + server.setHandler(security) + + return server + } + + private ConstraintSecurityHandler getBaseAuth(HashLoginService service, WebAppContext webapp) { + ConstraintSecurityHandler security = new ConstraintSecurityHandler() + + Constraint constraint = new Constraint() + constraint.setName("auth") + constraint.setAuthenticate(true) + constraint.setRoles(cfg.username) + + ConstraintMapping mapping = new ConstraintMapping() + mapping.setPathSpec("/*") + mapping.setConstraint(constraint) + + security.setConstraintMappings(Collections.singletonList(mapping)) + security.setAuthenticator(new BasicAuthenticator()) + security.setLoginService(service) + + security.setHandler(webapp) + security + } +} diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfModule.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfModule.groovy index 1aa4efa9f..4a66a1c3c 100644 --- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfModule.groovy +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfModule.groovy @@ -18,13 +18,19 @@ package io.fd.honeycomb.infra.distro.restconf import com.google.inject.AbstractModule import com.google.inject.Singleton +import com.google.inject.name.Names import groovy.util.logging.Slf4j +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.server.ServerConnector import org.opendaylight.netconf.sal.rest.api.RestConnector @Slf4j class RestconfModule extends AbstractModule { protected void configure() { + bind(Server).toProvider(JettyServerProvider).in(Singleton) + bind(ServerConnector).annotatedWith(Names.named("restconf-http")).toProvider(HttpConnectorProvider).in(Singleton) + bind(ServerConnector).annotatedWith(Names.named("restconf-https")).toProvider(HttpsConnectorProvider).in(Singleton) bind(RestConnector).toProvider(RestconfProvider).in(Singleton) } } diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfProvider.groovy b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfProvider.groovy index bffe1da1a..657e16986 100644 --- a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfProvider.groovy +++ b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/restconf/RestconfProvider.groovy @@ -21,19 +21,6 @@ import groovy.transform.ToString import groovy.util.logging.Slf4j import io.fd.honeycomb.infra.distro.ProviderTrait import io.fd.honeycomb.infra.distro.cfgattrs.HoneycombConfiguration -import org.eclipse.jetty.http.HttpVersion -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.HttpConnectionFactory -import org.eclipse.jetty.server.Server -import org.eclipse.jetty.server.ServerConnector -import org.eclipse.jetty.server.SslConnectionFactory -import org.eclipse.jetty.util.security.Constraint -import org.eclipse.jetty.util.security.Password -import org.eclipse.jetty.util.ssl.SslContextFactory -import org.eclipse.jetty.webapp.WebAppContext import org.opendaylight.controller.sal.core.api.Broker import org.opendaylight.netconf.sal.rest.api.RestConnector import org.opendaylight.netconf.sal.restconf.impl.RestconfProviderImpl @@ -43,10 +30,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. @ToString class RestconfProvider extends ProviderTrait<RestConnector> { - public static final String KEYSTORE_PASSWORD = "OBF:1v9s1unr1unn1vv51zlk1t331vg91x1b1vgl1t331zly1vu51uob1uo71v8u" - public static final String KEYSTORE_NAME = "/honeycomb-keystore" - public static final String REALM = "HCRealm" - @Inject HoneycombConfiguration cfg @@ -55,84 +38,8 @@ class RestconfProvider extends ProviderTrait<RestConnector> { def create() { def instance = new RestconfProviderImpl() - instance.setWebsocketPort(new PortNumber(cfg.restconfWebsocketPort)) + instance.setWebsocketPort(new PortNumber(cfg.restconfWebsocketPort.get())) domBroker.registerProvider(instance) - - def server = new Server(InetSocketAddress.createUnresolved(cfg.restconfBindingAddress, cfg.restconfPort)) - - // Load Realm for basic auth - def service = new HashLoginService(REALM) - // Reusing the name as role - // TODO make this more configurable - service.putUser(cfg.username, new Password(cfg.password), cfg.username) - server.addBean(service) - - final URL resource = getClass().getResource("/") - WebAppContext webapp = new WebAppContext(resource.getPath(), cfg.restconfRootPath) - - ConstraintSecurityHandler security = getBaseAuth(service, webapp) - server.setHandler(security) - - // 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 - def sslContextFactory = new SslContextFactory() - def keystoreURL = getClass().getResource(KEYSTORE_NAME) - sslContextFactory.setKeyStorePath(keystoreURL.path) - sslContextFactory.setKeyStorePassword(KEYSTORE_PASSWORD) - sslContextFactory.setKeyManagerPassword(KEYSTORE_PASSWORD) - sslContextFactory.setTrustStorePath(keystoreURL.path) - sslContextFactory.setTrustStorePassword(KEYSTORE_PASSWORD) - 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 - def sslConnector = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), - new HttpConnectionFactory()) - sslConnector.setHost(cfg.restconfHttpsBindingAddress) - sslConnector.setPort(cfg.restconfHttpsPort) - server.addConnector(sslConnector) - - try { - server.start() - } catch (Exception e) { - log.error "Unable to start Restconf", e - throw new RuntimeException("Unable to start Restconf", e) - } - - return instance - } - - private ConstraintSecurityHandler getBaseAuth(HashLoginService service, WebAppContext webapp) { - ConstraintSecurityHandler security = new ConstraintSecurityHandler() - - Constraint constraint = new Constraint() - constraint.setName("auth") - constraint.setAuthenticate(true) - constraint.setRoles(cfg.username) - - ConstraintMapping mapping = new ConstraintMapping() - mapping.setPathSpec("/*") - mapping.setConstraint(constraint) - - security.setConstraintMappings(Collections.singletonList(mapping)) - security.setAuthenticator(new BasicAuthenticator()) - security.setLoginService(service) - - security.setHandler(webapp) - security + instance } } |