Implementation for TMF 633 API - POST /serviceSpecification 54/111754/1
authorNikhilMohan <nikmohan81@gmail.com>
Wed, 26 Aug 2020 15:00:48 +0000 (20:30 +0530)
committernikhil mohan <nikmohan81@gmail.com>
Wed, 26 Aug 2020 15:04:02 +0000 (20:34 +0530)
Issue-ID: EXTAPI-488

Signed-off-by: nikhil mohan <nikmohan81@gmail.com>
Change-Id: I382e3b2bfbde656508bcfb0c86e748f21a7790d2

src/main/java/org/onap/nbi/apis/servicecatalog/SdcClient.java
src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationResource.java
src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationService.java
src/main/java/org/onap/nbi/exceptions/ApiExceptionHandler.java
src/main/java/org/onap/nbi/exceptions/BackendErrorHandler.java
src/test/resources/karatetest/data/serviceSpecification.json [new file with mode: 0644]
src/test/resources/karatetest/features/00--ServiceCatalog.feature
src/test/resources/mappings/sdc/sdc_post_spec.json [new file with mode: 0644]

index e362903..29a4a25 100644 (file)
@@ -22,9 +22,7 @@ import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.Map.Entry;
 import javax.annotation.PostConstruct;
 import org.apache.commons.io.IOUtils;
@@ -42,6 +40,7 @@ import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
 import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 
@@ -66,6 +65,8 @@ public class SdcClient {
 
     private static final String HEADER_ECOMP_INSTANCE_ID = "x-ecomp-instanceid";
     private static final String HEADER_AUTHORIZATION = "Authorization";
+    // changes for Post Implementation
+    private static final String USER_ID = "USER_ID";
 
     private static final Logger LOGGER = LoggerFactory.getLogger(SdcClient.class);
 
@@ -156,6 +157,19 @@ public class SdcClient {
 
         return createTmpFile(inputStream);
     }
+    /**
+     *
+     * @param serviceCatalogObject
+     * @param userId
+     */
+    public Map callPost(HashMap<Object, Object> serviceCatalogObject, String userId) {
+        // post url is the same as find url
+        UriComponentsBuilder callURI = UriComponentsBuilder.fromHttpUrl(sdcFindUrl);
+        ResponseEntity<Object> response = callSdcForPost(callURI.build().encode().toUri(), serviceCatalogObject,
+                userId);
+        // return (List<LinkedHashMap>) response.getBody();
+        return (LinkedHashMap) response.getBody();
+    }
 
     private Path createTmpFile(InputStream csarInputStream) throws IOException {
         Path csarFile = Files.createTempFile("csar", ".zip");
@@ -208,4 +222,46 @@ public class SdcClient {
                     response.getBody().toString());
         }
     }
+
+    //changes for Post implementation start
+    /**
+     *
+     * @param callURI
+     * @param obj
+     * @param userId
+     * @return
+     */
+    private ResponseEntity<Object> callSdcForPost(URI callURI, Object obj, String userId) {
+        ResponseEntity<Object> response = restTemplate.exchange(callURI, HttpMethod.POST,
+                new HttpEntity<>(obj, buildRequestHeaderForPost(userId)), Object.class);
+
+        if (null == response) {
+            return null;
+        } else {
+
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("response body : {} ", response.getBody().toString());
+            }
+            LOGGER.info("response status : {}", response.getStatusCodeValue());
+            return response;
+        }
+
+    }
+    /**
+     *
+     * @param userId
+     * @return
+     */
+    private HttpHeaders buildRequestHeaderForPost(String userId) {
+        HttpHeaders httpHeaders = new HttpHeaders();
+
+        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+        httpHeaders.add(HEADER_ECOMP_INSTANCE_ID, ecompInstanceId);
+        httpHeaders.add(HEADER_AUTHORIZATION, sdcHeaderAuthorization);
+        httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
+        httpHeaders.add(USER_ID, userId);
+
+        return httpHeaders;
+    }
+
 }
index 128bc6c..a0c27e7 100644 (file)
 
 package org.onap.nbi.apis.servicecatalog;
 
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import org.onap.nbi.OnapComponentsUrlPaths;
+import org.onap.nbi.apis.servicecatalog.model.ServiceSpecificationRequest;
 import org.onap.nbi.commons.JsonRepresentation;
 import org.onap.nbi.commons.ResourceManagement;
+import org.onap.nbi.exceptions.ValidationException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.util.MultiValueMap;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
+import javax.validation.Valid;
 
 @RestController
 @RequestMapping(OnapComponentsUrlPaths.SERVICE_SPECIFICATION_PATH)
