diff options
author | Zlatko Murgoski <zlatko.murgoski@nokia.com> | 2019-02-04 09:27:00 +0100 |
---|---|---|
committer | Zlatko Murgoski <zlatko.murgoski@nokia.com> | 2019-03-01 07:50:28 +0100 |
commit | e7360f7e7e77672b885087af68a3d96ebbc8c313 (patch) | |
tree | 8316d86334ec400b48f5a7a6a862fe7ffd9b9867 /src/main/java/org | |
parent | 8971ae1e6ccc99811663652819206231065b1755 (diff) |
Restart Issue
Restart Issue
Issue-ID: DCAEGEN2-1104
Change-Id: Iac1ee2f79be00084f5c0cd963503d54d7d6e6cb9
Signed-off-by: Zlatko Murgoski <zlatko.murgoski@nokia.com>
Diffstat (limited to 'src/main/java/org')
7 files changed, 157 insertions, 122 deletions
diff --git a/src/main/java/org/onap/dcae/ApplicationException.java b/src/main/java/org/onap/dcae/ApplicationException.java index 2079d867..1252423d 100644 --- a/src/main/java/org/onap/dcae/ApplicationException.java +++ b/src/main/java/org/onap/dcae/ApplicationException.java @@ -34,7 +34,11 @@ public class ApplicationException extends RuntimeException { super(message,ex); } - public ApplicationException(IOException ex) { + public ApplicationException(Exception ex) { super(ex); } + + public ApplicationException(String message) { + super(message); + } } diff --git a/src/main/java/org/onap/dcae/ApplicationSettings.java b/src/main/java/org/onap/dcae/ApplicationSettings.java index 7d52c5e8..7a2bff97 100644 --- a/src/main/java/org/onap/dcae/ApplicationSettings.java +++ b/src/main/java/org/onap/dcae/ApplicationSettings.java @@ -69,11 +69,21 @@ public class ApplicationSettings { Map<String, String> parsedArgs = argsParser.apply(args); configurationFileLocation = findOutConfigurationFileLocation(parsedArgs); loadPropertiesFromFile(); - parsedArgs.filterKeys(k -> !"c".equals(k)).forEach(this::updateProperty); + parsedArgs.filterKeys(k -> !"c".equals(k)).forEach(this::addOrUpdate); loadedJsonSchemas = loadJsonSchemas(); } - private void loadPropertiesFromFile() { + + public void reloadProperties() { + try { + properties.load(configurationFileLocation); + properties.refresh(); + } catch (ConfigurationException ex) { + log.error("Cannot load properties cause:", ex); + throw new ApplicationException(ex); + } + } + public void loadPropertiesFromFile() { try { properties.load(configurationFileLocation); } catch (ConfigurationException ex) { @@ -169,10 +179,6 @@ public class ApplicationSettings { return httpsEnabled() && properties.getInt("collector.service.secure.clientauth", 0) > 0; } - public String keystoreAlias() { - return properties.getString("collector.keystore.alias", "tomcat"); - } - public String truststorePasswordFileLocation() { return prependWithUserDirOnRelative(properties.getString("collector.truststore.passwordfile", "etc/trustpasswordfile")); } @@ -198,6 +204,14 @@ public class ApplicationSettings { } } + public void addOrUpdate(String key, String value) { + if (properties.containsKey(key)) { + properties.setProperty(key, value); + } else { + properties.addProperty(key, value); + } + } + private JSONObject jsonSchema() { return new JSONObject(properties.getString("collector.schema.file", format("{\"%s\":\"etc/CommonEventFormat_28.4.1.json\"}", FALLBACK_VES_VERSION))); @@ -214,14 +228,6 @@ public class ApplicationSettings { return HashMap.ofAll(domainToStreamIdsMapping); } - private void updateProperty(String key, String value) { - if (properties.containsKey(key)) { - properties.setProperty(key, value); - } else { - properties.addProperty(key, value); - } - } - private String prependWithUserDirOnRelative(String filePath) { if (!Paths.get(filePath).isAbsolute()) { filePath = Paths.get(appInvocationDir, filePath).toString(); diff --git a/src/main/java/org/onap/dcae/VesApplication.java b/src/main/java/org/onap/dcae/VesApplication.java index 2dcd8fa8..d658b4aa 100644 --- a/src/main/java/org/onap/dcae/VesApplication.java +++ b/src/main/java/org/onap/dcae/VesApplication.java @@ -25,6 +25,7 @@ import java.nio.file.Paths; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.json.JSONObject; @@ -41,6 +42,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Lazy; @@ -54,47 +56,77 @@ public class VesApplication { private static final int MAX_THREADS = 20; public static LinkedBlockingQueue<JSONObject> fProcessingInputQueue; private static ApplicationSettings properties; + private static ConfigurableApplicationContext context; + private static ConfigLoader configLoader; + private static EventProcessor eventProcessor; + private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; + private static SpringApplication app; + private static EventPublisher eventPublisher; + private static ScheduledFuture<?> scheduleFeatures; + private static ExecutorService executor; public static void main(String[] args) { - SpringApplication app = new SpringApplication(VesApplication.class); + app = new SpringApplication(VesApplication.class); + properties = new ApplicationSettings(args, CLIUtils::processCmdLine); + scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); + init(); + app.setAddCommandLineProperties(true); + context = app.run(); + configLoader.updateConfig(); - properties = new ApplicationSettings(args, CLIUtils::processCmdLine); + } + + public static void restartApplication() { + Thread thread = new Thread(() -> { + context.close(); + properties.reloadProperties(); + scheduleFeatures.cancel(true); + init(); + context = SpringApplication.run(VesApplication.class); + }); + thread.setDaemon(false); + thread.start(); + } + + private static void init() { + fProcessingInputQueue = new LinkedBlockingQueue<>(properties.maximumAllowedQueuedEvents()); + createConfigLoader(); + createSchedulePoolExecutor(); + createExecutors(); + } - fProcessingInputQueue = new LinkedBlockingQueue<>(properties.maximumAllowedQueuedEvents()); + private static void createExecutors() { + eventPublisher = EventPublisher.createPublisher(oplog, getDmapConfig()); + eventProcessor = new EventProcessor(new EventSender(eventPublisher, properties)); - EventPublisher publisher = EventPublisher.createPublisher(oplog, - DMaaPConfigurationParser - .parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())) - .get()); - spawnDynamicConfigUpdateThread(publisher, properties); - EventProcessor ep = new EventProcessor( - new EventSender(EventPublisher.createPublisher(oplog, getDmapConfig()), properties)); + executor = Executors.newFixedThreadPool(MAX_THREADS); + for (int i = 0; i < MAX_THREADS; ++i) { + executor.execute(eventProcessor); + } + } - ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS); - for (int i = 0; i < MAX_THREADS; ++i) { - executor.execute(ep); - } + private static void createSchedulePoolExecutor() { + scheduleFeatures = scheduledThreadPoolExecutor.scheduleAtFixedRate(configLoader::updateConfig, + properties.configurationUpdateFrequency(), + properties.configurationUpdateFrequency(), + TimeUnit.MINUTES); + } - app.setAddCommandLineProperties(true); - app.run(); + private static void createConfigLoader() { + configLoader = ConfigLoader.create(getEventPublisher()::reconfigure, + Paths.get(properties.dMaaPConfigurationFileLocation()), + properties.configurationFileLocation()); } - private static void spawnDynamicConfigUpdateThread(EventPublisher eventPublisher, ApplicationSettings properties) { - ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); - ConfigLoader configLoader = ConfigLoader - .create(eventPublisher::reconfigure, - Paths.get(properties.dMaaPConfigurationFileLocation()), - properties.configurationFileLocation()); - scheduledThreadPoolExecutor - .scheduleAtFixedRate(configLoader::updateConfig, - properties.configurationUpdateFrequency(), - properties.configurationUpdateFrequency(), - TimeUnit.MINUTES); + + private static EventPublisher getEventPublisher() { + return EventPublisher.createPublisher(oplog, DMaaPConfigurationParser + .parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())).get()); } private static Map<String, PublisherConfig> getDmapConfig() { - return DMaaPConfigurationParser. - parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())).get(); + return DMaaPConfigurationParser + .parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())).get(); } @Bean diff --git a/src/main/java/org/onap/dcae/common/SSLContextCreator.java b/src/main/java/org/onap/dcae/common/SSLContextCreator.java index a76c7cbe..e636f4c0 100644 --- a/src/main/java/org/onap/dcae/common/SSLContextCreator.java +++ b/src/main/java/org/onap/dcae/common/SSLContextCreator.java @@ -20,9 +20,8 @@ package org.onap.dcae.common; -import org.springframework.boot.web.server.Ssl; - import java.nio.file.Path; +import org.springframework.boot.web.server.Ssl; public class SSLContextCreator { private final String keyStorePassword; @@ -53,7 +52,6 @@ public class SSLContextCreator { private void configureKeyStore(final Ssl ssl) { final String keyStore = keyStoreFile.toAbsolutePath().toString(); - ssl.setKeyStore(keyStore); ssl.setKeyPassword(keyStorePassword); ssl.setKeyAlias(certAlias); diff --git a/src/main/java/org/onap/dcae/controller/ConfigLoader.java b/src/main/java/org/onap/dcae/controller/ConfigLoader.java index e11c2b8a..dbf52823 100644 --- a/src/main/java/org/onap/dcae/controller/ConfigLoader.java +++ b/src/main/java/org/onap/dcae/controller/ConfigLoader.java @@ -33,6 +33,7 @@ import io.vavr.control.Try; import java.nio.file.Path; import java.util.function.Consumer; import org.json.JSONObject; +import org.onap.dcae.VesApplication; import org.onap.dcae.common.publishing.PublisherConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,19 +46,21 @@ public class ConfigLoader { private final ConfigFilesFacade configFilesFacade; private final Function1<EnvProps, Try<JSONObject>> configurationSource; private final Function0<Map<String, String>> envVariablesSupplier; + private boolean toRestart = false; ConfigLoader(Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer, - ConfigFilesFacade configFilesFacade, - Function1<EnvProps, Try<JSONObject>> configurationSource, - Function0<Map<String, String>> envVariablesSupplier) { + ConfigFilesFacade configFilesFacade, + Function1<EnvProps, Try<JSONObject>> configurationSource, + Function0<Map<String, String>> envVariablesSupplier) { this.eventPublisherReconfigurer = eventPublisherReconfigurer; this.configFilesFacade = configFilesFacade; this.configurationSource = configurationSource; this.envVariablesSupplier = envVariablesSupplier; } - public static ConfigLoader create(Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer, - Path dMaaPConfigFile, Path propertiesConfigFile) { + public static ConfigLoader create( + Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer, + Path dMaaPConfigFile, Path propertiesConfigFile) { return new ConfigLoader(eventPublisherReconfigurer, new ConfigFilesFacade(dMaaPConfigFile, propertiesConfigFile), ConfigSource::getAppConfig, @@ -67,20 +70,27 @@ public class ConfigLoader { public void updateConfig() { log.info("Trying to dynamically update config from Config Binding Service"); readEnvProps(envVariablesSupplier.get()) - .onEmpty(() -> log.warn(SKIP_MSG)) - .forEach(this::updateConfig); + .onEmpty(() -> log.warn(SKIP_MSG)).forEach(this::updateConfig); } private void updateConfig(EnvProps props) { configurationSource.apply(props) .onFailure(logSkip()) .onSuccess(newConf -> { - updateConfigurationProperties(newConf); - updateDMaaPProperties(newConf); + updateConfigurationProperties(newConf); + updateDMaaPProperties(newConf); + reloadApplication(); } ); } + private void reloadApplication() { + if(toRestart){ + log.info("New app config - Application will be restarted"); + VesApplication.restartApplication(); + } + } + private void updateDMaaPProperties(JSONObject newConf) { configFilesFacade.readDMaaPConfiguration() .onFailure(logSkip()) @@ -98,9 +108,13 @@ public class ConfigLoader { private void compareAndOverwritePropertiesConfig(JSONObject newConf, Map<String, String> oldProps) { Map<String, String> newProperties = getProperties(newConf); - if (!oldProps.equals(newProperties)) { + Map<String, String> result = oldProps.filterKeys((s) -> newProperties.keySet().contains(s)); + if (!result.equals(newProperties)) { configFilesFacade.writeProperties(newProperties) - .onSuccess(__ -> log.info("New properties configuration written to file")) + .onSuccess(__ -> { + toRestart= true; + log.info("New properties configuration written to file"); + }) .onFailure(logSkip()); } else { log.info("Collector properties from CBS are the same as currently used ones. " + SKIP_MSG); @@ -115,7 +129,10 @@ public class ConfigLoader { .onSuccess(parsedConfig -> configFilesFacade.writeDMaaPConfiguration(newDMaaPConf) .onFailure(logSkip()) - .onSuccess(__ -> log.info("New dMaaP configuration written to file"))); + .onSuccess(__ -> { + toRestart= true; + log.info("New dMaaP configuration written to file"); + })); } else { log.info("DMaaP config from CBS is the same as currently used one. " + SKIP_MSG); } diff --git a/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java b/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java deleted file mode 100644 index be569119..00000000 --- a/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java +++ /dev/null @@ -1,49 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.ves - * ================================================================================ - * Copyright (C) 2018 Nokia. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.dcae.controller; - -import io.vavr.collection.Map; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.function.Consumer; -import org.onap.dcae.common.publishing.PublisherConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * On the first application launch, the configuration update thread that application spawns, has no chance to run yet - * and prepare initial application configuration. In this case, it needs to be fetched from outside of the application, - * so this is run from the .sh script. - * Later on, once application is already started it will take care of the configuration update itself - * @author Pawel Szalapski (pawel.szalapski@nokia.com) - */ -public class PreAppStartupConfigUpdater { - private final static Logger log = LoggerFactory.getLogger(PreAppStartupConfigUpdater.class); - - private static final Path DEFAULT_CONFIGURATION_FILE_PATH = Paths.get("etc/collector.properties"); - private static final Path DEFAULT_DMAAP_FILE_PATH = Paths.get("etc/DmaapConfig.json"); - private static final Consumer<Map<String, PublisherConfig>> NO_OP_CONSUMER = c -> { }; - - public static void main(String[] args) { - log.info("Running initial configuration update, before the application gets started."); - ConfigLoader.create(NO_OP_CONSUMER, DEFAULT_DMAAP_FILE_PATH, DEFAULT_CONFIGURATION_FILE_PATH) - .updateConfig(); - } -} diff --git a/src/main/java/org/onap/dcae/restapi/ServletConfig.java b/src/main/java/org/onap/dcae/restapi/ServletConfig.java index 35616ac1..e66f3f1f 100644 --- a/src/main/java/org/onap/dcae/restapi/ServletConfig.java +++ b/src/main/java/org/onap/dcae/restapi/ServletConfig.java @@ -21,6 +21,16 @@ package org.onap.dcae.restapi; +import static java.nio.file.Files.readAllBytes; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; import org.onap.dcae.ApplicationException; import org.onap.dcae.ApplicationSettings; import org.onap.dcae.common.SSLContextCreator; @@ -32,12 +42,6 @@ import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; - -import static java.nio.file.Files.readAllBytes; - @Component public class ServletConfig implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> { @@ -49,28 +53,51 @@ public class ServletConfig implements WebServerFactoryCustomizer<ConfigurableSer @Override public void customize(ConfigurableServletWebServerFactory container) { final boolean hasClientTlsAuthentication = properties.clientTlsAuthenticationEnabled(); - if (hasClientTlsAuthentication || properties.authorizationEnabled()) { - container.setSsl(hasClientTlsAuthentication ? httpsContextWithTlsAuthentication() : simpleHttpsContext()); - container.setPort(properties.httpsPort()); + container.setSsl(hasClientTlsAuthentication ? httpsContextWithTlsAuthentication() : simpleHttpsContext()); + int port = properties.httpsPort(); + container.setPort(port); + log.info("Application https port: " + port); } else { - container.setPort(properties.httpPort()); + int port = properties.httpPort(); + container.setPort(port); + log.info("Application http port: " + port); } + } private SSLContextCreator simpleHttpsContextBuilder() { log.info("Enabling SSL"); - final Path keyStore = toAbsolutePath(properties.keystoreFileLocation()); - log.info("Using keyStore path: " + keyStore); + final Path keyStorePath = toAbsolutePath(properties.keystoreFileLocation()); + log.info("Using keyStore path: " + keyStorePath); final Path keyStorePasswordLocation = toAbsolutePath(properties.keystorePasswordFileLocation()); final String keyStorePassword = getKeyStorePassword(keyStorePasswordLocation); log.info("Using keyStore password from: " + keyStorePasswordLocation); + return SSLContextCreator.create(keyStorePath, getKeyStoreAlias(keyStorePath, keyStorePassword), keyStorePassword); + } - final String alias = properties.keystoreAlias(); + private String getKeyStoreAlias(Path keyStorePath, String keyStorePassword) { + KeyStore keyStore = getKeyStore(); + try(InputStream keyStoreData = new FileInputStream(keyStorePath.toString())){ + keyStore.load(keyStoreData, keyStorePassword.toCharArray()); + String alias = keyStore.aliases().nextElement(); + log.info("Actual key store alias is: " + alias); + return alias; + } catch (IOException | GeneralSecurityException ex) { + log.error("Cannot load Key Store alias cause: " + ex); + throw new ApplicationException(ex); + } + } - return SSLContextCreator.create(keyStore, alias, keyStorePassword); + private KeyStore getKeyStore() { + try { + return KeyStore.getInstance(KeyStore.getDefaultType()); + } catch (KeyStoreException ex) { + log.error("Cannot create Key Store instance cause: " + ex); + throw new ApplicationException(ex); + } } private Ssl simpleHttpsContext() { |