Merge "Added non-vulnerable version for log4j"
[vnfsdk/refrepo.git] / vnfmarket-be / vnf-sdk-marketplace / src / main / java / org / onap / vtp / scenario / VTPScenarioResource.java
1 /**
2  * Copyright 2018 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.vtp.scenario;
18
19 import java.io.File;
20 import java.io.FileReader;
21 import java.io.FileWriter;
22 import java.io.IOException;
23 import java.text.MessageFormat;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.regex.Matcher;
30
31 import javax.ws.rs.Consumes;
32 import javax.ws.rs.DELETE;
33 import javax.ws.rs.GET;
34 import javax.ws.rs.POST;
35 import javax.ws.rs.Path;
36 import javax.ws.rs.PathParam;
37 import javax.ws.rs.Produces;
38 import javax.ws.rs.QueryParam;
39 import javax.ws.rs.core.MediaType;
40 import javax.ws.rs.core.Response;
41
42 import com.google.common.collect.Maps;
43 import org.apache.commons.io.FileUtils;
44 import org.apache.cxf.common.util.CollectionUtils;
45 import org.eclipse.jetty.http.HttpStatus;
46 import org.glassfish.jersey.media.multipart.BodyPartEntity;
47 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
48 import org.glassfish.jersey.media.multipart.FormDataParam;
49 import org.onap.vnfsdk.marketplace.common.CommonConstant;
50 import org.onap.vnfsdk.marketplace.common.FileUtil;
51 import org.onap.vnfsdk.marketplace.common.ToolUtil;
52 import org.onap.vtp.VTPResource;
53 import org.onap.vtp.error.VTPError;
54 import org.onap.vtp.error.VTPError.VTPException;
55 import org.onap.vtp.scenario.model.VTPTestCase;
56 import org.onap.vtp.scenario.model.VTPTestScenario;
57 import org.onap.vtp.scenario.model.VTPTestSuite;
58 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseInput;
59 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseList;
60 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseOutput;
61 import org.onap.vtp.scenario.model.VTPTestScenario.VTPTestScenarioList;
62 import org.onap.vtp.scenario.model.VTPTestSuite.VTPTestSuiteList;
63
64 import com.google.gson.JsonArray;
65 import com.google.gson.JsonElement;
66 import com.google.gson.JsonObject;
67
68 import io.swagger.annotations.Api;
69 import io.swagger.annotations.ApiOperation;
70 import io.swagger.annotations.ApiParam;
71 import io.swagger.annotations.ApiResponse;
72 import io.swagger.annotations.ApiResponses;
73
74 @Path("/vtp")
75 @Api(tags = {"VTP Scenario"})
76 public class VTPScenarioResource extends VTPResource{
77     private static final String DESCRIPTION = "description";
78     private static final String PRODUCT_ARG="--product";
79     private static final String OPEN_CLI="open-cli";
80     private static final String FORMAT="--format";
81     private static final String IO_EXCEPTION_OCCURS ="IOException occurs";
82     private static final String SERVICE="service";
83     public VTPTestScenarioList listTestScenariosHandler() throws VTPException {
84         List<String> args = new ArrayList<>();
85
86         args.addAll(Arrays.asList(
87                 PRODUCT_ARG, OPEN_CLI, "product-list", FORMAT, "json"
88         ));
89
90
91         JsonElement results = null;
92         try {
93             results = this.makeRpcAndGetJson(args);
94         } catch (IOException e) {
95             LOG.error(IO_EXCEPTION_OCCURS,e);
96         }
97
98         VTPTestScenarioList list = new VTPTestScenarioList();
99
100         if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
101             JsonArray resultsArray = results.getAsJsonArray();
102             for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
103                 JsonElement jsonElement = it.next();
104                 JsonObject n = jsonElement.getAsJsonObject();
105                 if (n.entrySet().iterator().hasNext()) {
106                     String name = n.get("product").getAsString();
107
108                     if (OPEN_CLI.equalsIgnoreCase(name))
109                         continue;
110
111                     list.getScenarios().add(new VTPTestScenario().setName(name).setDescription(
112                             n.get(DESCRIPTION).getAsString()));
113                 }
114             }
115         }
116
117         return list;
118     }
119
120     @Path("/scenarios")
121     @GET
122     @ApiOperation(tags = "VTP Scenario", value = " List available test scenarios", response = VTPTestScenario.class, responseContainer = "List")
123     @Produces(MediaType.APPLICATION_JSON)
124     @ApiResponses(value = {
125             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
126                     message = "Failed to perform the operation",
127                     response = VTPError.class) })
128     public Response listTestScenarios() throws VTPException {
129         return Response.ok(this.listTestScenariosHandler().getScenarios().toString(), MediaType.APPLICATION_JSON).build();
130     }
131
132     public VTPTestSuiteList listTestSutiesHandler(String scenario) throws VTPException {
133         List<String> args = new ArrayList<>();
134
135         args.addAll(Arrays.asList(
136                 PRODUCT_ARG, OPEN_CLI, "service-list", PRODUCT_ARG, scenario, FORMAT, "json"
137         ));
138
139         JsonElement results = null;
140         try {
141             results = this.makeRpcAndGetJson(args);
142         } catch (IOException e) {
143             LOG.error(IO_EXCEPTION_OCCURS,e);
144         }
145
146         VTPTestSuiteList list = new VTPTestSuiteList();
147
148         if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
149             JsonArray resultsArray = results.getAsJsonArray();
150             for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
151                 JsonElement jsonElement = it.next();
152                 JsonObject n = jsonElement.getAsJsonObject();
153                 if (n.entrySet().iterator().hasNext()) {
154                     list.getSuites().add(new VTPTestSuite().setName(n.get(SERVICE).getAsString()).setDescription(
155                             n.get(DESCRIPTION).getAsString()));
156                 }
157             }
158         }
159
160         return list;
161     }
162
163     @Path("/scenarios/{scenario}/testsuites")
164     @GET
165     @ApiOperation(tags = "VTP Scenario",  value = " List available test suties in given scenario", response = VTPTestSuite.class, responseContainer = "List")
166     @Produces(MediaType.APPLICATION_JSON)
167     @ApiResponses(value = {
168             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
169                     message = "Failed to perform the operation",
170                     response = VTPError.class) })
171     public Response listTestSuties(
172             @ApiParam("Test scenario name") @PathParam("scenario") String scenario) throws VTPException {
173
174         return Response.ok(this.listTestSutiesHandler(scenario).getSuites().toString(), MediaType.APPLICATION_JSON).build();
175     }
176
177     public VTPTestCaseList listTestcasesHandler(String testSuiteName, String scenario) throws VTPException {
178         List<String> args = new ArrayList<>();
179
180         args.addAll(Arrays.asList(
181                 PRODUCT_ARG, OPEN_CLI, "schema-list", PRODUCT_ARG, scenario, FORMAT, "json"
182         ));
183         if (testSuiteName != null) {
184             args.add("--service");
185             args.add(testSuiteName);
186         }
187
188         JsonElement results = null;
189         try {
190             results = this.makeRpcAndGetJson(args);
191         } catch (IOException e) {
192             LOG.error(IO_EXCEPTION_OCCURS,e);
193         }
194
195         VTPTestCaseList list = new VTPTestCaseList();
196
197         if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
198             JsonArray resultsArray = results.getAsJsonArray();
199             for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
200                 JsonElement jsonElement = it.next();
201                 JsonObject n = jsonElement.getAsJsonObject();
202                 if (n.entrySet().iterator().hasNext())
203                     list.getTestCases().add(
204                             new VTPTestCase().setTestCaseName(
205                                     n.get("command").getAsString()).setTestSuiteName(
206                                     n.get(SERVICE).getAsString()));
207             }
208         }
209
210         return list;
211     }
212
213     @Path("/scenarios/{scenario}/testcases")
214     @GET
215     @ApiOperation(tags = "VTP Scenario", value = " List available test cases", response = VTPTestCase.class, responseContainer = "List")
216     @Produces(MediaType.APPLICATION_JSON)
217     @ApiResponses(value = {
218             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
219                     message = "Failed to perform the operation",
220                     response = VTPError.class) })
221     public Response listTestcases(
222             @ApiParam("Test scenario name") @PathParam("scenario") String scenario,
223             @ApiParam("Test suite name") @QueryParam("testSuiteName") String testSuiteName
224     ) throws VTPException {
225
226         return Response.ok(this.listTestcasesHandler(testSuiteName, scenario).getTestCases().toString(), MediaType.APPLICATION_JSON).build();
227     }
228
229     public VTPTestCase getTestcaseHandler(String scenario, String testSuiteName, String testCaseName) throws VTPException {
230         List<String> args = new ArrayList<>();
231         args.addAll(Arrays.asList(
232                 PRODUCT_ARG, OPEN_CLI, "schema-show", PRODUCT_ARG, scenario, "--service", testSuiteName, "--command", testCaseName , FORMAT, "json"
233         ));
234         JsonElement results = null;
235         try {
236             results = this.makeRpcAndGetJson(args);
237         } catch (IOException e) {
238             LOG.error(IO_EXCEPTION_OCCURS,e);
239         }
240
241         JsonObject schema = results.getAsJsonObject().getAsJsonObject("schema");
242
243         VTPTestCase tc = new VTPTestCase();
244         tc.setTestCaseName(schema.get("name").getAsString());
245         tc.setDescription(schema.get(DESCRIPTION).getAsString());
246         tc.setTestSuiteName(schema.get(SERVICE).getAsString());
247         tc.setAuthor(schema.get("author").getAsString());
248         JsonElement inputsJson = schema.get("inputs");
249         if (inputsJson != null && inputsJson.isJsonArray()) {
250             for (final JsonElement jsonElement: inputsJson.getAsJsonArray()) {
251                 JsonObject inputJson  = jsonElement.getAsJsonObject();
252                 VTPTestCaseInput input = new VTPTestCaseInput();
253
254                 input.setName(inputJson.get("name").getAsString());
255                 input.setDescription(inputJson.get(DESCRIPTION).getAsString());
256                 input.setType(inputJson.get("type").getAsString());
257
258                 if (inputJson.get("is_optional") != null)
259                     input.setIsOptional(inputJson.get("is_optional").getAsBoolean());
260
261                 if (inputJson.get("default_value") != null)
262                     input.setDefaultValue(inputJson.get("default_value").getAsString());
263
264                 if (inputJson.get("metadata") != null)
265                     input.setMetadata(inputJson.get("metadata"));
266
267                 tc.getInputs().add(input);
268             }
269         }
270
271         JsonElement outputsJson = schema.get("outputs");
272         if (outputsJson != null && outputsJson.isJsonArray() && outputsJson.getAsJsonArray().size()>0) {
273             for (final JsonElement jsonElement: outputsJson.getAsJsonArray()) {
274                 JsonObject outputJson = jsonElement.getAsJsonObject();
275                 VTPTestCaseOutput output = new VTPTestCaseOutput();
276                 output.setName(outputJson.get("name").getAsString());
277                 output.setDescription(outputJson.get(DESCRIPTION).getAsString());
278                 output.setType(outputJson.get("type").getAsString());
279
280                 tc.getOutputs().add(output);
281             }
282         }
283
284         return tc;
285     }
286
287     @Path("/scenarios/{scenario}/testsuites/{testSuiteName}/testcases/{testCaseName}")
288     @GET
289     @ApiOperation(tags = "VTP Scenario",  value = "Retrieve test cases details like inputs outputs and test suite name", response = VTPTestCase.class)
290     @Produces(MediaType.APPLICATION_JSON)
291     @ApiResponses(value = {
292             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
293                     message = "Failed to perform the operation", response = VTPError.class),
294             @ApiResponse(code = HttpStatus.NOT_FOUND_404,
295                     message = "Test case does not exist", response = VTPError.class)})
296     public Response getTestcase(
297             @ApiParam("Test scenario name") @PathParam("scenario") String scenario,
298             @ApiParam(value = "Test case name") @PathParam("testSuiteName") String testSuiteName,
299             @ApiParam(value = "Test case name") @PathParam("testCaseName") String testCaseName)
300             throws VTPException {
301
302         return Response.ok(this.getTestcaseHandler(scenario, testSuiteName, testCaseName).toString(), MediaType.APPLICATION_JSON).build();
303     }
304
305     @Path("/scenarios")
306     @POST
307     @ApiOperation(tags = "VTP Scenario", value = "Create Scenario")
308     @Consumes(MediaType.MULTIPART_FORM_DATA)
309     @Produces(MediaType.APPLICATION_JSON)
310     @ApiResponses(value = {
311             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
312     public Response storageScenarios(@ApiParam(value = "file form data body parts", required = true)
313                                      @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException {
314         bodyParts.forEach(bodyPart -> {
315             BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity();
316             String fileName = bodyPart.getContentDisposition().getFileName();
317             if (!ToolUtil.isYamlFile(new File(fileName))) {
318                 LOG.error("The fileName {} is not yaml !!!", fileName);
319                 return;
320             }
321             String scenario = fileName.substring(0, fileName.indexOf("-registry"));
322             File scenarioDir = new File(VTP_YAML_STORE, scenario);
323             File yamlFile = new File(VTP_YAML_STORE, fileName);
324
325             // 1、store the scenario yaml file and create the scenario dir
326             try {
327                 FileUtils.deleteQuietly(yamlFile);
328                 FileUtils.deleteDirectory(scenarioDir);
329                 FileUtils.forceMkdir(scenarioDir);
330                 FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile);
331             } catch (IOException e) {
332                 LOG.error("Save yaml {} failed", fileName, e);
333             }
334
335             // 2、create the testsuits dir and copy the testcase to current scenarios by commands
336             try {
337                 Map<String, Object> yamlInfos = Maps.newHashMap();
338                 try (FileReader fileReader = new FileReader(yamlFile)) {
339                     yamlInfos = snakeYaml().load(fileReader);
340                 }
341                 for (Object service : (List) yamlInfos.get("services")) {
342                     Map<String, Object> serviceMap = (Map<String, Object>) service;
343                     String testsuite = serviceMap.get("name").toString();
344                     File testsuiteDir = new File(scenarioDir, testsuite);
345                     FileUtils.forceMkdir(testsuiteDir);
346                     if (!serviceMap.containsKey("commands")) {
347                         continue;
348                     }
349                     for (Object cmd : (List) serviceMap.get("commands")) {
350                         File source = new File(VTP_YAML_STORE, cmd.toString().replaceAll("::", Matcher.quoteReplacement(File.separator)));
351                         if (!source.isFile()) {
352                             LOG.error("Source {} is not a yaml file !!!", source.getName());
353                             continue;
354                         }
355                         File dest = new File(testsuiteDir, cmd.toString().substring(cmd.toString().lastIndexOf("::") + 2));
356                         FileUtils.copyFile(source, dest);
357
358                         // 3、modify the testcase scenario and testsuite
359                         Map<String, Object> result = Maps.newHashMap();
360                         try (FileReader fileReader = new FileReader(dest)) {
361                             result = snakeYaml().load(fileReader);
362                         }
363                         Map<String, Object> info = (Map<String, Object>) result.get("info");
364                         info.put("product", scenario);
365                         info.put("service", testsuite);
366                         try (FileWriter fileWriter = new FileWriter(dest)) {
367                             snakeYaml().dump(result, fileWriter);
368                         }
369                     }
370                 }
371             } catch (Exception e) {
372                 LOG.error("Parse testcase yaml failed !!!", e);
373             }
374         });
375         return Response.ok("Save yaml success", MediaType.APPLICATION_JSON).build();
376     }
377
378
379     @Path("/scenarios/{scenarioName}")
380     @DELETE
381     @ApiOperation(tags = "VTP Scenario", value = "Delete yaml string")
382     @Produces(MediaType.APPLICATION_JSON)
383     @ApiResponses(value = {
384             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
385     public Response deleteScenario(@ApiParam("Test scenario yaml") @PathParam("scenarioName") String scenarioName) throws VTPException {
386         String scenario = scenarioName.substring(0, scenarioName.indexOf("-registry"));
387         File scenarioDir = new File(VTP_YAML_STORE, scenario);
388         List<File> yamls =  FileUtil.searchFiles(scenarioDir, CommonConstant.YAML_SUFFIX);
389         if (!CollectionUtils.isEmpty(yamls)) {
390             LOG.error("The scenario yaml {} has sub testcase yamls, delete failed", scenarioName);
391             throw new VTPException(
392                     new VTPError().setMessage(MessageFormat.format("The scenario yaml {0} has sub testcase yamls, delete failed !!!", scenarioName))
393                             .setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500));
394         }
395
396         try {
397             FileUtils.deleteQuietly(new File(VTP_YAML_STORE, scenarioName));
398             FileUtils.deleteDirectory(scenarioDir);
399         } catch (IOException e) {
400             LOG.error("Delete scenario yaml {} failed", scenarioName, e);
401             throw new VTPException(
402                     new VTPError().setMessage("Delete yaml failed !!!").setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500));
403         }
404         return Response.ok("Delete yaml success", MediaType.APPLICATION_JSON).build();
405     }
406
407     @Path("/testcases")
408     @POST
409     @ApiOperation(tags = "VTP Scenario", value = "Create test case")
410     @Consumes(MediaType.MULTIPART_FORM_DATA)
411     @Produces(MediaType.APPLICATION_JSON)
412     @ApiResponses(value = {
413             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
414     public Response storageTestcases(@ApiParam(value = "file form data body parts", required = true)
415                                      @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException {
416         bodyParts.forEach(bodyPart -> {
417             BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity();
418             String fileName = bodyPart.getContentDisposition().getFileName();
419             if (ToolUtil.isYamlFile(new File(fileName))) {
420                 // 1、store the testcase yaml file
421                 Map<String, Object> result = snakeYaml().load(entity.getInputStream());
422                 Map<String, Object> info = (Map<String, Object>) result.get("info");
423
424                 File yamlFile = new File(VTP_YAML_STORE, info.get("product") + File.separator + info.get("service") + File.separator + fileName);
425                 try {
426                     FileUtils.deleteQuietly(yamlFile);
427                     FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile);
428                 } catch (IOException e) {
429                     LOG.error("Save testcase yaml {} failed", yamlFile.getName(), e);
430                 }
431             } else {
432                 // 2、store the testcase script file
433                 File scriptFile = new File(VTP_SCRIPT_STORE, fileName);
434                 try {
435                     FileUtils.deleteQuietly(scriptFile);
436                     FileUtils.copyInputStreamToFile(entity.getInputStream(), scriptFile);
437                 } catch (IOException e) {
438                     LOG.error("Save testcase script {} failed", scriptFile.getName(), e);
439                 }
440             }
441         });
442         return Response.ok("Save success", MediaType.APPLICATION_JSON).build();
443     }
444 }