@@ -42,17 +46,17 @@ public class ServiceSpecificationResource extends ResourceManagement {
 
     @GetMapping(value = "/{serviceSpecId}", produces = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity<Object> getServiceSpecification(@PathVariable String serviceSpecId,
-            @RequestParam MultiValueMap<String, String> params) {
+                                                          @RequestParam MultiValueMap<String, String> params) {
         Map response = serviceSpecificationService.get(serviceSpecId);
 
         if (response != null) {
-           ArrayList<Map<String, Object>> resourseSpecificationMap= (ArrayList<Map<String, Object>>) response.get("resourceSpecification");
-           for (Map<String, Object> map : resourseSpecificationMap) {
-               map.remove("childResourceSpecification");
-               map.remove("serviceInstanceParams");
-               map.remove("InstanceSpecification");
-           }
-           response.put("resourceSpecification", resourseSpecificationMap);
+            ArrayList<Map<String, Object>> resourseSpecificationMap= (ArrayList<Map<String, Object>>) response.get("resourceSpecification");
+            for (Map<String, Object> map : resourseSpecificationMap) {
+                map.remove("childResourceSpecification");
+                map.remove("serviceInstanceParams");
+                map.remove("InstanceSpecification");
+            }
+            response.put("resourceSpecification", resourseSpecificationMap);
         }
 
         JsonRepresentation filter = new JsonRepresentation(params);
@@ -73,10 +77,35 @@ public class ServiceSpecificationResource extends ResourceManagement {
 
     @GetMapping(value = "/{serviceSpecId}/specificationInputSchema", produces = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity<Object> findSpecificationInputSchema(@PathVariable String serviceSpecId,
-            @RequestParam MultiValueMap<String, String> params) {
+                                                               @RequestParam MultiValueMap<String, String> params) {
         String response = serviceSpecificationService.getInputSchema(serviceSpecId);
         JsonRepresentation filter = new JsonRepresentation(params);
         return this.getResponse(response, filter);
     }
 
+    @PostMapping(value = "", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+    public Object createServiceSpecification(@RequestHeader(value = "USER_ID", required = true) String userId,
+                                             @Valid @RequestBody ServiceSpecificationRequest serviceSpecificationRequest, BindingResult result) {
+        if (null == userId || userId.isEmpty()) {
+            result.addError(new ObjectError("USER_ID", "USER_ID is missing in header!"));
+        }
+        if (result.hasErrors()) {
+            throw new ValidationException(result.getAllErrors());
+        }
+        Map serviceCatalogResponse = serviceSpecificationService.create(userId, serviceSpecificationRequest);
+
+        return createResponse(serviceCatalogResponse);
+    }
+    /**
+     *
+     * @param resource
+     * @return
+     */
+    private ResponseEntity<Object> createResponse(final Map resource) {
+        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(resource.get("id"))
+                .toUri();
+        return ResponseEntity.created(location).body(resource);
+
+    }
+
 }
\ No newline at end of file
index 9fc0ec0..45a4f3f 100644 (file)
@@ -17,13 +17,15 @@ package org.onap.nbi.apis.servicecatalog;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.io.FileUtils;
 import org.onap.nbi.apis.servicecatalog.jolt.FindServiceSpecJsonTransformer;
 import org.onap.nbi.apis.servicecatalog.jolt.GetServiceSpecJsonTransformer;
+import org.onap.nbi.apis.servicecatalog.jolt.PostServiceResponseSpecJsonTransformer;
+import org.onap.nbi.apis.servicecatalog.jolt.PostServiceSpecJsonTransformer;
+import org.onap.nbi.apis.servicecatalog.model.ServiceSpecificationRequest;
 import org.onap.nbi.apis.serviceorder.ServiceCatalogUrl;
 import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;
 import org.slf4j.Logger;
@@ -45,6 +47,13 @@ public class ServiceSpecificationService {
     @Autowired
     FindServiceSpecJsonTransformer findServiceSpecJsonTransformer;
 
+    // Change for processing POST request
+    @Autowired
+    PostServiceSpecJsonTransformer postServiceSpecJsonTransformer;
+
+    @Autowired
+    PostServiceResponseSpecJsonTransformer postServiceResponseSpecJsonTransformer ;
+
     @Autowired
     ToscaInfosProcessor toscaInfosProcessor;
 
@@ -101,4 +110,21 @@ public class ServiceSpecificationService {
             return null;
         }
     }
+
+    public Map create(String userId, ServiceSpecificationRequest specRequest) {
+        ObjectMapper mapper = new ObjectMapper();
+        LinkedHashMap specRequestMap = mapper.convertValue(specRequest, LinkedHashMap.class);
+        HashMap<Object, Object> serviceCatalogInput = (HashMap) postServiceSpecJsonTransformer.transform(specRequestMap);
+
+        //Call SDC Post API
+        Map sdcResponse = sdcClient.callPost(serviceCatalogInput,userId);
+        LOGGER.info("SDC response " + sdcResponse);
+        //Transform SDC Response
+        LinkedHashMap<Object,Object> serviceCatalogResponse =null;
+        if (!CollectionUtils.isEmpty(sdcResponse)) {
+            serviceCatalogResponse = (LinkedHashMap)postServiceResponseSpecJsonTransformer.transform(sdcResponse);
+        }
+        return serviceCatalogResponse;
+    }
+
 }
index c68e6d3..1fe6a8c 100644 (file)
@@ -16,6 +16,7 @@
 
 package org.onap.nbi.exceptions;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.ControllerAdvice;
@@ -56,4 +57,11 @@ public class ApiExceptionHandler {
         ApiError apiError = new ApiError("400", HttpStatus.BAD_REQUEST.getReasonPhrase(), exception.getMessages(), "");
         return new ResponseEntity<>(apiError, HttpStatus.BAD_REQUEST);
     }
+
+    @ExceptionHandler(JsonProcessingException.class)
+    @ResponseBody
+    public ResponseEntity<ApiError> validationExceptionHandler(final JsonProcessingException exception) {
+        ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST.name(), HttpStatus.BAD_REQUEST.getReasonPhrase(), "Request data is invalid!", "");
+        return new ResponseEntity<>(apiError, HttpStatus.BAD_REQUEST);
+    }
 }
index 48bf630..488ebd7 100644 (file)
@@ -19,6 +19,8 @@ package org.onap.nbi.exceptions;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.http.client.ClientHttpResponse;
 import org.springframework.web.client.DefaultResponseErrorHandler;
 import org.springframework.web.client.ResponseErrorHandler;
@@ -26,7 +28,7 @@ import org.springframework.web.client.ResponseErrorHandler;
 public class BackendErrorHandler implements ResponseErrorHandler {
 
     private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();
-
+    private static final Logger LOGGER = LoggerFactory.getLogger(BackendErrorHandler.class);
     @Override
     public boolean hasError(ClientHttpResponse response) throws IOException {
         return errorHandler.hasError(response);
@@ -38,6 +40,7 @@ public class BackendErrorHandler implements ResponseErrorHandler {
             String body = null;
             if (response.getBody() != null) {
                 body = IOUtils.toString(response.getBody(), StandardCharsets.UTF_8.name());
+                LOGGER.error("BackendErrorHandler {} error : {}", response.getBody());
             }
 
             throw new BackendFunctionalException(response.getStatusCode(), response.getStatusText(), body);
diff --git a/src/test/resources/karatetest/data/serviceSpecification.json b/src/test/resources/karatetest/data/serviceSpecification.json
new file mode 100644 (file)
index 0000000..858aa11
--- /dev/null
@@ -0,0 +1,195 @@
+[
+  {
+    "name": "partner-service",
+    "description": "A test service through TMF API 633",
+    "@type": "ServiceSpecification",
+    "@schemaLocation": null,
+    "@baseType": "Service",
+    "toscaModelURL": "/",
+    "toscaResourceName": "",
+    "category": "Partner Domain Service",
+    "subcategory": "subservice",
+    "version": "1.0",
+    "lifecycleStatus": "NOT_CERTIFIED_CHECKOUT",
+    "DistributionStatus": "DISTRIBUTION_NOT_APPROVED",
+    "targetServiceSchema": {
+      "@type": "string",
+      "@schemaLocation": "/"
+    },
+    "attachment": [{
+      "id" : "1eadef",
+      "name" : "info-artifact",
+      "description" : "informational",
+      "artifactLabel" : "notes",
+      "artifactGroupType" : "info",
+      "artifactTimeout" : "500",
+      "artifactChecksum" : "adef23",
+      "artifactVersion" : "1.0",
+      "generatedFromUUID" : "a12e",
+      "url" : "/artifact/info/1eadef",
+      "mimeType" : "text",
+      "@type" : "ONAPartifact"
+    }
+
+    ],
+    "relatedParty": [
+      {
+        "id": "cs0008",
+        "role": "designer",
+        "name": "Carlos Santana"
+      }
+    ],
+    "resourceSpecification": [
+      {
+        "id" : "281abc4d",
+        "version" : "1.0",
+        "name" : "vfirewall",
+        "resourceInstanceName" : "vfirewallinst",
+        "modelCustomizationName" : "vfirewallinst",
+        "resourceInvariantUUID" : "123ebdf",
+        "resourceType" : "VNF",
+        "@type" : "ONAPresource"
+      }
+    ],
+    "serviceSpecCharacteristic": [
+      {
+        "name": "firewall",
+        "description": "Firewall characteristic",
+        "valueType": "string",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "string",
+            "isDefault": true,
+            "value": "NA"
+          }
+        ]
+      },
+      {
+        "name": "isBundled",
+        "description": "is bundled or not",
+        "valueType": "boolean",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "boolean",
+            "isDefault": true,
+            "value": true
+          }
+        ]
+      },
+      {
+        "name": "NumberofPort",
+        "description": "NumberofPorts",
+        "valueType": "integer",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "string",
+            "isDefault": false,
+            "value": "10"
+          }
+        ]
+      },
+      {
+        "name": "ipaddress",
+        "description": "ipaddress",
+        "valueType": "float",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "string",
+            "isDefault": false,
+            "value": "15.123.9.101"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "@type": "ServiceSpecification",
+    "@schemaLocation": null,
+    "@baseType": "Service",
+    "toscaModelURL": "/",
+    "toscaResourceName": "",
+    "subcategory": "subservice",
+    "version": "1.0",
+    "lifecycleStatus": "NOT_CERTIFIED_CHECKOUT",
+    "targetServiceSchema": {
+      "@type": "string",
+      "@schemaLocation": "/"
+    },
+    "attachment": [],
+    "resourceSpecification": [],
+    "serviceSpecCharacteristic": [
+      {
+        "name": "firewall",
+        "description": "Firewall characteristic",
+        "valueType": "string",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "string",
+            "isDefault": true,
+            "value": "NA"
+          }
+        ]
+      },
+      {
+        "name": "isBundled",
+        "description": "is bundled or not",
+        "valueType": "boolean",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "boolean",
+            "isDefault": true,
+            "value": true
+          }
+        ]
+      },
+      {
+        "name": "NumberofPorts",
+        "description": "Number of Ports",
+        "valueType": "integer",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "string",
+            "isDefault": false,
+            "value": "10"
+          }
+        ]
+      },
+      {
+        "name": "ipaddress",
+        "description": "ipaddress",
+        "valueType": "string",
+        "@type": "string",
+        "@schemaLocation": "string",
+        "required": true,
+        "serviceSpecCharacteristicValue": [
+          {
+            "valueType": "string",
+            "isDefault": true,
+            "value": "10.244.34.1"
+          }
+        ]
+      }
+    ]
+  }
+]
\ No newline at end of file
index 2a4a5c0..1887498 100644 (file)
@@ -20,9 +20,10 @@ Feature: Service Catalog
 Background:
 * url nbiBaseUrl
 * def Context = Java.type('org.onap.nbi.test.Context');
