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