diff options
6 files changed, 272 insertions, 45 deletions
diff --git a/vnfmarket-be/vnf-sdk-marketplace/pom.xml b/vnfmarket-be/vnf-sdk-marketplace/pom.xml index 3dcda1a9..7d40b908 100644 --- a/vnfmarket-be/vnf-sdk-marketplace/pom.xml +++ b/vnfmarket-be/vnf-sdk-marketplace/pom.xml @@ -121,6 +121,11 @@ <artifactId>snakeyaml</artifactId> <version>1.26</version> </dependency> + <dependency> + <groupId>cn.hutool</groupId> + <artifactId>hutool-all</artifactId> + <version>5.3.10</version> + </dependency> <!-- jersey --> <!-- excluded jetty-util and added invulnerable version --> <dependency> @@ -290,7 +295,7 @@ due to Security Issues:- CVE-2019-10241,CVE-2019-10247,CVE-2019-10246 <forkMode>always</forkMode> <argLine> -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar - <!--${surefireArgLine}--> + ${surefireArgLine} </argLine> <skip>${maven.test.skip}</skip> <testFailureIgnore>${maven.test.failure.ignore}</testFailureIgnore> diff --git a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/CommonConstant.java b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/CommonConstant.java index 60d2a22a..cc3cbe9d 100644 --- a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/CommonConstant.java +++ b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/CommonConstant.java @@ -53,6 +53,8 @@ public class CommonConstant { public static final String CSAR_SUFFIX = ".csar"; + public static final String YAML_SUFFIX = ".yaml"; + public static final String HTTP_HEADER_CONTENT_RANGE = "Content-Range"; public static final String CATALOG_CSAR_DIR_NAME = "/csar"; @@ -103,6 +105,8 @@ public class CommonConstant { public static final String MEDIA_TYPE_JSON = "application/json;charset=UTF-8"; + public static final String MEDIA_TYPE_YAML = "text/yaml"; + public static final String URL = "url"; public static final String METHOD_TYPE = "methodType"; diff --git a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/FileUtil.java b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/FileUtil.java index 777080f1..4b008395 100644 --- a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/FileUtil.java +++ b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/FileUtil.java @@ -17,8 +17,11 @@ package org.onap.vnfsdk.marketplace.common; import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -30,8 +33,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.stream.JsonReader; -import java.io.FileWriter; -import java.io.FileReader; + import java.nio.file.Files; import java.nio.file.Paths; @@ -73,12 +75,12 @@ public final class FileUtil { boolean isFileDeleted=false; try { if (file.exists()){ - Files.delete(Paths.get(file.getPath())); - fileAbsPath = file.getAbsolutePath(); - logger.info("delete {} {}" ,hintInfo, fileAbsPath); + Files.delete(Paths.get(file.getPath())); + fileAbsPath = file.getAbsolutePath(); + logger.info("delete {} {}" ,hintInfo, fileAbsPath); } else{ - logger.info("file not exist. no need delete {} {}" ,hintInfo , fileAbsPath); + logger.info("file not exist. no need delete {} {}" ,hintInfo , fileAbsPath); } isFileDeleted=true; @@ -118,7 +120,7 @@ public final class FileUtil { } try (InputStream input = zipFile.getInputStream(entry); - BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));) { + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));) { int length = 0; while ((length = input.read(buffer)) != -1) { bos.write(buffer, 0, length); @@ -188,7 +190,7 @@ public final class FileUtil { public static boolean deleteDirectory(File file) { if (!file.exists()) { - return true; + return true; } if (file.isDirectory()) { for (File f : file.listFiles()) { @@ -246,4 +248,40 @@ public final class FileUtil { return true; } + + /** + * Search file in folder + * @param folder + * @param keyword + * @return + */ + public static List<File> searchFiles(File folder, String keyword) { + List<File> result = new ArrayList<File>(); + if (folder.isFile()) + result.add(folder); + + File[] subFolders = folder.listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + if (file.isDirectory()) { + return true; + } + if (file.getName().toLowerCase().contains(keyword)) { + return true; + } + return false; + } + }); + + if (subFolders != null) { + for (File file : subFolders) { + if (file.isFile()) { + result.add(file); + } else { + result.addAll(searchFiles(file, keyword)); + } + } + } + return result; + } } diff --git a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/VTPResource.java b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/VTPResource.java index 0d813c74..9e1a9c80 100644 --- a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/VTPResource.java +++ b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/VTPResource.java @@ -39,6 +39,8 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; public class VTPResource { @@ -50,6 +52,8 @@ public class VTPResource { protected static String VTP_ARTIFACT_STORE; // NOSONAR protected static String VTP_EXECUTION_TEMP_STORE; // NOSONAR protected static int VTP_EXECUTION_GRPC_TIMEOUT; // NOSONAR + protected static String VTP_YAML_STORE; // NOSONAR + protected static String VTP_SCRIPT_STORE; // NOSONAR protected static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US); // NOSONAR @@ -64,6 +68,8 @@ public class VTPResource { VTP_ARTIFACT_STORE = prp.getProperty("vtp.artifact.store"); VTP_EXECUTION_TEMP_STORE = prp.getProperty("vtp.file.store"); VTP_EXECUTION_GRPC_TIMEOUT = Integer.parseInt(prp.getProperty("vtp.grpc.timeout")) * 1000 ; + VTP_YAML_STORE = prp.getProperty("vtp.yaml.store"); + VTP_SCRIPT_STORE = prp.getProperty("vtp.script.store"); } catch (Exception e) { // NOSONAR LOG.error(e.getMessage()); } @@ -138,4 +144,16 @@ public class VTPResource { return output; } + + /** + * Build SnakeYaml instance + * @return + */ + protected Yaml snakeYaml() { + DumperOptions dumperOptions = new DumperOptions(); + dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + dumperOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN); + dumperOptions.setPrettyFlow(false); + return new Yaml(dumperOptions); + } } diff --git a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/scenario/VTPScenarioResource.java b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/scenario/VTPScenarioResource.java index 4b319328..274cacd9 100644 --- a/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/scenario/VTPScenarioResource.java +++ b/vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/scenario/VTPScenarioResource.java @@ -16,13 +16,22 @@ package org.onap.vtp.scenario; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @@ -30,7 +39,16 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import com.google.common.collect.Maps; +import org.apache.commons.io.FileUtils; +import org.apache.cxf.common.util.CollectionUtils; import org.eclipse.jetty.http.HttpStatus; +import org.glassfish.jersey.media.multipart.BodyPartEntity; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.glassfish.jersey.media.multipart.FormDataParam; +import org.onap.vnfsdk.marketplace.common.CommonConstant; +import org.onap.vnfsdk.marketplace.common.FileUtil; +import org.onap.vnfsdk.marketplace.common.ToolUtil; import org.onap.vtp.VTPResource; import org.onap.vtp.error.VTPError; import org.onap.vtp.error.VTPError.VTPException; @@ -67,7 +85,7 @@ public class VTPScenarioResource extends VTPResource{ args.addAll(Arrays.asList( PRODUCT_ARG, OPEN_CLI, "product-list", FORMAT, "json" - )); + )); JsonElement results = null; @@ -81,18 +99,18 @@ public class VTPScenarioResource extends VTPResource{ if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) { JsonArray resultsArray = results.getAsJsonArray(); - for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) { - JsonElement jsonElement = it.next(); - JsonObject n = jsonElement.getAsJsonObject(); - if (n.entrySet().iterator().hasNext()) { - String name = n.get("product").getAsString(); + for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) { + JsonElement jsonElement = it.next(); + JsonObject n = jsonElement.getAsJsonObject(); + if (n.entrySet().iterator().hasNext()) { + String name = n.get("product").getAsString(); - if (OPEN_CLI.equalsIgnoreCase(name)) - continue; + if (OPEN_CLI.equalsIgnoreCase(name)) + continue; - list.getScenarios().add(new VTPTestScenario().setName(name).setDescription( - n.get(DESCRIPTION).getAsString())); - } + list.getScenarios().add(new VTPTestScenario().setName(name).setDescription( + n.get(DESCRIPTION).getAsString())); + } } } @@ -116,7 +134,7 @@ public class VTPScenarioResource extends VTPResource{ args.addAll(Arrays.asList( PRODUCT_ARG, OPEN_CLI, "service-list", PRODUCT_ARG, scenario, FORMAT, "json" - )); + )); JsonElement results = null; try { @@ -129,14 +147,14 @@ public class VTPScenarioResource extends VTPResource{ if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) { JsonArray resultsArray = results.getAsJsonArray(); - for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) { - JsonElement jsonElement = it.next(); - JsonObject n = jsonElement.getAsJsonObject(); - if (n.entrySet().iterator().hasNext()) { - list.getSuites().add(new VTPTestSuite().setName(n.get(SERVICE).getAsString()).setDescription( - n.get(DESCRIPTION).getAsString())); - } + for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) { + JsonElement jsonElement = it.next(); + JsonObject n = jsonElement.getAsJsonObject(); + if (n.entrySet().iterator().hasNext()) { + list.getSuites().add(new VTPTestSuite().setName(n.get(SERVICE).getAsString()).setDescription( + n.get(DESCRIPTION).getAsString())); } + } } return list; @@ -161,7 +179,7 @@ public class VTPScenarioResource extends VTPResource{ args.addAll(Arrays.asList( PRODUCT_ARG, OPEN_CLI, "schema-list", PRODUCT_ARG, scenario, FORMAT, "json" - )); + )); if (testSuiteName != null) { args.add("--service"); args.add(testSuiteName); @@ -178,15 +196,15 @@ public class VTPScenarioResource extends VTPResource{ if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) { JsonArray resultsArray = results.getAsJsonArray(); - for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) { - JsonElement jsonElement = it.next(); - JsonObject n = jsonElement.getAsJsonObject(); - if (n.entrySet().iterator().hasNext()) - list.getTestCases().add( - new VTPTestCase().setTestCaseName( - n.get("command").getAsString()).setTestSuiteName( - n.get(SERVICE).getAsString())); - } + for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) { + JsonElement jsonElement = it.next(); + JsonObject n = jsonElement.getAsJsonObject(); + if (n.entrySet().iterator().hasNext()) + list.getTestCases().add( + new VTPTestCase().setTestCaseName( + n.get("command").getAsString()).setTestSuiteName( + n.get(SERVICE).getAsString())); + } } return list; @@ -201,9 +219,9 @@ public class VTPScenarioResource extends VTPResource{ message = "Failed to perform the operation", response = VTPError.class) }) public Response listTestcases( - @ApiParam("Test scenario name") @PathParam("scenario") String scenario, - @ApiParam("Test suite name") @QueryParam("testSuiteName") String testSuiteName - ) throws VTPException { + @ApiParam("Test scenario name") @PathParam("scenario") String scenario, + @ApiParam("Test suite name") @QueryParam("testSuiteName") String testSuiteName + ) throws VTPException { return Response.ok(this.listTestcasesHandler(testSuiteName, scenario).getTestCases().toString(), MediaType.APPLICATION_JSON).build(); } @@ -212,7 +230,7 @@ public class VTPScenarioResource extends VTPResource{ List<String> args = new ArrayList<>(); args.addAll(Arrays.asList( PRODUCT_ARG, OPEN_CLI, "schema-show", PRODUCT_ARG, scenario, "--service", testSuiteName, "--command", testCaseName , FORMAT, "json" - )); + )); JsonElement results = null; try { results = this.makeRpcAndGetJson(args); @@ -279,8 +297,148 @@ public class VTPScenarioResource extends VTPResource{ @ApiParam("Test scenario name") @PathParam("scenario") String scenario, @ApiParam(value = "Test case name") @PathParam("testSuiteName") String testSuiteName, @ApiParam(value = "Test case name") @PathParam("testCaseName") String testCaseName) - throws VTPException { + throws VTPException { return Response.ok(this.getTestcaseHandler(scenario, testSuiteName, testCaseName).toString(), MediaType.APPLICATION_JSON).build(); } -} + + @Path("/scenarios") + @POST + @ApiOperation(tags = "VTP Scenario", value = "Create Scenario") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)}) + public Response storageScenarios(@ApiParam(value = "file form data body parts", required = true) + @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException { + bodyParts.forEach(bodyPart -> { + BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity(); + String fileName = bodyPart.getContentDisposition().getFileName(); + if (!ToolUtil.isYamlFile(new File(fileName))) { + LOG.error("The fileName {} is not yaml !!!", fileName); + return; + } + String scenario = fileName.substring(0, fileName.indexOf("-registry")); + File scenarioDir = new File(VTP_YAML_STORE, scenario); + File yamlFile = new File(VTP_YAML_STORE, fileName); + + // 1、store the scenario yaml file and create the scenario dir + try { + FileUtils.deleteQuietly(yamlFile); + FileUtils.deleteDirectory(scenarioDir); + FileUtils.forceMkdir(scenarioDir); + FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile); + } catch (IOException e) { + LOG.error("Save yaml {} failed", fileName, e); + } + + // 2、create the testsuits dir and copy the testcase to current scenarios by commands + try { + Map<String, Object> yamlInfos = Maps.newHashMap(); + try (FileReader fileReader = new FileReader(yamlFile)) { + yamlInfos = snakeYaml().load(fileReader); + } + for (Object service : (List) yamlInfos.get("services")) { + Map<String, Object> serviceMap = (Map<String, Object>) service; + String testsuite = serviceMap.get("name").toString(); + File testsuiteDir = new File(scenarioDir, testsuite); + FileUtils.forceMkdir(testsuiteDir); + if (!serviceMap.containsKey("commands")) { + continue; + } + for (Object cmd : (List) serviceMap.get("commands")) { + File source = new File(VTP_YAML_STORE, cmd.toString().replaceAll("::", Matcher.quoteReplacement(File.separator))); + if (!source.isFile()) { + LOG.error("Source {} is not a yaml file !!!", source.getName()); + continue; + } + File dest = new File(testsuiteDir, cmd.toString().substring(cmd.toString().lastIndexOf("::") + 2)); + FileUtils.copyFile(source, dest); + + // 3、modify the testcase scenario and testsuite + Map<String, Object> result = Maps.newHashMap(); + try (FileReader fileReader = new FileReader(dest)) { + result = snakeYaml().load(fileReader); + } + Map<String, Object> info = (Map<String, Object>) result.get("info"); + info.put("product", scenario); + info.put("service", testsuite); + try (FileWriter fileWriter = new FileWriter(dest)) { + snakeYaml().dump(result, fileWriter); + } + } + } + } catch (Exception e) { + LOG.error("Parse testcase yaml failed !!!", e); + } + }); + return Response.ok("Save yaml success", MediaType.APPLICATION_JSON).build(); + } + + + @Path("/scenarios/{scenarioName}") + @DELETE + @ApiOperation(tags = "VTP Scenario", value = "Delete yaml string") + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)}) + public Response deleteScenario(@ApiParam("Test scenario yaml") @PathParam("scenarioName") String scenarioName) throws VTPException { + String scenario = scenarioName.substring(0, scenarioName.indexOf("-registry")); + File scenarioDir = new File(VTP_YAML_STORE, scenario); + List<File> yamls = FileUtil.searchFiles(scenarioDir, CommonConstant.YAML_SUFFIX); + if (!CollectionUtils.isEmpty(yamls)) { + LOG.error("The scenario yaml {} has sub testcase yamls, delete failed", scenarioName); + throw new VTPException( + new VTPError().setMessage(MessageFormat.format("The scenario yaml {0} has sub testcase yamls, delete failed !!!", scenarioName)) + .setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500)); + } + + try { + FileUtils.deleteQuietly(new File(VTP_YAML_STORE, scenarioName)); + FileUtils.deleteDirectory(scenarioDir); + } catch (IOException e) { + LOG.error("Delete scenario yaml {} failed", scenarioName, e); + throw new VTPException( + new VTPError().setMessage("Delete yaml failed !!!").setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500)); + } + return Response.ok("Delete yaml success", MediaType.APPLICATION_JSON).build(); + } + + @Path("/testcases") + @POST + @ApiOperation(tags = "VTP Scenario", value = "Create test case") + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)}) + public Response storageTestcases(@ApiParam(value = "file form data body parts", required = true) + @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException { + bodyParts.forEach(bodyPart -> { + BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity(); + String fileName = bodyPart.getContentDisposition().getFileName(); + if (ToolUtil.isYamlFile(new File(fileName))) { + // 1、store the testcase yaml file + Map<String, Object> result = snakeYaml().load(entity.getInputStream()); + Map<String, Object> info = (Map<String, Object>) result.get("info"); + + File yamlFile = new File(VTP_YAML_STORE, info.get("product") + File.separator + info.get("service") + File.separator + fileName); + try { + FileUtils.deleteQuietly(yamlFile); + FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile); + } catch (IOException e) { + LOG.error("Save testcase yaml {} failed", yamlFile.getName(), e); + } + } else { + // 2、store the testcase script file + File scriptFile = new File(VTP_SCRIPT_STORE, fileName); + try { + FileUtils.deleteQuietly(scriptFile); + FileUtils.copyInputStreamToFile(entity.getInputStream(), scriptFile); + } catch (IOException e) { + LOG.error("Save testcase script {} failed", scriptFile.getName(), e); + } + } + }); + return Response.ok("Save success", MediaType.APPLICATION_JSON).build(); + } +}
\ No newline at end of file diff --git a/vnfmarket-be/vnf-sdk-marketplace/src/main/resources/vtp.properties b/vnfmarket-be/vnf-sdk-marketplace/src/main/resources/vtp.properties index d0e89d81..f7a579da 100644 --- a/vnfmarket-be/vnf-sdk-marketplace/src/main/resources/vtp.properties +++ b/vnfmarket-be/vnf-sdk-marketplace/src/main/resources/vtp.properties @@ -17,4 +17,8 @@ vtp.grpc.port = 50051 vtp.artifact.store = /tmp/data/vtp-artifacts vtp.file.store = /tmp/data/vtp-tmp-files #60 seconds -vtp.grpc.timeout = 60
\ No newline at end of file +vtp.grpc.timeout = 60 + +#scenariotestsuittestcase store +vtp.yaml.store = /opt/oclip/open-cli-schema/vtp +vtp.script.store = /opt/oclip/script/vtp
\ No newline at end of file |