+* def data = read('../data/serviceSpecification.json')
 * configure readTimeout = 30000
 * call Context.startServers();
-    
+
 Scenario: testServiceCatalogGetResourceWithoutTosca
 Given path 'serviceSpecification','1e3feeb0-8e36-46c6-862c-236d9c626439_withoutTosca'
 When method get
@@ -127,4 +128,74 @@ When method get
 Then status 500
 * call Context.startServers();
 
+Scenario: testCreateServiceSpec
+Given path 'serviceSpecification'
+And header USER_ID = 'cs0008'
+And request data[0]
+When method post
+Then status 201
+And match $.id contains '#notnull'
+And match $.lifecycleStatus == 'NOT_CERTIFIED_CHECKOUT'
+And match $.serviceSpecCharacteristic ==
+"""
+[ {
+    "name" : "isBundle",
+    "description" : "is bundled or not",
+    "valueType" : "boolean",
+    "required" : true,
+    "serviceSpecCharacteristicValue" : [ {
+      "value" : "true",
+      "isDefault" : true
+    } ]
+  }, {
+    "name" : "ipaddress",
+    "description" : "ipaddress",
+    "valueType" : "string",
+    "required" : true,
+    "serviceSpecCharacteristicValue" : [ {
+      "value" : "10.244.34.1",
+      "isDefault" : true
+    } ]
+  }, {
+    "name" : "firewall",
+    "description" : "Firewall characteristic",
+    "valueType" : "string",
+    "required" : true,
+    "serviceSpecCharacteristicValue" : [ {
+      "value" : "NA",
+      "isDefault" : true
+    } ]
+  }, {
+    "name" : "NumberofPorts",
+    "description" : "Number of Ports",
+    "valueType" : "integer",
+    "required" : true,
+    "serviceSpecCharacteristicValue" : [ {
+      "value" : "10",
+      "isDefault" : true
+    } ]
+  } ]
+"""
+
+Scenario: testCreateServiceSpecWithoutUser
+Given path 'serviceSpecification'
+And request data[0]
+When method post
+Then status 400
+And match $.message contains "Missing request header 'USER_ID'"
+
+Scenario: testCreateServiceSpecWithoutPayload
+Given path 'serviceSpecification'
+And header USER_ID = 'cs0008'
+And request {}
+When method post
+Then status 400
+
+Scenario: testCreateServiceSpecWithoutMandatoryDetails
+Given path 'serviceSpecification'
+And header USER_ID = 'cs0008'
+And request data[1]
+When method post
+Then status 400
+And match $.message contains 'Bad Request'
 
