Change rule retrieval from CBS to ConfigMap
[holmes/rule-management.git] / rulemgt / src / main / java / org / onap / holmes / rulemgt / dcae / ConfigFileScanningTask.java
1 /**
2  * Copyright 2021 ZTE Corporation.
3  * <p>
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * <p>
8  * http://www.apache.org/licenses/LICENSE-2.0
9  * <p>
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.holmes.rulemgt.dcae;
18
19 import com.google.gson.JsonArray;
20 import com.google.gson.JsonElement;
21 import com.google.gson.JsonObject;
22 import com.google.gson.JsonParser;
23 import org.apache.commons.lang.StringUtils;
24 import org.onap.holmes.common.ConfigFileScanner;
25 import org.onap.holmes.common.utils.FileUtils;
26 import org.onap.holmes.common.utils.JerseyClient;
27 import org.onap.holmes.rulemgt.bean.request.RuleCreateRequest;
28 import org.onap.holmes.rulemgt.bean.response.RuleQueryListResponse;
29 import org.onap.holmes.rulemgt.bean.response.RuleResult4API;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import javax.ws.rs.client.Entity;
34 import javax.ws.rs.core.MediaType;
35 import java.io.File;
36 import java.nio.file.Paths;
37 import java.util.*;
38
39 public class ConfigFileScanningTask implements Runnable {
40     final public static long POLLING_PERIOD = 30L;
41     final private static Logger LOGGER = LoggerFactory.getLogger(ConfigFileScanningTask.class);
42     final private static long FILE_SIZE_LMT = 1024 * 1024 * 10; // 10MB
43     final private Map<String, String> configInEffect = new HashMap(); // Contents for configInEffect are <closedControlLoop>:<ruleContents> pairs.
44     private String configFile = "/opt/hrmrules/index.json";
45     private ConfigFileScanner configFileScanner;
46     private String url = "https://127.0.0.1:9101/api/holmes-rule-mgmt/v1/rule";
47
48     public ConfigFileScanningTask(ConfigFileScanner configFileScanner) {
49         this.configFileScanner = configFileScanner;
50     }
51
52     @Override
53     public void run() {
54         if (null == configFileScanner) {
55             configFileScanner = new ConfigFileScanner();
56         }
57         Map<String, String> newConfig = extractConfigItems(configFileScanner.scan(configFile));
58
59         List<RuleResult4API> deployedRules = getExistingRules();
60
61         // deal with newly added rules
62         final Set<String> existingKeys = new HashSet(configInEffect.keySet());
63         final Set<String> newKeys = new HashSet(newConfig.keySet());
64         newKeys.stream()
65                 .filter(key -> !existingKeys.contains(key))
66                 .forEach(key -> {
67                     if (deployRule(key, newConfig.get(key))) {
68                         configInEffect.put(key, newConfig.get(key));
69                         LOGGER.info("Rule '{}' has been deployed.", key);
70                     }
71                 });
72
73         // deal with removed rules
74         existingKeys.stream().filter(key -> !newKeys.contains(key)).forEach(key -> {
75             if (deleteRule(find(deployedRules, key))) {
76                 configInEffect.remove(key);
77                 LOGGER.info("Rule '{}' has been removed.", key);
78             }
79         });
80
81         // deal with changed rules
82         existingKeys.stream().filter(key -> newKeys.contains(key)).forEach(key -> {
83             if (changed(configInEffect.get(key), newConfig.get(key))) {
84                 if (deleteRule(find(deployedRules, key))) {
85                     configInEffect.remove(key);
86                     deployRule(key, newConfig.get(key));
87                     configInEffect.put(key, newConfig.get(key));
88                     LOGGER.info("Rule '{}' has been updated.", key);
89                 }
90             }
91         });
92     }
93
94     private Map<String, String> extractConfigItems(Map<String, String> configFiles) {
95         Map<String, String> ret = new HashMap();
96         for (Map.Entry entry : configFiles.entrySet()) {
97             JsonArray ja = JsonParser.parseString(entry.getValue().toString()).getAsJsonArray();
98             Iterator<JsonElement> iterator = ja.iterator();
99             while (iterator.hasNext()) {
100                 JsonObject jo = iterator.next().getAsJsonObject();
101                 String contents = readFile(jo.get("file").getAsString());
102                 if (StringUtils.isNotBlank(contents)) {
103                     ret.put(jo.get("closedControlLoopName").getAsString(), contents);
104                 }
105             }
106         }
107         return ret;
108     }
109
110     private String normalizePath(String path) {
111         if (!path.startsWith("/")) {
112             return Paths.get(new File(configFile).getParent(), path).toString();
113         }
114         return path;
115     }
116     private String readFile(String path) {
117         String finalPath = normalizePath(path);
118         File file = new File(finalPath);
119         if (file.exists() && !file.isDirectory() && file.length() <= FILE_SIZE_LMT) {
120             return FileUtils.readTextFile(finalPath);
121         } else {
122             LOGGER.warn("The file {} does not exist or it is a directory or it is too large to load.", finalPath);
123         }
124         return null;
125     }
126
127     private RuleResult4API find(final List<RuleResult4API> rules, String clName) {
128         for (RuleResult4API rule : rules) {
129             if (rule.getLoopControlName().equals(clName)) {
130                 return rule;
131             }
132         }
133         return null;
134     }
135
136     private boolean changed(String con1, String con2) {
137         // if either of the arguments is null, consider it as invalid and unchanged
138         if (con1 == null || con2 == null) {
139             return false;
140         }
141
142         if (!con1.replaceAll("\\s", StringUtils.EMPTY)
143                 .equals(con2.replaceAll("\\s", StringUtils.EMPTY))) {
144             return true;
145         }
146
147         return false;
148     }
149
150     private List<RuleResult4API> getExistingRules() {
151         RuleQueryListResponse ruleQueryListResponse = JerseyClient.newInstance().get(url, RuleQueryListResponse.class);
152         List<RuleResult4API> deployedRules = Collections.EMPTY_LIST;
153         if (null != ruleQueryListResponse) {
154             deployedRules = ruleQueryListResponse.getCorrelationRules();
155         }
156         return deployedRules;
157     }
158
159     private boolean deployRule(String clName, String contents) {
160         RuleCreateRequest ruleCreateRequest = getRuleCreateRequest(clName, contents);
161         if (JerseyClient.newInstance().header("Accept", MediaType.APPLICATION_JSON)
162                 .put(url, Entity.json(ruleCreateRequest)) == null) {
163             LOGGER.error("Failed to deploy rule: {}.", clName);
164             return false;
165         }
166         return true;
167     }
168
169     private RuleCreateRequest getRuleCreateRequest(String clName, String contents) {
170         RuleCreateRequest ruleCreateRequest = new RuleCreateRequest();
171         ruleCreateRequest.setLoopControlName(clName);
172         ruleCreateRequest.setRuleName(clName);
173         ruleCreateRequest.setContent(contents);
174         ruleCreateRequest.setDescription("");
175         ruleCreateRequest.setEnabled(1);
176         return ruleCreateRequest;
177     }
178
179     private boolean deleteRule(RuleResult4API rule) {
180         if (rule == null) {
181             LOGGER.info("No rule found, nothing to delete.");
182             return false;
183         }
184         if (null == JerseyClient.newInstance().delete(url + "/" + rule.getRuleId())) {
185             LOGGER.warn("Failed to delete rule, the rule id is: {}", rule.getRuleId());
186             return false;
187         }
188         return true;
189     }
190 }