Code improvement for pending sonar issues
[cli.git] / framework / src / main / java / org / onap / cli / fw / store / OnapCommandExecutionStore.java
1 /*
2  * Copyright 2019 Huawei Technologies Co., Ltd.
3  *
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  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.cli.fw.store;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.file.Files;
22 import java.nio.file.Path;
23 import java.nio.file.Paths;
24 import java.text.SimpleDateFormat;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.Map;
30 import java.util.TimeZone;
31
32 import org.apache.commons.io.FileUtils;
33 import org.onap.cli.fw.conf.OnapCommandConfig;
34 import org.onap.cli.fw.conf.OnapCommandConstants;
35 import org.onap.cli.fw.error.OnapCommandExecutionFailed;
36 import org.onap.cli.fw.error.OnapCommandExecutionNotFound;
37 import org.onap.cli.fw.utils.ProcessRunner;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 public class OnapCommandExecutionStore {
42     private static Logger log = LoggerFactory.getLogger(OnapCommandExecutionStore.class);
43
44     private static boolean storeReady = false; // NOSONAR
45     private static final String REQUEST_ID = "requestId";
46     private static final String EXECUTION_ID = "executionId";
47     private static final String INPUT = "input";
48     private static final String STDOUT = "stdout";
49     private static final String STDERR = "stderr";
50     private static final String DEBUG = "debug";
51     private static final String IN_PROGRESS = "in-progress";
52     private static final String OUTPUT = "output";
53     private static final String ERROR = "error";
54     private static final String COMPLETED = "completed";
55     private static final String FAILED = "failed";
56     private static final String EXECUTIONID = "execution-id";
57     private static final String REQUESTID = "request-id";
58
59     private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
60
61     private static final String SEPARATOR = "__";
62
63     private enum SearchMode {
64         FIND,
65         FILE //for developer mode
66
67
68     }
69
70     private static SearchMode searchMode = SearchMode.FILE;
71     static {
72         String mode = OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_EXECUTION_SEARCH_MODE);
73         if (mode.equalsIgnoreCase(SearchMode.FIND.name()))
74             searchMode = SearchMode.FIND;
75     }
76
77     public static class ExecutionStoreContext {
78         private String requestId;
79         private String executionId;
80         private String profile;
81         private String storePath;
82         public String getExecutionId() {
83             return executionId;
84         }
85         public ExecutionStoreContext setExecutionId(String executionId) {
86             this.executionId = executionId;
87             return this;
88         }
89         public String getStorePath() {
90             return storePath;
91         }
92         public ExecutionStoreContext setStorePath(String storePath) {
93             this.storePath = storePath;
94             return this;
95         }
96         public String getRequestId() {
97             return requestId;
98         }
99         public ExecutionStoreContext setRequestId(String requestId) {
100             this.requestId = requestId;
101              return this;
102         }
103         public String getProfile() {
104             return profile;
105         }
106         public void setProfile(String profile) {
107             this.profile = profile;
108         }
109     }
110
111     public static class Execution {
112         private String id;
113         private String requestId;
114         private String status;
115         private String startTime;
116         private String endTime;
117         private String input;
118         private String output;
119         private String profile;
120         private String command;
121         private String product;
122         private String service;
123
124         public String getInput() {
125             return input;
126         }
127         public void setInput(String input) {
128             this.input = input;
129         }
130         public String getOutput() {
131             return output;
132         }
133         public void setOutput(String output) {
134             this.output = output;
135         }
136         public String getProfile() {
137             return profile;
138         }
139         public void setProfile(String profile) {
140             this.profile = profile;
141         }
142         public String getCommand() {
143             return command;
144         }
145         public void setCommand(String command) {
146             this.command = command;
147         }
148         public String getProduct() {
149             return product;
150         }
151         public void setProduct(String product) {
152             this.product = product;
153         }
154         public String getService() {
155             return service;
156         }
157         public void setService(String service) {
158             this.service = service;
159         }
160         public String getId() {
161             return id;
162         }
163         public void setId(String id) {
164             this.id = id;
165         }
166         public String getEndTime() {
167             return endTime;
168         }
169         public void setEndTime(String endTime) {
170             this.endTime = endTime;
171         }
172         public void setStartTime(String timeOfExecution) {
173             this.startTime = timeOfExecution;
174         }
175         public String getStartTime() {
176             return startTime;
177         }
178         public String getStatus() {
179             return status;
180         }
181         public void setStatus(String status) {
182             this.status = status;
183         }
184         public String getRequestId() {
185             return requestId;
186         }
187         public void setRequestId(String requestId) {
188             this.requestId = requestId;
189         }
190     }
191
192     static {
193         try {
194             FileUtils.forceMkdir(new File(getBasePath()));
195             storeReady = true;
196         } catch (IOException e) {
197             log.error("Failed to create the data store results");
198         }
199     }
200
201     private static OnapCommandExecutionStore store = null;
202
203     private OnapCommandExecutionStore() {
204         this.dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
205     }
206
207     public static OnapCommandExecutionStore getStore() {
208         if (store == null) {
209             store = new OnapCommandExecutionStore();
210         }
211
212         return store;
213     }
214
215     private static String getBasePath() {
216         return OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_DATA_DIR) +
217                 File.separator + "executions";
218     }
219
220     public ExecutionStoreContext storeExectutionStart(
221             String requestId, String product, String service, String cmd, String profile, String input) {
222
223         ExecutionStoreContext context = new ExecutionStoreContext();
224         context.setRequestId(requestId);
225
226         String executionId = requestId + "-" + System.currentTimeMillis();
227         context.setExecutionId(executionId);
228
229         String storePath = getBasePath() + File.separator + executionId + SEPARATOR + product +
230                 SEPARATOR + service +
231                 SEPARATOR + cmd +
232                 SEPARATOR + (profile != null ? profile : "" );
233
234         try {
235             File dir = new File(storePath);
236             FileUtils.forceMkdir(dir);
237             context.setStorePath(dir.getAbsolutePath());
238
239             if (product != null)
240                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OnapCommandConstants.INFO_PRODUCT), product);
241             if (service != null)
242                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OnapCommandConstants.INFO_SERVICE), service);
243             if (cmd != null)
244                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OnapCommandConstants.RPC_CMD), cmd);
245
246             FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + REQUEST_ID), requestId);
247
248             FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + EXECUTION_ID), executionId);
249
250             if (input != null)
251                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + INPUT), input);
252             if (profile != null) {
253                 context.setProfile(profile);
254                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OnapCommandConstants.RPC_PROFILE), profile);
255             }
256
257             FileUtils.touch(new File(context.getStorePath() + File.separator + STDOUT));
258             FileUtils.touch(new File(context.getStorePath() + File.separator + STDERR));
259             FileUtils.touch(new File(context.getStorePath() + File.separator + DEBUG));
260
261             FileUtils.touch(new File(context.getStorePath() + File.separator + IN_PROGRESS));
262         } catch (IOException e) {
263             log.error("Failed to store the execution start details {}", storePath);
264         }
265
266         return context;
267     }
268
269     public void storeExectutionEnd(
270             ExecutionStoreContext context,
271             String output, String error, String debug, boolean passed) {
272
273         try {
274             if (output != null)
275                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output);
276             if (error != null)
277                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + ERROR), error);
278             if (debug != null)
279                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + DEBUG), debug);
280             if (passed)
281                 FileUtils.touch(new File(context.getStorePath() + File.separator + COMPLETED));
282             else
283                 FileUtils.touch(new File(context.getStorePath() + File.separator + FAILED));
284             Path path= Paths.get(context.getStorePath() + File.separator + IN_PROGRESS);
285             try {
286                 Files.delete(path);
287             } catch (IOException e) {
288                 log.error("Failed to delete "+ context.getStorePath() + File.separator + IN_PROGRESS);
289             }
290         } catch (IOException e) {
291             log.error("Failed to store the execution end details {}", context.storePath);
292         }
293     }
294
295     public void storeExectutionProgress(
296             ExecutionStoreContext context,
297             String output, String error, String debug) {
298
299         try {
300             if (output != null)
301                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output);
302             if (error != null)
303                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + ERROR), error);
304             if (debug != null)
305                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + DEBUG), debug);
306         } catch (IOException e) {
307             log.error("Failed to store the execution end details {}", context.storePath);
308         }
309     }
310
311     public void storeExectutionDebug(
312             ExecutionStoreContext context,
313             String debug) {
314
315         try {
316             if (debug != null) {
317                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + DEBUG), debug);
318             }
319         } catch (IOException e) {
320             log.error("Failed to store the execution debug details {}", context.storePath);
321         }
322     }
323
324     public void storeExectutionOutput(
325             ExecutionStoreContext context,
326             String output) {
327
328         try {
329             if (output != null) {
330                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output);
331             }
332         } catch (IOException e) {
333             log.error("Failed to store the execution output details {}", context.storePath);
334         }
335     }
336     public List<OnapCommandExecutionStore.Execution> listExecutions(Map<String, String> search) throws OnapCommandExecutionFailed {
337         List <OnapCommandExecutionStore.Execution> list = new ArrayList<>();
338
339         try {
340             List <String> dirs = new ArrayList<>();
341             if (System.getProperty("os.name").toLowerCase().startsWith("windows") || searchMode.equals(SearchMode.FILE)) {
342                 for (File f: new File(getBasePath()).listFiles()) {
343                     if(search.containsKey(EXECUTIONID)) {
344                         if (f.getName().startsWith(search.get(EXECUTIONID)))
345                                 dirs.add(f.getAbsolutePath());
346
347                         continue;
348                     }
349
350                     if(search.containsKey(REQUESTID)) {
351                         if (f.getName().startsWith(search.get(REQUESTID)))
352                                 dirs.add(f.getAbsolutePath());
353
354                     }
355
356                     else
357                         dirs.add(f.getAbsolutePath());
358                 }
359             } else {
360                 //find results -type d -newermt '2019-02-11 10:00:00' ! -newermt '2019-02-11 15:10:00' -name "*__*__profile-list*"
361                 //find 'results' -type d -newermt '2019-02-11T10:00:00.000' ! -newermt '2019-02-11T15:10:00.000' -name "*__*__profile*"
362
363                 StringBuilder searchString = new StringBuilder("find " + new File(getBasePath()).getAbsolutePath() + " -type d ");
364
365                 String startTime = search.get("startTime");
366                 if (startTime != null) {
367                     searchString.append(" -newermt " + startTime);
368                 }
369
370                 String endTime = search.get("endTime");
371                 if (endTime != null) {
372                     searchString.append(" ! -newermt " + endTime);
373                 }
374
375                 searchString.append(" -name \"");
376
377                 if(search.containsKey(EXECUTIONID)) {
378                     searchString.append(search.get(EXECUTIONID));
379                 } else if(search.containsKey(REQUESTID)) {
380                     searchString.append(search.get(REQUESTID) + "*");
381                 } else {
382                     searchString.append("*");
383                 }
384
385                 for (String term: Arrays.asList("product", "service", "command", "profile")) {
386                     searchString.append("__");
387                     if (search.get(term) != null && !search.get(term).isEmpty()) {
388                         searchString.append(search.get(term));
389                     } else {
390                         searchString.append("*");
391                     }
392                 }
393                 if (!searchString.toString().endsWith("*"))
394                     searchString.append("*");
395
396                 searchString.append("\"");
397
398                 ProcessRunner pr = new ProcessRunner(new String [] {searchString.toString()}, null, ".");
399                 pr.setTimeout(10000);
400                 pr.overrideToUnix();
401                 pr.run();
402                 if (pr.getExitCode() != 0) {
403                     throw new OnapCommandExecutionFailed("System failed to search the executions with error " + pr.getError());
404                 }
405
406                 if (!pr.getOutput().trim().isEmpty())
407                     dirs = Arrays.asList(pr.getOutput().split("\\r?\\n"));
408             }
409
410             for (String dir: dirs) {
411                 list.add(this.makeExecution(dir));
412             }
413         } catch (Exception e) {
414             throw new OnapCommandExecutionFailed(e, "Failed to search the executions");
415         }
416
417         return list;
418     }
419
420     private Execution makeExecution(String executionStorePath) throws IOException {
421         OnapCommandExecutionStore.Execution exectuion = new OnapCommandExecutionStore.Execution();
422         if (new File(executionStorePath + File.separator + REQUEST_ID).exists())
423             exectuion.setRequestId(FileUtils.readFileToString(new File(executionStorePath + File.separator + REQUEST_ID)));
424         if (new File(executionStorePath + File.separator + EXECUTION_ID).exists())
425             exectuion.setId(FileUtils.readFileToString(new File(executionStorePath + File.separator + EXECUTION_ID)));
426         exectuion.setProduct(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.INFO_PRODUCT)));
427         exectuion.setService(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.INFO_SERVICE)));
428         exectuion.setCommand(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.RPC_CMD)));
429         if (new File(executionStorePath + File.separator + OnapCommandConstants.RPC_PROFILE).exists())
430             exectuion.setProfile(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.RPC_PROFILE)));
431
432         exectuion.setInput(FileUtils.readFileToString(new File(executionStorePath + File.separator + INPUT)));
433         exectuion.setStartTime(dateFormatter.format(new File(executionStorePath + File.separator + INPUT).lastModified()));
434
435         if (new File(executionStorePath + File.separator + IN_PROGRESS).exists()) {
436             exectuion.setStatus(IN_PROGRESS);
437         } else if (new File(executionStorePath + File.separator + COMPLETED).exists()) {
438             exectuion.setStatus(COMPLETED);
439             if (new File(executionStorePath + File.separator + OUTPUT).exists()) {
440                 exectuion.setOutput(FileUtils.readFileToString(new File(executionStorePath + File.separator + OUTPUT)));
441                 exectuion.setEndTime(dateFormatter.format(new File(executionStorePath + File.separator + OUTPUT).lastModified()));
442             }
443         } else if (new File(executionStorePath + File.separator + FAILED).exists()) {
444             exectuion.setStatus(FAILED);
445             if (new File(executionStorePath + File.separator + ERROR).exists()) {
446                 exectuion.setOutput(FileUtils.readFileToString(new File(executionStorePath + File.separator + ERROR)));
447                 exectuion.setEndTime(dateFormatter.format(new File(executionStorePath + File.separator + ERROR).lastModified()));
448             }
449         }
450
451         return exectuion;
452     }
453
454     private File getExecutionDir(String executionId) throws OnapCommandExecutionNotFound {
455         File []f =  new File(getBasePath()).listFiles((dir, name) -> {
456             if (name.startsWith(executionId)) return true;
457             return false;
458         });
459
460         if (f.length == 0) {
461             throw new OnapCommandExecutionNotFound(executionId);
462         }
463
464         return f[0];
465     }
466
467     public String showExecutionOut(String executionId) throws OnapCommandExecutionNotFound {
468         try {
469             return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + "stdout"));
470         } catch (IOException e) {
471             return "";
472         }
473     }
474
475     public String showExecutionErr(String executionId) throws OnapCommandExecutionNotFound {
476         try {
477             return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + "stderr"));
478         } catch (IOException e) {
479             return "";
480         }
481     }
482
483     public String showExecutionDebug(String executionId) throws OnapCommandExecutionNotFound {
484         try {
485             return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + DEBUG));
486         } catch (IOException e) {
487             return "";
488         }
489     }
490     public Execution getExecution(String executionId) throws OnapCommandExecutionNotFound, OnapCommandExecutionFailed {
491         try {
492             return this.makeExecution(this.getExecutionDir(executionId).getAbsolutePath());
493         } catch (IOException e) {
494             throw new OnapCommandExecutionFailed(e, "Failed to retrieve the execution");
495         }
496     }
497 }