diff --git a/src/test/resources/mappings/sdc/sdc_post_spec.json b/src/test/resources/mappings/sdc/sdc_post_spec.json
new file mode 100644 (file)
index 0000000..41e724f
--- /dev/null
@@ -0,0 +1,106 @@
+{
+  "request": {
+    "method": "POST",
+    "url": "/sdc/v1/catalog/services",
+    "headers": {
+      "USER_ID": {
+        "contains": "cs0008"
+      }
+    },
+    "bodyPatterns": [
+      {
+        "contains": "\"name\":\"partner-service\""
+      }
+    ]
+  },
+  "response": {
+    "status": 201,
+    "jsonBody": {
+      "uuid": "1e3feeb0-8e36-46c6-862c-236d9c626439",
+      "href": "/serviceSpecification/1e3feeb0-8e36-46c6-862c-236d9c626439",
+      "name": "partner-service",
+      "description": "service",
+      "@type": "ServiceSpecification",
+      "@schemaLocation": null,
+      "@baseType": "Service",
+      "toscaModelURL": "/",
+      "toscaResourceName": "string",
+      "category": "Partner Domain Service",
+      "subcategory": "string",
+      "version": "1.0",
+      "lifecycleState": "NOT_CERTIFIED_CHECKOUT",
+      "targetServiceSchema": {
+        "@type": "string",
+        "@schemaLocation": "/"
+      },
+      "artifacts": [
+        {
+          "artifactUUID": "1eadef",
+          "artifactName": "info-artifact",
+          "artifactDescription": "informational",
+          "artifactLabel": "notes",
+          "artifactGroupType": "info",
+          "artifactTimeout": "500",
+          "artifactChecksum": "adef23",
+          "artifactVersion": "1.0",
+          "generatedFromUUID": "a12e",
+          "artifactURL": "/artifact/info/1eadef",
+          "artifactType": "text"
+        }
+      ],
+      "lastUpdaterUserId": "cs0008",
+      "lastUpdaterFullName": "Carlos Santana",
+      "resources": [
+        {
+          "resourceUUID": "281abc4d",
+          "resourceVersion": "1.0",
+          "resourceName": "vfirewall",
+          "resourceInstanceName": "vfirewallinst",
+          "resourceInvariantUUID": "123ebdf",
+          "resoucreType": "VNF"
+        }
+      ],
+      "properties": [
+        {
+          "type": "boolean",
+          "required": true,
+          "definition": false,
+          "description": "is bundled or not",
+          "name": "isBundle",
+          "value": "true",
+          "defaultValue": true
+        },
+        {
+          "type": "string",
+          "required": true,
+          "definition": false,
+          "description": "ipaddress",
+          "name": "ipaddress",
+          "value": "10.244.34.1",
+          "defaultValue": true
+        },
+        {
+          "type": "string",
+          "required": true,
+          "definition": false,
+          "description": "Firewall characteristic",
+          "name": "firewall",
+          "value": "NA",
+          "defaultValue": true
+        },
+        {
+          "type": "integer",
+          "required": true,
+          "definition": false,
+          "description": "Number of Ports",
+          "name": "NumberofPorts",
+          "value": "10",
+          "defaultValue": true
+        }
+      ]
+    },
+    "headers": {
+      "Content-Type": "application/json"
+    }
+  }
+}
\ No newline at end of file