Merge "removed block of commented-out lines of code"
[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             deleteFile(context, path);
286         } catch (IOException e) {
287             log.error("Failed to store the execution end details {}", context.storePath);
288         }
289     }
290
291     private void deleteFile(ExecutionStoreContext context, Path path){
292         try {
293             Files.delete(path);
294         } catch (IOException e) {
295             String contextPath = context.getStorePath() + File.separator + IN_PROGRESS;
296             log.error("Failed to delete {}", contextPath);
297         }
298     }
299
300     public void storeExectutionProgress(
301             ExecutionStoreContext context,
302             String output, String error, String debug) {
303
304         try {
305             if (output != null)
306                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output);
307             if (error != null)
308                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + ERROR), error);
309             if (debug != null)
310                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + DEBUG), debug);
311         } catch (IOException e) {
312             log.error("Failed to store the execution end details {}", context.storePath);
313         }
314     }
315
316     public void storeExectutionDebug(
317             ExecutionStoreContext context,
318             String debug) {
319
320         try {
321             if (debug != null) {
322                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + DEBUG), debug);
323             }
324         } catch (IOException e) {
325             log.error("Failed to store the execution debug details {}", context.storePath);
326         }
327     }
328
329     public void storeExectutionOutput(
330             ExecutionStoreContext context,
331             String output) {
332
333         try {
334             if (output != null) {
335                 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output);
336             }
337         } catch (IOException e) {
338             log.error("Failed to store the execution output details {}", context.storePath);
339         }
340     }
341     public List<OnapCommandExecutionStore.Execution> listExecutions(Map<String, String> search) throws OnapCommandExecutionFailed {
342         List <OnapCommandExecutionStore.Execution> list = new ArrayList<>();
343
344         try {
345             List <String> dirs = new ArrayList<>();
346             if (System.getProperty("os.name").toLowerCase().startsWith("windows") || searchMode.equals(SearchMode.FILE)) {
347                 for (File f: new File(getBasePath()).listFiles()) {
348                     if(search.containsKey(EXECUTIONID)) {
349                         if (f.getName().startsWith(search.get(EXECUTIONID)))
350                                 dirs.add(f.getAbsolutePath());
351
352                         continue;
353                     }
354
355                     if(search.containsKey(REQUESTID)) {
356                         if (f.getName().startsWith(search.get(REQUESTID)))
357                                 dirs.add(f.getAbsolutePath());
358
359                     }
360
361                     else
362                         dirs.add(f.getAbsolutePath());
363                 }
364             } else {
365                 //find results -type d -newermt '2019-02-11 10:00:00' ! -newermt '2019-02-11 15:10:00' -name "*__*__profile-list*"
366                 //find 'results' -type d -newermt '2019-02-11T10:00:00.000' ! -newermt '2019-02-11T15:10:00.000' -name "*__*__profile*"
367
368                 StringBuilder searchString = new StringBuilder("find " + new File(getBasePath()).getAbsolutePath() + " -type d ");
369
370                 String startTime = search.get("startTime");
371                 if (startTime != null) {
372                     searchString.append(" -newermt " + startTime);
373                 }
374
375                 String endTime = search.get("endTime");
376                 if (endTime != null) {
377                     searchString.append(" ! -newermt " + endTime);
378                 }
379
380                 searchString.append(" -name \"");
381
382                 if(search.containsKey(EXECUTIONID)) {
383                     searchString.append(search.get(EXECUTIONID));
384                 } else if(search.containsKey(REQUESTID)) {
385                     searchString.append(search.get(REQUESTID) + "*");
386                 } else {
387                     searchString.append("*");
388                 }
389
390                 for (String term: Arrays.asList("product", "service", "command", "profile")) {
391                     searchString.append("__");
392                     if (search.get(term) != null && !search.get(term).isEmpty()) {
393                         searchString.append(search.get(term));
394                     } else {
395                         searchString.append("*");
396                     }
397                 }
398                 if (!searchString.toString().endsWith("*"))
399                     searchString.append("*");
400
401                 searchString.append("\"");
402
403                 ProcessRunner pr = new ProcessRunner(new String [] {searchString.toString()}, null, ".");
404                 pr.setTimeout(10000);
405                 pr.overrideToUnix();
406                 pr.run();
407                 if (pr.getExitCode() != 0) {
408                     throw new OnapCommandExecutionFailed("System failed to search the executions with error " + pr.getError());
409                 }
410
411                 if (!pr.getOutput().trim().isEmpty())
412                     dirs = Arrays.asList(pr.getOutput().split("\\r?\\n"));
413             }
414
415             for (String dir: dirs) {
416                 list.add(this.makeExecution(dir));
417             }
418         } catch (Exception e) {// NOSONAR
419             throw new OnapCommandExecutionFailed(e, "Failed to search the executions");
420         }
421
422         return list;
423     }
424
425     private Execution makeExecution(String executionStorePath) throws IOException {
426         OnapCommandExecutionStore.Execution exectuion = new OnapCommandExecutionStore.Execution();
427         if (new File(executionStorePath + File.separator + REQUEST_ID).exists())
428             exectuion.setRequestId(FileUtils.readFileToString(new File(executionStorePath + File.separator + REQUEST_ID)));
429         if (new File(executionStorePath + File.separator + EXECUTION_ID).exists())
430             exectuion.setId(FileUtils.readFileToString(new File(executionStorePath + File.separator + EXECUTION_ID)));
431         exectuion.setProduct(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.INFO_PRODUCT)));
432         exectuion.setService(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.INFO_SERVICE)));
433         exectuion.setCommand(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.RPC_CMD)));
434         if (new File(executionStorePath + File.separator + OnapCommandConstants.RPC_PROFILE).exists())
435             exectuion.setProfile(FileUtils.readFileToString(new File(executionStorePath + File.separator + OnapCommandConstants.RPC_PROFILE)));
436
437         exectuion.setInput(FileUtils.readFileToString(new File(executionStorePath + File.separator + INPUT)));
438         exectuion.setStartTime(dateFormatter.format(new File(executionStorePath + File.separator + INPUT).lastModified()));
439
440         if (new File(executionStorePath + File.separator + IN_PROGRESS).exists()) {
441             exectuion.setStatus(IN_PROGRESS);
442         } else if (new File(executionStorePath + File.separator + COMPLETED).exists()) {
443             exectuion.setStatus(COMPLETED);
444             if (new File(executionStorePath + File.separator + OUTPUT).exists()) {
445                 exectuion.setOutput(FileUtils.readFileToString(new File(executionStorePath + File.separator + OUTPUT)));
446                 exectuion.setEndTime(dateFormatter.format(new File(executionStorePath + File.separator + OUTPUT).lastModified()));
447             }
448         } else if (new File(executionStorePath + File.separator + FAILED).exists()) {
449             exectuion.setStatus(FAILED);
450             if (new File(executionStorePath + File.separator + ERROR).exists()) {
451                 exectuion.setOutput(FileUtils.readFileToString(new File(executionStorePath + File.separator + ERROR)));
452                 exectuion.setEndTime(dateFormatter.format(new File(executionStorePath + File.separator + ERROR).lastModified()));
453             }
454         }
455
456         return exectuion;
457     }
458
459     private File getExecutionDir(String executionId) throws OnapCommandExecutionNotFound {
460         File []f =  new File(getBasePath()).listFiles((dir, name) -> {
461             return name.startsWith(executionId);
462         });
463
464         if (f.length == 0) {
465             throw new OnapCommandExecutionNotFound(executionId);
466         }
467
468         return f[0];
469     }
470
471     public String showExecutionOut(String executionId) throws OnapCommandExecutionNotFound {
472         try {
473             return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + "stdout"));
474         } catch (IOException e) {
475             return "";
476         }
477     }
478
479     public String showExecutionErr(String executionId) throws OnapCommandExecutionNotFound {
480         try {
481             return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + "stderr"));
482         } catch (IOException e) {
483             return "";
484         }
485     }
486
487     public String showExecutionDebug(String executionId) throws OnapCommandExecutionNotFound {
488         try {
489             return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + DEBUG));
490         } catch (IOException e) {
491             return "";
492         }
493     }
494     public Execution getExecution(String executionId) throws OnapCommandExecutionNotFound, OnapCommandExecutionFailed {
495         try {
496             return this.makeExecution(this.getExecutionDir(executionId).getAbsolutePath());
497         } catch (IOException e) {
498             throw new OnapCommandExecutionFailed(e, "Failed to retrieve the execution");
499         }
500     }
501 }