2 * Copyright 2019 Huawei Technologies Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.cli.fw.store;
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;
31 import java.util.TimeZone;
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;
42 public class OnapCommandExecutionStore {
43 private static Logger log = LoggerFactory.getLogger(OnapCommandExecutionStore.class);
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";
62 private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
64 private static final String SEPARATOR = "__";
66 private enum SearchMode {
68 FILE //for developer mode
73 private static SearchMode searchMode = SearchMode.FILE;
75 String mode = OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_EXECUTION_SEARCH_MODE);
76 if (mode.equalsIgnoreCase(SearchMode.FIND.name()))
77 searchMode = SearchMode.FIND;
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() {
88 public ExecutionStoreContext setExecutionId(String executionId) {
89 this.executionId = executionId;
92 public String getStorePath() {
95 public ExecutionStoreContext setStorePath(String storePath) {
96 this.storePath = storePath;
99 public String getRequestId() {
102 public ExecutionStoreContext setRequestId(String requestId) {
103 this.requestId = requestId;
106 public String getProfile() {
109 public void setProfile(String profile) {
110 this.profile = profile;
114 public static class Execution {
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;
127 public String getInput() {
130 public void setInput(String input) {
133 public String getOutput() {
136 public void setOutput(String output) {
137 this.output = output;
139 public String getProfile() {
142 public void setProfile(String profile) {
143 this.profile = profile;
145 public String getCommand() {
148 public void setCommand(String command) {
149 this.command = command;
151 public String getProduct() {
154 public void setProduct(String product) {
155 this.product = product;
157 public String getService() {
160 public void setService(String service) {
161 this.service = service;
163 public String getId() {
166 public void setId(String id) {
169 public String getEndTime() {
172 public void setEndTime(String endTime) {
173 this.endTime = endTime;
175 public void setStartTime(String timeOfExecution) {
176 this.startTime = timeOfExecution;
178 public String getStartTime() {
181 public String getStatus() {
184 public void setStatus(String status) {
185 this.status = status;
187 public String getRequestId() {
190 public void setRequestId(String requestId) {
191 this.requestId = requestId;
197 FileUtils.forceMkdir(new File(getBasePath()));
199 } catch (IOException e) {
200 log.error("Failed to create the data store results");
204 private static OnapCommandExecutionStore store = null;
206 private OnapCommandExecutionStore() {
207 this.dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
210 public static OnapCommandExecutionStore getStore() {
212 store = new OnapCommandExecutionStore();
218 private static String getBasePath() {
219 return OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_DATA_DIR) +
220 File.separator + "executions";
223 public ExecutionStoreContext storeExectutionStart(
224 String requestId, String product, String service, String cmd, String profile, String input) {
226 ExecutionStoreContext context = new ExecutionStoreContext();
227 context.setRequestId(requestId);
229 String executionId = requestId + "-" + System.currentTimeMillis();
230 context.setExecutionId(executionId);
232 String storePath = getBasePath() + File.separator + executionId + SEPARATOR + product +
233 SEPARATOR + service +
235 SEPARATOR + (profile != null ? profile : "" );
238 File dir = new File(storePath);
239 FileUtils.forceMkdir(dir);
240 context.setStorePath(dir.getAbsolutePath());
243 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OnapCommandConstants.INFO_PRODUCT), product, (Charset) null);
245 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OnapCommandConstants.INFO_SERVICE), service, (Charset) null);
247 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OnapCommandConstants.RPC_CMD), cmd, (Charset) null);
249 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + REQUEST_ID), requestId, (Charset) null);
251 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + EXECUTION_ID), executionId, (Charset) 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);
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));
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);
272 public void storeExectutionEnd(
273 ExecutionStoreContext context,
274 String output, String error, String debug, boolean passed) {
278 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output, (Charset) null);
280 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + ERROR), error, (Charset) null);
282 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + DEBUG), debug, (Charset) null);
284 FileUtils.touch(new File(context.getStorePath() + File.separator + COMPLETED));
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);
294 private void deleteFile(ExecutionStoreContext context, Path path){
297 } catch (IOException e) {
298 String contextPath = context.getStorePath() + File.separator + IN_PROGRESS;
299 log.error("Failed to delete {}", contextPath);
303 public void storeExectutionProgress(
304 ExecutionStoreContext context,
305 String output, String error, String debug) {
309 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output, (Charset) null);
311 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + ERROR), error, (Charset) 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);
319 public void storeExectutionDebug(
320 ExecutionStoreContext context,
325 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + DEBUG), debug, (Charset) null);
327 } catch (IOException e) {
328 log.error("Failed to store the execution debug details {}", context.storePath);
332 public void storeExectutionOutput(
333 ExecutionStoreContext context,
337 if (output != null) {
338 FileUtils.writeStringToFile(new File(context.getStorePath() + File.separator + OUTPUT), output, (Charset) null);
340 } catch (IOException e) {
341 log.error("Failed to store the execution output details {}", context.storePath);
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());
354 if(search.containsKey(REQUESTID)) {
355 if (f.getName().startsWith(search.get(REQUESTID)))
356 dirs.add(f.getAbsolutePath());
361 dirs.add(f.getAbsolutePath());
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 ");
369 String startTime = search.get("startTime");
370 if (startTime != null) {
371 searchString.append(" -newermt " + startTime);
374 String endTime = search.get("endTime");
375 if (endTime != null) {
376 searchString.append(" ! -newermt " + endTime);
379 searchString.append(" -name \"");
381 if(search.containsKey(EXECUTIONID)) {
382 searchString.append(search.get(EXECUTIONID));
383 } else if(search.containsKey(REQUESTID)) {
384 searchString.append(search.get(REQUESTID) + "*");
386 searchString.append("*");
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));
394 searchString.append("*");
397 if (!searchString.toString().endsWith("*"))
398 searchString.append("*");
400 searchString.append("\"");
402 ProcessRunner pr = new ProcessRunner(new String [] {searchString.toString()}, null, ".");
403 pr.setTimeout(10000);
406 if (pr.getExitCode() != 0) {
407 throw new OnapCommandExecutionFailed("System failed to search the executions with error " + pr.getError());
410 if (!pr.getOutput().trim().isEmpty())
411 dirs = Arrays.asList(pr.getOutput().split("\\r?\\n"));
416 public List<OnapCommandExecutionStore.Execution> listExecutions(Map<String, String> search) throws OnapCommandExecutionFailed {
417 List <OnapCommandExecutionStore.Execution> list = new ArrayList<>();
420 List <String> dirs = new ArrayList<>();
421 if (System.getProperty(OS_NAME).toLowerCase().startsWith(WINDOWS) || searchMode.equals(SearchMode.FILE)) {
422 dirs = listExecutionsWindows(search, dirs);
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);
429 for (String dir: dirs) {
430 list.add(this.makeExecution(dir));
432 } catch (Exception e) {// NOSONAR
433 throw new OnapCommandExecutionFailed(e, "Failed to search the executions");
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));
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()));
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()));
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()));
473 private File getExecutionDir(String executionId) throws OnapCommandExecutionNotFound {
474 File []f = new File(getBasePath()).listFiles((dir, name) -> {
475 return name.startsWith(executionId);
479 throw new OnapCommandExecutionNotFound(executionId);
485 public String showExecutionOut(String executionId) throws OnapCommandExecutionNotFound {
487 return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + STDOUT), (Charset) null);
488 } catch (IOException e) {
493 public String showExecutionErr(String executionId) throws OnapCommandExecutionNotFound {
495 return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + STDERR), (Charset) null);
496 } catch (IOException e) {
501 public String showExecutionDebug(String executionId) throws OnapCommandExecutionNotFound {
503 return FileUtils.readFileToString(new File (this.getExecutionDir(executionId).getAbsolutePath() + File.separator + DEBUG), (Charset) null);
504 } catch (IOException e) {
508 public Execution getExecution(String executionId) throws OnapCommandExecutionNotFound, OnapCommandExecutionFailed {
510 return this.makeExecution(this.getExecutionDir(executionId).getAbsolutePath());
511 } catch (IOException e) {
512 throw new OnapCommandExecutionFailed(e, "Failed to retrieve the execution");