aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/onap/dcae/controller
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/onap/dcae/controller')
-rw-r--r--src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java122
-rw-r--r--src/main/java/org/onap/dcae/controller/ConfigLoader.java128
-rw-r--r--src/main/java/org/onap/dcae/controller/ConfigParsing.java58
-rw-r--r--src/main/java/org/onap/dcae/controller/ConfigSource.java88
-rw-r--r--src/main/java/org/onap/dcae/controller/Conversions.java53
-rw-r--r--src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java77
-rw-r--r--src/main/java/org/onap/dcae/controller/EnvProps.java70
-rw-r--r--src/main/java/org/onap/dcae/controller/FetchDynamicConfig.java186
-rw-r--r--src/main/java/org/onap/dcae/controller/LoadDynamicConfig.java128
-rw-r--r--src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java49
10 files changed, 645 insertions, 314 deletions
diff --git a/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java b/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java
new file mode 100644
index 00000000..42155eda
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * 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 static io.vavr.API.Try;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.enhanceError;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.logError;
+import static org.onap.dcae.controller.Conversions.toList;
+
+import io.vavr.CheckedRunnable;
+import io.vavr.Tuple2;
+import io.vavr.collection.Map;
+import io.vavr.control.Try;
+import java.io.FileNotFoundException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class ConfigFilesFacade {
+
+ private static Logger log = LoggerFactory.getLogger(ConfigFilesFacade.class);
+
+ private final Path dMaaPConfigPath;
+ private final Path propertiesPath;
+
+ public ConfigFilesFacade(Path dMaaPConfigPath, Path propertiesPath) {
+ this.dMaaPConfigPath = dMaaPConfigPath;
+ this.propertiesPath = propertiesPath;
+ }
+
+ Try<Map<String, String>> readCollectorProperties() {
+ log.info(f("Reading collector properties from path: '%s'", propertiesPath));
+ return Try(() -> readProperties())
+ .map(prop -> toList(prop.getKeys()).toMap(k -> k, k -> (String) prop.getProperty(k)))
+ .mapFailure(enhanceError("Unable to read properties configuration from path '%s'", propertiesPath))
+ .onFailure(logError(log))
+ .peek(props -> log.info(f("Read following collector properties: '%s'", props)));
+ }
+
+ Try<JSONObject> readDMaaPConfiguration() {
+ log.info(f("Reading DMaaP configuration from file: '%s'", dMaaPConfigPath));
+ return readFile(dMaaPConfigPath)
+ .recover(FileNotFoundException.class, __ -> "{}")
+ .mapFailure(enhanceError("Unable to read DMaaP configuration from file '%s'", dMaaPConfigPath))
+ .flatMap(Conversions::toJson)
+ .onFailure(logError(log))
+ .peek(props -> log.info(f("Read following DMaaP properties: '%s'", props)));
+ }
+
+ Try<Void> writeDMaaPConfiguration(JSONObject dMaaPConfiguration) {
+ log.info(f("Writing DMaaP configuration '%s' into file '%s'", dMaaPConfiguration, dMaaPConfigPath));
+ return writeFile(dMaaPConfigPath, indentConfiguration(dMaaPConfiguration.toString()))
+ .mapFailure(enhanceError("Could not save new DMaaP configuration to path '%s'", dMaaPConfigPath))
+ .onFailure(logError(log))
+ .peek(__ -> log.info("Written successfully"));
+ }
+
+
+ Try<Void> writeProperties(Map<String, String> properties) {
+ log.info(f("Writing properties configuration '%s' into file '%s'", properties, propertiesPath));
+ return Try.run(saveProperties(properties))
+ .mapFailure(enhanceError("Could not save properties to path '%s'", properties))
+ .onFailure(logError(log))
+ .peek(__ -> log.info("Written successfully"));
+ }
+
+ private Try<String> readFile(Path path) {
+ return Try(() -> new String(Files.readAllBytes(path), StandardCharsets.UTF_8))
+ .mapFailure(enhanceError("Could not read content from path: '%s'", path));
+ }
+
+ private Try<Void> writeFile(Path path, String content) {
+ return Try.run(() -> Files.write(path, content.getBytes()))
+ .mapFailure(enhanceError("Could not write content to path: '%s'", path));
+ }
+
+ private PropertiesConfiguration readProperties() throws ConfigurationException {
+ PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration();
+ propertiesConfiguration.load(propertiesPath.toFile());
+ return propertiesConfiguration;
+ }
+
+ private CheckedRunnable saveProperties(Map<String, String> properties) {
+ return () -> {
+ PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration(propertiesPath.toFile());
+ propertiesConfiguration.setEncoding(null);
+ for (Tuple2<String, String> property : properties) {
+ propertiesConfiguration.addProperty(property._1, property._2);
+ }
+ propertiesConfiguration.save();
+ };
+ }
+
+ private String indentConfiguration(String configuration) {
+ return new JSONObject(configuration).toString(4);
+ }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/ConfigLoader.java b/src/main/java/org/onap/dcae/controller/ConfigLoader.java
new file mode 100644
index 00000000..fb807075
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/ConfigLoader.java
@@ -0,0 +1,128 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * 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 static org.onap.dcae.commonFunction.event.publishing.DMaaPConfigurationParser.parseToDomainMapping;
+import static org.onap.dcae.controller.ConfigParsing.getDMaaPConfig;
+import static org.onap.dcae.controller.ConfigParsing.getProperties;
+import static org.onap.dcae.controller.EnvPropertiesReader.readEnvProps;
+
+import io.vavr.Function0;
+import io.vavr.Function1;
+import io.vavr.collection.HashMap;
+import io.vavr.collection.Map;
+import io.vavr.control.Try;
+import java.nio.file.Path;
+import java.util.function.Consumer;
+import org.json.JSONObject;
+import org.onap.dcae.commonFunction.event.publishing.EventPublisher;
+import org.onap.dcae.commonFunction.event.publishing.PublisherConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigLoader {
+
+ private static final String SKIP_MSG = "Skipping dynamic configuration update";
+ private static Logger log = LoggerFactory.getLogger(ConfigLoader.class);
+ private final Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer;
+ private final ConfigFilesFacade configFilesFacade;
+ private final Function1<EnvProps, Try<JSONObject>> configurationSource;
+ private final Function0<Map<String, String>> envVariablesSupplier;
+
+ ConfigLoader(Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer,
+ 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) {
+ return new ConfigLoader(eventPublisherReconfigurer,
+ new ConfigFilesFacade(dMaaPConfigFile, propertiesConfigFile),
+ ConfigSource::getAppConfig,
+ () -> HashMap.ofAll(System.getenv()));
+ }
+
+ public void updateConfig() {
+ log.info("Trying to dynamically update config from Config Binding Service");
+ readEnvProps(envVariablesSupplier.get())
+ .onEmpty(() -> log.warn(SKIP_MSG))
+ .forEach(props -> updateConfig(props));
+ }
+
+ private void updateConfig(EnvProps props) {
+ configurationSource.apply(props)
+ .onFailure(logSkip())
+ .onSuccess(newConf -> {
+ updateConfigurationProperties(newConf);
+ updateDMaaPProperties(newConf);
+ }
+ );
+ }
+
+ private void updateDMaaPProperties(JSONObject newConf) {
+ configFilesFacade.readDMaaPConfiguration()
+ .onFailure(logSkip())
+ .onSuccess(oldDMaaPConf -> getDMaaPConfig(newConf)
+ .onEmpty(() -> log.warn(SKIP_MSG))
+ .forEach(newDMaaPConf -> compareAndOverwriteDMaaPConfig(oldDMaaPConf, newDMaaPConf)));
+ }
+
+
+ private void updateConfigurationProperties(JSONObject newConf) {
+ configFilesFacade.readCollectorProperties()
+ .onFailure(logSkip())
+ .onSuccess(oldProps -> compareAndOverwritePropertiesConfig(newConf, oldProps));
+ }
+
+ private void compareAndOverwritePropertiesConfig(JSONObject newConf, Map<String, String> oldProps) {
+ Map<String, String> newProperties = getProperties(newConf);
+ if (!oldProps.equals(newProperties)) {
+ configFilesFacade.writeProperties(newProperties)
+ .onSuccess(__ -> 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);
+ }
+ }
+
+ private void compareAndOverwriteDMaaPConfig(JSONObject oldDMaaPConf, JSONObject newDMaaPConf) {
+ if (!oldDMaaPConf.toString().equals(newDMaaPConf.toString())) {
+ parseToDomainMapping(newDMaaPConf)
+ .onFailure(exc -> log.error(SKIP_MSG, exc))
+ .onSuccess(eventPublisherReconfigurer)
+ .onSuccess(parsedConfig ->
+ configFilesFacade.writeDMaaPConfiguration(newDMaaPConf)
+ .onFailure(logSkip())
+ .onSuccess(__ -> log.info("New dMaaP configuration written to file")));
+ } else {
+ log.info("DMaaP config from CBS is the same as currently used one. " + SKIP_MSG);
+ }
+ }
+
+ private Consumer<Throwable> logSkip() {
+ return __ -> log.error(SKIP_MSG);
+ }
+}
diff --git a/src/main/java/org/onap/dcae/controller/ConfigParsing.java b/src/main/java/org/onap/dcae/controller/ConfigParsing.java
new file mode 100644
index 00000000..2ee0c918
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/ConfigParsing.java
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * 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 static io.vavr.API.Try;
+import static io.vavr.API.Tuple;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+import static org.onap.dcae.controller.Conversions.toList;
+
+import io.vavr.collection.Map;
+import io.vavr.control.Option;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+interface ConfigParsing {
+
+ Logger log = LoggerFactory.getLogger(ConfigParsing.class);
+
+ static Option<JSONObject> getDMaaPConfig(JSONObject configuration) {
+ log.info(f("Getting DMaaP configuration from app configuration: '%s'", configuration));
+ return toList(configuration.toMap().entrySet().iterator())
+ .filter(t -> t.getKey().startsWith("streams_publishes"))
+ .headOption()
+ .flatMap(e -> Try(() -> configuration.getJSONObject(e.getKey())).toOption())
+ .onEmpty(() -> log.warn(f("App configuration '%s' is missing DMaaP configuration ('streams_publishes' key) "
+ + "or DMaaP configuration is not a valid json document", configuration)))
+ .peek(dMaaPConf -> log.info(f("Found following DMaaP configuration: '%s'", dMaaPConf)));
+ }
+
+ static Map<String, String> getProperties(JSONObject configuration) {
+ log.info(f("Getting properties configuration from app configuration: '%s'", configuration));
+ Map<String, String> confEntries = toList(configuration.toMap().entrySet().iterator())
+ .toMap(e -> Tuple(e.getKey(), String.valueOf(e.getValue())))
+ .filterKeys(e -> !e.startsWith("streams_publishes"));
+ log.info(f("Found following app properties: '%s'", confEntries));
+ return confEntries;
+ }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/ConfigSource.java b/src/main/java/org/onap/dcae/controller/ConfigSource.java
new file mode 100644
index 00000000..7e6a9fc8
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/ConfigSource.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * 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 static io.vavr.API.Try;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.enhanceError;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+import static org.onap.dcae.controller.Conversions.toJson;
+import static org.onap.dcae.controller.Conversions.toJsonArray;
+
+import com.mashape.unirest.http.Unirest;
+import io.vavr.control.Try;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class ConfigSource {
+
+ private static final Logger log = LoggerFactory.getLogger(ConfigSource.class);
+
+ static Try<JSONObject> getAppConfig(EnvProps envProps) {
+ log.info("Fetching app configuration from CBS");
+ return callConsulForCBSConfiguration(envProps)
+ .peek(strBody -> log.info(f("Received following CBS configuration from Consul '%s'", strBody)))
+ .flatMap(strBody -> toJsonArray(strBody))
+ .flatMap(json -> withdrawCatalog(json))
+ .flatMap(json -> constructFullCBSUrl(json))
+ .flatMap(cbsUrl -> callCBSForAppConfig(envProps, cbsUrl))
+ .flatMap(strBody -> toJson(strBody))
+ .peek(jsonNode -> log.info(f("Received app configuration: '%s'", jsonNode)))
+ .onFailure(exc -> log.error("Could not fetch application config", exc));
+ }
+
+ private static Try<String> callConsulForCBSConfiguration(EnvProps envProps) {
+ return executeGet(envProps.consulHost + ":" + envProps.consulPort + "/v1/catalog/service/" + envProps.cbsName)
+ .mapFailure(enhanceError("Unable to retrieve CBS configuration from Consul"));
+ }
+
+ private static Try<String> constructFullCBSUrl(JSONObject json) {
+ return Try(() -> json.get("ServiceAddress").toString() + ":" + json.get("ServicePort").toString())
+ .mapFailure(enhanceError("ServiceAddress / ServicePort missing from CBS conf: '%s'", json));
+ }
+
+ private static Try<JSONObject> withdrawCatalog(JSONArray json) {
+ return Try(() -> new JSONObject(json.get(0).toString()))
+ .mapFailure(enhanceError("CBS response '%s' is in invalid format,"
+ + " most probably is it not a list of configuration objects", json));
+ }
+
+ private static Try<String> callCBSForAppConfig(EnvProps envProps, String cbsUrl) {
+ log.info("Calling CBS for application config");
+ return executeGet(cbsUrl + "/service_component/" + envProps.appName)
+ .mapFailure(enhanceError("Unable to fetch configuration from CBS"));
+ }
+
+
+ private static Try<String> executeGet(String url) {
+ log.info(f("Calling HTTP GET on url: '%s'", url));
+ return Try(() -> Unirest.get(url).asString())
+ .mapFailure(enhanceError("Http call (GET '%s') failed.", url))
+ .filter(
+ res -> res.getStatus() == 200,
+ res -> new RuntimeException(f("HTTP call (GET '%s') failed with status %s and body '%s'",
+ url, res.getStatus(), res.getBody())))
+ .map(res -> res.getBody())
+ .peek(body -> log.info(f("HTTP GET on '%s' returned body '%s'", url, body)));
+ }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/Conversions.java b/src/main/java/org/onap/dcae/controller/Conversions.java
new file mode 100644
index 00000000..09a9a43c
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/Conversions.java
@@ -0,0 +1,53 @@
+/*-
+ * ============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 static org.onap.dcae.commonFunction.event.publishing.VavrUtils.enhanceError;
+
+import io.vavr.API;
+import io.vavr.collection.List;
+import io.vavr.control.Try;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.StreamSupport;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ * @author Pawel Szalapski (pawel.szalapski@nokia.com)
+ */
+interface Conversions {
+
+ static Try<JSONObject> toJson(String strBody) {
+ return API.Try(() -> new JSONObject(strBody))
+ .mapFailure(enhanceError("Value '%s' is not a valid JSON document", strBody));
+ }
+
+ static Try<JSONArray> toJsonArray(String strBody) {
+ return API.Try(() -> new JSONArray(strBody))
+ .mapFailure(enhanceError("Value '%s' is not a valid JSON array", strBody));
+ }
+
+ static <T> List<T> toList(Iterator<T> iterator) {
+ return List.ofAll(StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false));
+ }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java b/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java
new file mode 100644
index 00000000..23bcbda8
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.ves
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * 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 static io.vavr.API.List;
+import static io.vavr.API.Try;
+import static org.onap.dcae.commonFunction.event.publishing.VavrUtils.f;
+
+import io.vavr.collection.Map;
+import io.vavr.control.Option;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class EnvPropertiesReader {
+
+ private final static Logger log = LoggerFactory.getLogger(EnvPropertiesReader.class);
+
+ static Option<EnvProps> readEnvProps(Map<String, String> environmentVariables) {
+ log.info("Loading necessary environment variables for dynamic configuration update");
+ int consulPort = getConsulPort(environmentVariables);
+ Option<String> consulHost = getConsulHost(environmentVariables);
+ Option<String> cbsServiceName = getCBSName(environmentVariables);
+ Option<String> vesCollectorAppName = getAppName(environmentVariables);
+ return Option.sequence(List(consulHost, cbsServiceName, vesCollectorAppName))
+ .map(e -> new EnvProps(e.get(0), consulPort, e.get(1), e.get(2)))
+ .onEmpty(() -> log.warn("Some required environment variables are missing"))
+ .peek(props -> log.info(f("Discovered following environment variables: '%s'", props)));
+ }
+
+ private static Option<String> getAppName(Map<String, String> environmentVariables) {
+ return environmentVariables.get("HOSTNAME")
+ .orElse(environmentVariables.get("SERVICE_NAME"))
+ .onEmpty(() -> log.warn("App service name (as registered in CBS) (env var: 'HOSTNAME' / 'SERVICE_NAME') "
+ + "is missing error environment variables."));
+ }
+
+ private static Option<String> getCBSName(Map<String, String> environmentVariables) {
+ return environmentVariables.get("CONFIG_BINDING_SERVICE")
+ .onEmpty(() -> log.warn("Name of CBS Service (as registered in Consul) (env var: 'CONFIG_BINDING_SERVICE') "
+ + "is missing from environment variables."));
+ }
+
+ private static Integer getConsulPort(Map<String, String> environmentVariables) {
+ return environmentVariables.get("CONSUL_PORT")
+ .flatMap(str -> Try(() -> Integer.valueOf(str))
+ .onFailure(exc -> log.warn("Consul port is not an integer value", exc))
+ .toOption())
+ .onEmpty(() -> log.warn("Consul port (env var: 'CONSUL_PORT') is missing from environment variables. "
+ + "Using default value of 8500"))
+ .getOrElse(8500);
+ }
+
+ private static Option<String> getConsulHost(Map<String, String> environmentVariables) {
+ return environmentVariables.get("CONSUL_HOST")
+ .onEmpty(() -> log.warn("Consul host (env var: 'CONSUL_HOST') (without port) "
+ + "is missing from environment variables."));
+ }
+
+}
diff --git a/src/main/java/org/onap/dcae/controller/EnvProps.java b/src/main/java/org/onap/dcae/controller/EnvProps.java
new file mode 100644
index 00000000..2ee41cc6
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/EnvProps.java
@@ -0,0 +1,70 @@
+/*-
+ * ============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 java.util.Objects;
+
+/**
+ * @author Pawel Szalapski (pawel.szalapski@nokia.com)
+ */
+final class EnvProps {
+
+ final String consulHost;
+ final int consulPort;
+ final String cbsName;
+ final String appName;
+
+ EnvProps(String consulHost, int consulPort, String cbsName, String appName) {
+ this.consulHost = consulHost;
+ this.consulPort = consulPort;
+ this.cbsName = cbsName;
+ this.appName = appName;
+ }
+
+ @Override
+ public String toString() {
+ return "EnvProps{" +
+ "consulHost='" + consulHost + '\'' +
+ ", consulPort=" + consulPort +
+ ", cbsName='" + cbsName + '\'' +
+ ", appName='" + appName + '\'' +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EnvProps envProps = (EnvProps) o;
+ return consulPort == envProps.consulPort &&
+ Objects.equals(consulHost, envProps.consulHost) &&
+ Objects.equals(cbsName, envProps.cbsName) &&
+ Objects.equals(appName, envProps.appName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(consulHost, consulPort, cbsName, appName);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/onap/dcae/controller/FetchDynamicConfig.java b/src/main/java/org/onap/dcae/controller/FetchDynamicConfig.java
deleted file mode 100644
index ed42a5a4..00000000
--- a/src/main/java/org/onap/dcae/controller/FetchDynamicConfig.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * PROJECT
- * ================================================================================
- * Copyright (C) 2017-2018 AT&T Intellectual Property. 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 com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.json.JSONArray;
-import org.json.JSONObject;
-import org.json.JSONTokener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.*;
-import java.util.Map;
-
-public class FetchDynamicConfig {
-
- private static final Logger log = LoggerFactory.getLogger(FetchDynamicConfig.class);
-
- public static String configFile = "/opt/app/KV-Configuration.json";
- public static String retString;
- public static String retCBSString;
- private static String url;
- private static Map<String, String> env;
-
- public FetchDynamicConfig() {
- }
-
- public static void main(String[] args) {
- Boolean areEqual;
- // Call consul api and identify the CBS Service address and port
- getconsul();
- // Construct and invoke CBS API to get application Configuration
- getCBS();
- // Verify if data has changed
- areEqual = verifyConfigChange();
- // If new config then write data returned into configFile for
- // LoadDynamicConfig process
- if (!areEqual) {
- FetchDynamicConfig fc = new FetchDynamicConfig();
- fc.writefile(retCBSString);
- } else {
- log.info("New config pull results identical - " + configFile + " NOT refreshed");
- }
- }
-
- private static void getconsul() {
-
- env = System.getenv();
- for (Map.Entry<String, String> entry : env.entrySet()) {
- log.info(entry.getKey() + ":" + entry.getValue());
- }
-
- if (env.containsKey("CONSUL_HOST") && env.containsKey("CONFIG_BINDING_SERVICE")) {
- // && env.containsKey("HOSTNAME")) {
- log.info(">>>Dynamic configuration to be fetched from ConfigBindingService");
- url = env.get("CONSUL_HOST") + ":8500/v1/catalog/service/" + env.get("CONFIG_BINDING_SERVICE");
-
- retString = executecurl(url);
-
- } else {
- log.info(">>>Static configuration to be used");
- }
-
- }
-
- public static boolean verifyConfigChange() {
-
- boolean areEqual = false;
- // Read current data
- try {
- File f = new File(configFile);
- if (f.exists() && !f.isDirectory()) {
-
- String jsonData = LoadDynamicConfig.readFile(configFile);
- JSONObject jsonObject = new JSONObject(jsonData);
-
- ObjectMapper mapper = new ObjectMapper();
-
- JsonNode tree1 = mapper.readTree(jsonObject.toString());
- JsonNode tree2 = mapper.readTree(retCBSString);
- areEqual = tree1.equals(tree2);
- log.info("Comparison value:" + areEqual);
- } else {
- log.info("First time config file read: " + configFile);
- }
-
- } catch (IOException e) {
- log.error("Comparison with new fetched data failed" + e.getMessage());
-
- }
-
- return areEqual;
-
- }
-
- public static void getCBS() {
-
- env = System.getenv();
- // consul return as array
- JSONTokener temp = new JSONTokener(retString);
- JSONObject cbsjobj = (JSONObject) new JSONArray(temp).get(0);
-
- String urlPart1 = null;
- if (cbsjobj.has("ServiceAddress") && cbsjobj.has("ServicePort")) {
- urlPart1 = cbsjobj.getString("ServiceAddress") + ":" + cbsjobj.getInt("ServicePort");
- }
-
- log.info("CONFIG_BINDING_SERVICE DNS RESOLVED:" + urlPart1);
-
- if (env.containsKey("HOSTNAME")) {
- url = urlPart1 + "/service_component/" + env.get("HOSTNAME");
- retCBSString = executecurl(url);
- } else if (env.containsKey("SERVICE_NAME")) {
- url = urlPart1 + "/service_component/" + env.get("SERVICE_NAME");
- retCBSString = executecurl(url);
- } else {
- log.error("Service name environment variable - HOSTNAME/SERVICE_NAME not found within container ");
- }
-
- }
-
- private static String executecurl(String url) {
-
- String[] command = {"curl", "-v", url};
- ProcessBuilder process = new ProcessBuilder(command);
- Process p;
- String result = null;
- try {
- p = process.start();
- InputStreamReader ipr = new InputStreamReader(p.getInputStream());
- BufferedReader reader = new BufferedReader(ipr);
- StringBuilder builder = new StringBuilder();
- String line;
-
- while ((line = reader.readLine()) != null) {
- builder.append(line);
- }
- result = builder.toString();
- log.info(result);
-
- reader.close();
- ipr.close();
- } catch (IOException e) {
- log.error("error", e);
- e.printStackTrace();
- }
- return result;
-
- }
-
- public void writefile(String retCBSString) {
- log.info("URL to fetch configuration:" + url + " Return String:" + retCBSString);
-
- String indentedretstring = (new JSONObject(retCBSString)).toString(4);
-
- try (FileWriter file = new FileWriter(FetchDynamicConfig.configFile)) {
- file.write(indentedretstring);
-
- log.info("Successfully Copied JSON Object to file " + configFile);
- } catch (IOException e) {
- log.error("Error in writing configuration into file " + configFile + retString + e.getMessage());
- e.printStackTrace();
- }
-
- }
-
-}
diff --git a/src/main/java/org/onap/dcae/controller/LoadDynamicConfig.java b/src/main/java/org/onap/dcae/controller/LoadDynamicConfig.java
deleted file mode 100644
index c1ab80c1..00000000
--- a/src/main/java/org/onap/dcae/controller/LoadDynamicConfig.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * PROJECT
- * ================================================================================
- * Copyright (C) 2017-2018 AT&T Intellectual Property. 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 org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.json.JSONObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-
-public class LoadDynamicConfig {
-
- private static final Logger log = LoggerFactory.getLogger(LoadDynamicConfig.class);
-
- public String propFile = "collector.properties";
- public String configFile = "/opt/app/KV-Configuration.json";
- public String dMaaPOutputFile = "./etc/DmaapConfig.json";
-
- public LoadDynamicConfig() {
-
- }
-
- public static void main(String[] args) {
- Map<String, String> env = System.getenv();
-
- // Check again to ensure new controller deployment related config
- if (env.containsKey("CONSUL_HOST") && env.containsKey("CONFIG_BINDING_SERVICE")
- && env.containsKey("HOSTNAME")) {
-
- try {
-
- LoadDynamicConfig lc = new LoadDynamicConfig();
- String jsonData = readFile(lc.configFile);
- JSONObject jsonObject = new JSONObject(jsonData);
- lc.writeconfig(jsonObject);
-
-
- } catch (Exception e) {
- log.error(e.getLocalizedMessage(), e);
- e.printStackTrace();
-
- }
-
- } else {
- log.info(">>>Static configuration to be used");
- }
-
- }
-
- public static String readFile(String filename) {
- String result = "";
- try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
- StringBuilder sb = new StringBuilder();
- String line = br.readLine();
- while (line != null) {
- sb.append(line);
- line = br.readLine();
- }
- result = sb.toString();
- } catch (Exception e) {
- log.error(e.getLocalizedMessage(), e);
- e.printStackTrace();
- }
- return result;
- }
-
- public void writeconfig(JSONObject jsonObject) {
-
- PropertiesConfiguration conf;
- try {
- conf = new PropertiesConfiguration(propFile);
-
- conf.setEncoding(null);
-
- // update properties based on consul dynamic configuration
- Iterator<?> keys = jsonObject.keys();
-
- while (keys.hasNext()) {
- String key = (String) keys.next();
- // check if any configuration is related to dmaap
- // and write into dmaapconfig.json
- if (key.startsWith("streams_publishes")) {
- // VESCollector only have publish streams
- try (FileWriter file = new FileWriter(dMaaPOutputFile)) {
- String indentedretstring = (new JSONObject(jsonObject.get(key).toString())).toString(4);
- file.write(indentedretstring);
- log.info("Successfully written JSON Object to DmaapConfig.json");
- } catch (IOException e) {
- log.info("Error in writing dmaap configuration into DmaapConfig.json", e);
- }
- } else {
- conf.setProperty(key, jsonObject.get(key).toString());
- }
-
- }
- conf.save();
- } catch (ConfigurationException e) {
- log.error(e.getLocalizedMessage(), e);
- e.printStackTrace();
- }
- }
-
-}
diff --git a/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java b/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java
new file mode 100644
index 00000000..c5ee9d86
--- /dev/null
+++ b/src/main/java/org/onap/dcae/controller/PreAppStartupConfigUpdater.java
@@ -0,0 +1,49 @@
+/*-
+ * ============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.commonFunction.event.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();
+ }
+}