Scenario active management 37/111937/1
authorCooper.Wu <wutuo@chinamobile.com>
Tue, 1 Sep 2020 08:11:48 +0000 (16:11 +0800)
committerCooper.Wu <wutuo@chinamobile.com>
Tue, 1 Sep 2020 08:12:10 +0000 (16:12 +0800)
Issue-ID: VNFSDK-613
Change-Id: I0d89a53d5aa5c31137b25e1a65075fdb1e3504da
Signed-off-by: Cooper.Wu <wutuo@chinamobile.com>
vnfmarket-be/vnf-sdk-marketplace/pom.xml
vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vnfsdk/marketplace/common/CommonConstant.java
vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/VTPResource.java
vnfmarket-be/vnf-sdk-marketplace/src/main/java/org/onap/vtp/scenario/VTPScenarioResource.java
vnfmarket-be/vnf-sdk-marketplace/src/main/resources/vtp.properties

index 3dcda1a..3fbfb22 100644 (file)
             <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>
index 60d2a22..cc3cbe9 100644 (file)
@@ -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";
index 0d813c7..9e1a9c8 100644 (file)
@@ -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);
+    }
 }
index 4b31932..2eff61f 100644 (file)
 
 package org.onap.vtp.scenario;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import java.io.*;
+import java.text.MessageFormat;
+import java.util.*;
+import java.util.regex.Matcher;
+
+import javax.ws.rs.*;
 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.ToolUtil;
 import org.onap.vtp.VTPResource;
 import org.onap.vtp.error.VTPError;
 import org.onap.vtp.error.VTPError.VTPException;
@@ -283,4 +286,153 @@ public class VTPScenarioResource extends VTPResource{
 
         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.copyInputStreamToFile(entity.getInputStream(), yamlFile);
+                FileUtils.forceMkdir(scenarioDir);
+            } 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 (!cn.hutool.core.io.FileUtil.isFile(source)) {
+                            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 = cn.hutool.core.io.FileUtil.loopFiles(scenarioDir, new FileFilter() {
+            @Override
+            public boolean accept(File pathname) {
+                final String path = pathname.getPath();
+                if (null != path && path.endsWith(CommonConstant.YAML_SUFFIX)) {
+                    return true;
+                }
+                return false;
+            }
+        });
+        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();
+    }
 }
index d0e89d8..f7a579d 100644 (file)
@@ -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
+
+#scenario¡¢testsuit¡¢testcase store
+vtp.yaml.store = /opt/oclip/open-cli-schema/vtp
+vtp.script.store = /opt/oclip/script/vtp
\ No newline at end of file