diff options
author | Guangrong Fu <fu.guangrong@zte.com.cn> | 2021-12-01 14:22:37 +0800 |
---|---|---|
committer | Guangrong Fu <fu.guangrong@zte.com.cn> | 2021-12-01 15:25:34 +0800 |
commit | 5cc6fc1a762c547f420ce281deac69f02f6c2b83 (patch) | |
tree | f59492080a97a46699cffa634a19423e0050f06d /rulemgt/src/main/java/org | |
parent | 2eedf476653c9054d946332a15b62d465619abd4 (diff) |
Change rule retrieval from CBS to ConfigMap
Issue-ID: HOLMES-488
Signed-off-by: Guangrong Fu <fu.guangrong@zte.com.cn>
Change-Id: I89f4d47b9b2e0f1c9c9d32083a146d54d0000c5d
Diffstat (limited to 'rulemgt/src/main/java/org')
3 files changed, 197 insertions, 11 deletions
diff --git a/rulemgt/src/main/java/org/onap/holmes/rulemgt/RuleActiveApp.java b/rulemgt/src/main/java/org/onap/holmes/rulemgt/RuleActiveApp.java index f77b909..a9a78c8 100644 --- a/rulemgt/src/main/java/org/onap/holmes/rulemgt/RuleActiveApp.java +++ b/rulemgt/src/main/java/org/onap/holmes/rulemgt/RuleActiveApp.java @@ -17,13 +17,10 @@ package org.onap.holmes.rulemgt; import io.dropwizard.setup.Environment; -import org.onap.holmes.common.config.MicroServiceConfig; +import org.onap.holmes.common.ConfigFileScanner; import org.onap.holmes.common.dropwizard.ioc.bundle.IOCApplication; -import org.onap.holmes.common.utils.CommonUtils; import org.onap.holmes.common.utils.transactionid.TransactionIdFilter; -import org.onap.holmes.rulemgt.dcae.DcaeConfigurationPolling; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.onap.holmes.rulemgt.dcae.ConfigFileScanningTask; import javax.servlet.DispatcherType; import java.util.EnumSet; @@ -41,12 +38,10 @@ public class RuleActiveApp extends IOCApplication<RuleAppConfig> { public void run(RuleAppConfig configuration, Environment environment) throws Exception { super.run(configuration, environment); - if (!"1".equals(System.getenv("TESTING"))) { - ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); - service.scheduleAtFixedRate( - new DcaeConfigurationPolling(CommonUtils.getEnv(MicroServiceConfig.HOSTNAME)), 0, - DcaeConfigurationPolling.POLLING_PERIOD, TimeUnit.MILLISECONDS); - } + ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); + service.scheduleAtFixedRate( + new ConfigFileScanningTask(new ConfigFileScanner()), 60L, + ConfigFileScanningTask.POLLING_PERIOD, TimeUnit.SECONDS); environment.servlets().addFilter("customFilter", new TransactionIdFilter()).addMappingForUrlPatterns(EnumSet .allOf(DispatcherType.class), true, "/*"); diff --git a/rulemgt/src/main/java/org/onap/holmes/rulemgt/dcae/ConfigFileScanningTask.java b/rulemgt/src/main/java/org/onap/holmes/rulemgt/dcae/ConfigFileScanningTask.java new file mode 100644 index 0000000..9f7b89f --- /dev/null +++ b/rulemgt/src/main/java/org/onap/holmes/rulemgt/dcae/ConfigFileScanningTask.java @@ -0,0 +1,190 @@ +/** + * Copyright 2021 ZTE Corporation. + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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 org.onap.holmes.rulemgt.dcae; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.commons.lang.StringUtils; +import org.onap.holmes.common.ConfigFileScanner; +import org.onap.holmes.common.utils.FileUtils; +import org.onap.holmes.common.utils.JerseyClient; +import org.onap.holmes.rulemgt.bean.request.RuleCreateRequest; +import org.onap.holmes.rulemgt.bean.response.RuleQueryListResponse; +import org.onap.holmes.rulemgt.bean.response.RuleResult4API; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import java.io.File; +import java.nio.file.Paths; +import java.util.*; + +public class ConfigFileScanningTask implements Runnable { + final public static long POLLING_PERIOD = 30L; + final private static Logger LOGGER = LoggerFactory.getLogger(ConfigFileScanningTask.class); + final private static long FILE_SIZE_LMT = 1024 * 1024 * 10; // 10MB + final private Map<String, String> configInEffect = new HashMap(); // Contents for configInEffect are <closedControlLoop>:<ruleContents> pairs. + private String configFile = "/opt/hrmrules/index.json"; + private ConfigFileScanner configFileScanner; + private String url = "https://127.0.0.1:9101/api/holmes-rule-mgmt/v1/rule"; + + public ConfigFileScanningTask(ConfigFileScanner configFileScanner) { + this.configFileScanner = configFileScanner; + } + + @Override + public void run() { + if (null == configFileScanner) { + configFileScanner = new ConfigFileScanner(); + } + Map<String, String> newConfig = extractConfigItems(configFileScanner.scan(configFile)); + + List<RuleResult4API> deployedRules = getExistingRules(); + + // deal with newly added rules + final Set<String> existingKeys = new HashSet(configInEffect.keySet()); + final Set<String> newKeys = new HashSet(newConfig.keySet()); + newKeys.stream() + .filter(key -> !existingKeys.contains(key)) + .forEach(key -> { + if (deployRule(key, newConfig.get(key))) { + configInEffect.put(key, newConfig.get(key)); + LOGGER.info("Rule '{}' has been deployed.", key); + } + }); + + // deal with removed rules + existingKeys.stream().filter(key -> !newKeys.contains(key)).forEach(key -> { + if (deleteRule(find(deployedRules, key))) { + configInEffect.remove(key); + LOGGER.info("Rule '{}' has been removed.", key); + } + }); + + // deal with changed rules + existingKeys.stream().filter(key -> newKeys.contains(key)).forEach(key -> { + if (changed(configInEffect.get(key), newConfig.get(key))) { + if (deleteRule(find(deployedRules, key))) { + configInEffect.remove(key); + deployRule(key, newConfig.get(key)); + configInEffect.put(key, newConfig.get(key)); + LOGGER.info("Rule '{}' has been updated.", key); + } + } + }); + } + + private Map<String, String> extractConfigItems(Map<String, String> configFiles) { + Map<String, String> ret = new HashMap(); + for (Map.Entry entry : configFiles.entrySet()) { + JsonArray ja = JsonParser.parseString(entry.getValue().toString()).getAsJsonArray(); + Iterator<JsonElement> iterator = ja.iterator(); + while (iterator.hasNext()) { + JsonObject jo = iterator.next().getAsJsonObject(); + String contents = readFile(jo.get("file").getAsString()); + if (StringUtils.isNotBlank(contents)) { + ret.put(jo.get("closedControlLoopName").getAsString(), contents); + } + } + } + return ret; + } + + private String normalizePath(String path) { + if (!path.startsWith("/")) { + return Paths.get(new File(configFile).getParent(), path).toString(); + } + return path; + } + private String readFile(String path) { + String finalPath = normalizePath(path); + File file = new File(finalPath); + if (file.exists() && !file.isDirectory() && file.length() <= FILE_SIZE_LMT) { + return FileUtils.readTextFile(finalPath); + } else { + LOGGER.warn("The file {} does not exist or it is a directory or it is too large to load.", finalPath); + } + return null; + } + + private RuleResult4API find(final List<RuleResult4API> rules, String clName) { + for (RuleResult4API rule : rules) { + if (rule.getLoopControlName().equals(clName)) { + return rule; + } + } + return null; + } + + private boolean changed(String con1, String con2) { + // if either of the arguments is null, consider it as invalid and unchanged + if (con1 == null || con2 == null) { + return false; + } + + if (!con1.replaceAll("\\s", StringUtils.EMPTY) + .equals(con2.replaceAll("\\s", StringUtils.EMPTY))) { + return true; + } + + return false; + } + + private List<RuleResult4API> getExistingRules() { + RuleQueryListResponse ruleQueryListResponse = JerseyClient.newInstance().get(url, RuleQueryListResponse.class); + List<RuleResult4API> deployedRules = Collections.EMPTY_LIST; + if (null != ruleQueryListResponse) { + deployedRules = ruleQueryListResponse.getCorrelationRules(); + } + return deployedRules; + } + + private boolean deployRule(String clName, String contents) { + RuleCreateRequest ruleCreateRequest = getRuleCreateRequest(clName, contents); + if (JerseyClient.newInstance().header("Accept", MediaType.APPLICATION_JSON) + .put(url, Entity.json(ruleCreateRequest)) == null) { + LOGGER.error("Failed to deploy rule: {}.", clName); + return false; + } + return true; + } + + private RuleCreateRequest getRuleCreateRequest(String clName, String contents) { + RuleCreateRequest ruleCreateRequest = new RuleCreateRequest(); + ruleCreateRequest.setLoopControlName(clName); + ruleCreateRequest.setRuleName(clName); + ruleCreateRequest.setContent(contents); + ruleCreateRequest.setDescription(""); + ruleCreateRequest.setEnabled(1); + return ruleCreateRequest; + } + + private boolean deleteRule(RuleResult4API rule) { + if (rule == null) { + LOGGER.info("No rule found, nothing to delete."); + return false; + } + if (null == JerseyClient.newInstance().delete(url + "/" + rule.getRuleId())) { + LOGGER.warn("Failed to delete rule, the rule id is: {}", rule.getRuleId()); + return false; + } + return true; + } +} diff --git a/rulemgt/src/main/java/org/onap/holmes/rulemgt/dcae/DcaeConfigurationPolling.java b/rulemgt/src/main/java/org/onap/holmes/rulemgt/dcae/DcaeConfigurationPolling.java index f07d8ac..8049e8f 100644 --- a/rulemgt/src/main/java/org/onap/holmes/rulemgt/dcae/DcaeConfigurationPolling.java +++ b/rulemgt/src/main/java/org/onap/holmes/rulemgt/dcae/DcaeConfigurationPolling.java @@ -30,6 +30,7 @@ import javax.ws.rs.core.MediaType; import java.util.List; @Slf4j +@Deprecated public class DcaeConfigurationPolling implements Runnable { public static final long POLLING_PERIOD = 30 * 1000L; |