From c727082e6809f7a3076809dceb218e80ce4456bf Mon Sep 17 00:00:00 2001 From: Norm Traxler Date: Tue, 5 Feb 2019 19:58:05 +0000 Subject: Service Decomposition support for network Issue-ID: SDNC-475 Add decompose of service-instance and vf-module "l3-network" relationships. Some Sonar cleanup. Change-Id: Ie944e6d8acac05ebdce1753176455d929daa2e97 Signed-off-by: Norm Traxler --- .../AAIBasicAuthCondition.java | 2 +- .../AAIClientCertCondition.java | 2 +- .../servicedecomposition/AAIConfiguration.java | 3 +- .../exception/DiscoveryException.java | 3 +- .../service/SpringServiceImpl.java | 22 +- .../service/rs/RestServiceImpl.java | 6 +- .../pomba/servicedecomposition/util/RestUtil.java | 285 ++++++++------- .../test/AuthorizationConfigurationTest.java | 6 +- .../test/ServiceDecompositionTest.java | 83 ++++- .../test/TestHttpServletRequest.java | 392 --------------------- .../src/test/resources/junit/aai-generic-vnf2.json | 9 +- .../resources/junit/aai-service-instance2.json | 47 +++ 12 files changed, 301 insertions(+), 559 deletions(-) delete mode 100644 pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/TestHttpServletRequest.java create mode 100644 pomba/service-decomposition/src/test/resources/junit/aai-service-instance2.json (limited to 'pomba') diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIBasicAuthCondition.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIBasicAuthCondition.java index 512500a..0990902 100644 --- a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIBasicAuthCondition.java +++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIBasicAuthCondition.java @@ -27,6 +27,6 @@ public class AAIBasicAuthCondition implements Condition { public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String authenticationMode = conditionContext.getEnvironment().getProperty("aai.authentication"); - return authenticationMode.equalsIgnoreCase("basic_auth"); + return "basic_auth".equalsIgnoreCase(authenticationMode); } } diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIClientCertCondition.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIClientCertCondition.java index 6c77f73..39f17fe 100644 --- a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIClientCertCondition.java +++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIClientCertCondition.java @@ -27,6 +27,6 @@ public class AAIClientCertCondition implements Condition { public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String authenticationMode = conditionContext.getEnvironment().getProperty("aai.authentication"); - return authenticationMode.equalsIgnoreCase("client_cert"); + return "client_cert".equalsIgnoreCase(authenticationMode); } } diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java index ad60b4a..9ef29a5 100644 --- a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java +++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/AAIConfiguration.java @@ -101,8 +101,7 @@ public class AAIConfiguration { @Bean(name="aaiClient") public RestClient restClientWithClientCert() { RestClient restClient = new RestClient(); - System.out.println("in client cert"); - if (httpProtocol.equals("https")) + if ("https".equals(httpProtocol)) restClient.validateServerHostname(false).validateServerCertChain(false).trustStore(trustStorePath).clientCertFile(keyStorePath).clientCertPassword(keyStorePassword).connectTimeoutMs(connectionTimeout).readTimeoutMs(readTimeout); else restClient.validateServerHostname(false).validateServerCertChain(false).connectTimeoutMs(connectionTimeout).readTimeoutMs(readTimeout); diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java index eee34fe..888b30b 100644 --- a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java +++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/exception/DiscoveryException.java @@ -53,7 +53,7 @@ public class DiscoveryException extends Exception { private static final long serialVersionUID = -4874149714911165454L; private final Status httpStatus; - private String responseCode; + private final String responseCode; public DiscoveryException(Error error, Status httpStatus, Object... args) { super(error.getMessage(args)); @@ -66,6 +66,7 @@ public class DiscoveryException extends Exception { public DiscoveryException(Error error, Exception cause, Object... args) { super(error.getMessage(args), cause); + this.responseCode = error.getResponseCode(); this.httpStatus = Status.INTERNAL_SERVER_ERROR; } diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java index 56685ad..22a7d4a 100644 --- a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java +++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/SpringServiceImpl.java @@ -25,7 +25,6 @@ import org.onap.sdnc.apps.pomba.servicedecomposition.util.RestUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.*; @org.springframework.stereotype.Service @@ -49,25 +48,14 @@ public class SpringServiceImpl implements SpringService { private String aaiResourceList; @Override - public String decomposeService(String fromAppId, - String transactionId, - String serviceInstanceId, - ONAPLogAdapter adapter) throws DiscoveryException { + public String decomposeService(String fromAppId, String transactionId, String serviceInstanceId, + ONAPLogAdapter adapter) throws DiscoveryException { + log.info("Querying A&AI for service instance {}", serviceInstanceId); - log.info("Querying A&AI for service instance " + serviceInstanceId); - JSONObject serviceInstance = null; - - try { - serviceInstance = RestUtil.retrieveAAIModelData(aaiClient, aaiBaseUrl, aaiBasicAuthorization, aaiServiceInstancePath, aaiResourceList, - transactionId, serviceInstanceId, adapter); - } catch (DiscoveryException de) { - throw de; - } catch (Exception e) { - throw new DiscoveryException(GENERAL_FAILURE, e , e.getLocalizedMessage()); - } + JSONObject serviceInstance = RestUtil.retrieveAAIModelData(aaiClient, aaiBaseUrl, aaiBasicAuthorization, + aaiServiceInstancePath, aaiResourceList, transactionId, serviceInstanceId); return serviceInstance.toString(); } - } diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java index 6840b82..7dcd3de 100644 --- a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java +++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/service/rs/RestServiceImpl.java @@ -49,8 +49,6 @@ public class RestServiceImpl implements RestService { @Resource(name="basicAuthHeader") private String basicAuthHeader; - public RestServiceImpl() {} - @Override public Response getContext(HttpServletRequest request, String authorization, @@ -72,7 +70,7 @@ public class RestServiceImpl implements RestService { } if (transactionId == null || transactionId.isEmpty()) { transactionId = UUID.randomUUID().toString(); - log.debug(ONAPLogConstants.Headers.REQUEST_ID+ " is missing; using newly generated value: " + transactionId); + log.debug("{} is missing; using newly generated value: {}", ONAPLogConstants.Headers.REQUEST_ID, transactionId); } RestUtil.validateURL(serviceInstanceId); String context = service.decomposeService(fromAppId, transactionId, serviceInstanceId, adapter); @@ -84,6 +82,7 @@ public class RestServiceImpl implements RestService { return Response.ok().entity(context).build(); } catch (DiscoveryException x) { + log.error(x.getHttpStatus().getReasonPhrase(), x); adapter.getResponseDescriptor() .setResponseCode(x.getResponseCode()) .setResponseStatus(ResponseStatus.ERROR); @@ -95,6 +94,7 @@ public class RestServiceImpl implements RestService { return builder.build(); } catch (Exception e) { + log.error(Status.INTERNAL_SERVER_ERROR.getReasonPhrase(), e); adapter.getResponseDescriptor() .setResponseCode(GENERAL_FAILURE.getResponseCode()) .setResponseStatus(ResponseStatus.ERROR); diff --git a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java index ffd7bf8..af2f7be 100644 --- a/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java +++ b/pomba/service-decomposition/src/main/java/org/onap/sdnc/apps/pomba/servicedecomposition/util/RestUtil.java @@ -19,25 +19,24 @@ package org.onap.sdnc.apps.pomba.servicedecomposition.util; import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.FETCH_RESOURCE_FAILED; import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.INVALID_URL; -import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.RELATIONSHIP_LINK_PARSE_ERROR; import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.SERVICE_INSTANCE_NOT_FOUND; -import static org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException.Error.SERVICE_RELATIONSHIP_PARSE_ERROR; -import com.sun.jersey.core.util.MultivaluedMapImpl; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; + import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response.Status; + import org.json.JSONArray; import org.json.JSONObject; import org.onap.aai.restclient.client.OperationResult; import org.onap.aai.restclient.client.RestClient; -import org.onap.logging.ref.slf4j.ONAPLogAdapter; import org.onap.sdnc.apps.pomba.servicedecomposition.exception.DiscoveryException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,6 +45,10 @@ import org.slf4j.LoggerFactory; public class RestUtil { + + + private static final String RELATIONSHIP_KEY = "relationship"; + private static final String RELATIONSHIP_LIST_KEY = "relationship-list"; // Parameters for Query AAI Model Data API // HTTP headers private static final String TRANSACTION_ID = "X-TransactionId"; @@ -54,6 +57,8 @@ public class RestUtil { private static final String AUTHORIZATION = "Authorization"; private static final Resource GENERIC_VNF = new Resource("generic-vnf"); + private static final Resource VF_MODULE = new Resource("vf-module"); + private static final Resource L3_NETWORK = new Resource("l3-network"); public static class Resource { private String resourceName; @@ -71,6 +76,11 @@ public class RestUtil { private String getCollectionName() { return this.collectionName; } + + @Override + public String toString() { + return "Resource [resourceName=" + resourceName + ", collectionName=" + collectionName + "]"; + } } private static final String JSON_ATT_RELATED_TO = "related-to"; @@ -81,6 +91,10 @@ public class RestUtil { private static final String DEPTH = "?depth=2"; private static Logger logger = LoggerFactory.getLogger(RestUtil.class); + private RestUtil() { + throw new IllegalStateException("Utility class"); + } + /** * Validates the URL parameter. * @@ -97,11 +111,6 @@ public class RestUtil { return MessageFormat.format(siPath, serviceInstanceId); } - - /* - * Trigger external API call to AAI to retrieve Service Instance data (i.e. genericVNF and VNFC) - */ - /** * @param aaiClient * @param baseURL @@ -115,7 +124,7 @@ public class RestUtil { * @throws DiscoveryException */ public static JSONObject retrieveAAIModelData(RestClient aaiClient, String baseURL, String aaiBasicAuthorization, String aaiServiceInstancePath, String aaiResourceList, - String transactionId, String serviceInstanceId, ONAPLogAdapter adapter) throws DiscoveryException { + String transactionId, String serviceInstanceId) throws DiscoveryException { // Follow two variables for transform purpose String url = baseURL + generateServiceInstanceURL(aaiServiceInstancePath, serviceInstanceId); @@ -123,20 +132,29 @@ public class RestUtil { JSONObject serviceInstancePayload = new JSONObject( getResource(aaiClient, url, aaiBasicAuthorization, transactionId)); // Handle the case if the service instance is not found in AAI - if (serviceInstancePayload == null || serviceInstancePayload.length() == 0) { - logger.info("Service Instance " + serviceInstanceId + " is not found from AAI"); + if (serviceInstancePayload.length() == 0) { + logger.info("Service Instance {} is not found from AAI", serviceInstanceId); // Only return the empty Json on the root level. i.e service instance throw new DiscoveryException(SERVICE_INSTANCE_NOT_FOUND, Status.NOT_FOUND); } - HashMap> relationMap = extractServiceRelationShips(serviceInstancePayload); - logger.info("The number of the relationships for service instance id {} is: {}", serviceInstanceId, + Map> relationMap = extractRelationships(serviceInstancePayload); + logger.info("The number of the relationship types for service instance id {} is: {}", serviceInstanceId, relationMap.size()); JSONObject response = processVNFRelationMap(aaiClient, aaiResourceList, baseURL, aaiBasicAuthorization, transactionId, relationMap, serviceInstancePayload); + + if (relationMap.containsKey(L3_NETWORK.getResourceName())) { + List l3NetworkRelatedLinks = relationMap.get(L3_NETWORK.getResourceName()); + List l3networkPayload = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId, + L3_NETWORK.getResourceName(), l3NetworkRelatedLinks); + + response.put(L3_NETWORK.getCollectionName(), l3networkPayload); + } + return response; - } + } /** * @param aaiClient @@ -146,46 +164,100 @@ public class RestUtil { * @throws DiscoveryException */ private static JSONObject processVNFRelationMap(RestClient aaiClient, String aaiResourceList, String baseURL, String aaiBasicAuthorization, String transactionId, - HashMap> relationMap, JSONObject serviceInstancePayload) throws DiscoveryException { - List vnfLst = new ArrayList(); // List of the VNF JSON along with related resources + Map> relationMap, JSONObject serviceInstancePayload) throws DiscoveryException { + List vnfLst = new ArrayList<>(); // List of the VNF JSON along with related resources JSONObject response = serviceInstancePayload; List resourceTypes = getResourceTypes(aaiResourceList); if (relationMap.get(GENERIC_VNF.getResourceName()) != null) { - List vnfList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId, GENERIC_VNF.getResourceName(), - relationMap.get(GENERIC_VNF.getResourceName())); + List vnfList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId, + GENERIC_VNF.getResourceName(), relationMap.get(GENERIC_VNF.getResourceName())); // Logic to Create the Generic VNF JSON and extract further relationships for (JSONObject vnfPayload : vnfList) { + Map> vnfRelationMap = extractRelationships(vnfPayload); + String vnfId = vnfPayload.optString("vnf-id"); + for (Resource resourceType : resourceTypes) { - List vnfcLinkLst = extractRelatedLink(vnfPayload, resourceType.getResourceName()); - if (vnfcLinkLst != null && !vnfcLinkLst.isEmpty()) { - logger.info("The number of the API call for vnfc is:" + vnfcLinkLst.size()); - List vnfcList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, transactionId, - resourceType.getResourceName(), vnfcLinkLst); - if (vnfcList != null) { - vnfPayload.put(resourceType.getCollectionName(), vnfcList); - } - } else { - logger.info("No " + resourceType.getResourceName() + " found for vnf-id:" + vnfPayload.getString("vnf-id")); + List vnfcLinkLst = vnfRelationMap.get(resourceType.getResourceName()); + if (vnfcLinkLst == null || vnfcLinkLst.isEmpty()) { + logger.info("No relationships found for generic-vnf '{}', resource type '{}'", vnfId, + resourceType.getResourceName()); + continue; } + + logger.info("Number of relationships found for generic-vnf '{}', resource type '{}' are: {}", vnfId, + resourceType.getResourceName(), vnfcLinkLst.size()); + List vnfcList = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, + transactionId, resourceType.getResourceName(), vnfcLinkLst); + vnfPayload.put(resourceType.getCollectionName(), vnfcList); } - // Add final vnf payload to list - vnfLst.add(vnfPayload); + + // Process vf-module looking for l3-network: + processVfModuleList(aaiClient, baseURL, aaiBasicAuthorization, transactionId, vnfPayload); + // Add final vnf payload to list + vnfLst.add(vnfPayload); } } else { - logger.info("No " + GENERIC_VNF.getResourceName() + " found for :" + serviceInstancePayload.getString("service-instance-id")); + logger.info("No {} found for service-instance-id: {}", GENERIC_VNF.getResourceName(), + serviceInstancePayload.optString("service-instance-id")); } // Add generic vnf with related resource payload to response - if (vnfLst != null && !vnfLst.isEmpty()) { + if (!vnfLst.isEmpty()) { response.put(GENERIC_VNF.getCollectionName(), vnfLst); } return response; } + private static void processVfModuleList(RestClient aaiClient, String baseURL, String aaiBasicAuthorization, String transactionId, + JSONObject vnfPayload) throws DiscoveryException { + + if (!vnfPayload.has(VF_MODULE.getCollectionName())) { + return; + } + + JSONObject vfmoduleCollection = vnfPayload.getJSONObject(VF_MODULE.getCollectionName()); + + if (!vfmoduleCollection.has(VF_MODULE.getResourceName())) { + return; + } + + JSONArray vfModuleList = vfmoduleCollection.getJSONArray(VF_MODULE.getResourceName()); + + for (int i = 0; i < vfModuleList.length(); i++) { + JSONObject vfModulePayload = vfModuleList.optJSONObject(i); + if (vfModulePayload == null) { + logger.error("VF Module not found for vnf-id {}", vnfPayload.opt("vnf-id")); + continue; + } + processVfModule(aaiClient, baseURL, aaiBasicAuthorization, transactionId, vfModulePayload); + } + } + + private static void processVfModule(RestClient aaiClient, String baseURL, String aaiBasicAuthorization, + String transactionId, JSONObject vfModulePayload) throws DiscoveryException { + + Map> relationMap = extractRelationships(vfModulePayload); + Object vfModuleId = vfModulePayload.opt("vf-module-id"); + + List l3NetworkRelatedLinks = relationMap.get(L3_NETWORK.getResourceName()); + if (l3NetworkRelatedLinks == null) { + logger.info("No relationships found for vf-module '{}', resource type '{}'", vfModuleId, L3_NETWORK.getResourceName()); + // No L3-network relationships exist. + return; + } + + logger.info("Number of relationships found for vf-module '{}', resource type '{}' are: {}", vfModuleId, L3_NETWORK.getResourceName(), l3NetworkRelatedLinks.size()); + + List l3NetworkObjects = processResourceList(aaiClient, baseURL, aaiBasicAuthorization, + transactionId, L3_NETWORK.getResourceName(), l3NetworkRelatedLinks); + + // Add l3-network with related resource payload to the vfModulePayload: + vfModulePayload.put(L3_NETWORK.getCollectionName(), l3NetworkObjects); + } /** * @param aaiClient @@ -198,7 +270,7 @@ public class RestUtil { */ private static List processResourceList(RestClient aaiClient, String aaiBaseURL, String aaiBasicAuthorization, String transactionId, String resourceType, List resourceList) throws DiscoveryException { - List resourcePayloadList = new ArrayList(); + List resourcePayloadList = new ArrayList<>(); for (String resourceLink : resourceList) { String resourceURL = aaiBaseURL + resourceLink; // With latest AAI development, in order to retrieve the both generic VNF + vf_module, we can use @@ -210,8 +282,8 @@ public class RestUtil { // Response from generic VNF API call JSONObject resourcePayload = new JSONObject( getResource(aaiClient, resourceURL, aaiBasicAuthorization, transactionId)); - if (resourcePayload == null || resourcePayload.length() == 0) { - logger.info("Resource with url " + resourceLink + " is not found from AAI"); + if (resourcePayload.length() == 0) { + logger.info("Resource with url {} is not found from AAI", resourceLink); } else { resourcePayloadList.add(resourcePayload); } @@ -219,48 +291,56 @@ public class RestUtil { return resourcePayloadList; } - /** - * @param serviceInstancePayload - * @param relationMap - * @return - * @throws DiscoveryException + * Extract the related-Link from Json payload. For example + *
+     * {
+     *    "related-to": "vnfc",
+     *    "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003",
+     *    "relationship-data": [
+     *       {
+     *          "relationship-key": "vnfc.vnfc-name",
+     *          "relationship-value": "zrdm5aepdg01vmg003"
+     *       }
+     *    ]
+     * }
+     * 
+ * @param payload input pay load json. + * @return Map of "related-to" to list of "related-link" strings. */ - private static HashMap> extractServiceRelationShips(JSONObject payload) - throws DiscoveryException { + private static Map> extractRelationships(JSONObject payload) { - JSONArray relationships = null; - HashMap> relationMap = new HashMap>(); - logger.info("Fetching Service Instance Relationships"); - try { - JSONObject relationshipList = payload.getJSONObject("relationship-list"); - if (relationshipList != null) { - relationships = relationshipList.getJSONArray("relationship"); - } - } catch (Exception e) { - logger.error(e.getMessage()); - throw new DiscoveryException(SERVICE_RELATIONSHIP_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR, - e.getMessage()); + Map> relationMap = new HashMap<>(); + + if (!payload.has(RELATIONSHIP_LIST_KEY)) { + return relationMap; } - if (relationships != null && relationships.length() > 0) { - for (int i = 0; i < relationships.length(); i++) { - JSONObject obj = relationships.optJSONObject(i); - String relatedToObj = obj.getString(JSON_ATT_RELATED_TO); - String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK); + JSONObject relationshipList = payload.getJSONObject(RELATIONSHIP_LIST_KEY); - if (relatedToObj == null) { - logger.info("Related-To Object found null"); - continue; - } - List relatedLinkList = relationMap.get(relatedToObj); - if (relatedLinkList == null) { - relatedLinkList = new ArrayList<>(); - relationMap.put(relatedToObj, relatedLinkList); - } - relatedLinkList.add(relatedLinkObj); + if (!relationshipList.has(RELATIONSHIP_KEY)) { + return relationMap; + } + + JSONArray relationships = relationshipList.getJSONArray(RELATIONSHIP_KEY); + + for (int i = 0; i < relationships.length(); i++) { + JSONObject obj = relationships.optJSONObject(i); + String relatedToObj = obj.optString(JSON_ATT_RELATED_TO); + + if (relatedToObj == null) { + logger.error("Related-To Object is null"); + continue; } + List relatedLinkList = relationMap.get(relatedToObj); + if (relatedLinkList == null) { + relatedLinkList = new ArrayList<>(); + relationMap.put(relatedToObj, relatedLinkList); + } + String relatedLinkObj = obj.getString(JSON_ATT_RELATED_LINK); + relatedLinkList.add(relatedLinkObj); } + return relationMap; } @@ -276,74 +356,19 @@ public class RestUtil { throws DiscoveryException { OperationResult result = client.get(url, buildHeaders(aaiBasicAuthorization, transId), MediaType.valueOf(MediaType.APPLICATION_JSON)); - if (result.getResultCode() == 200) { - String jsonString = result.getResult(); - return jsonString; + if (result.wasSuccessful()) { + return result.getResult(); } else if (result.getResultCode() == 404) { // Resource not found, generate empty JSON format - logger.info("Resource for " + url + " is not found " + "return empty Json format"); + logger.info("Resource for {} is not found, return empty Json format", url); return EMPTY_JSON_STRING; } else { throw new DiscoveryException(FETCH_RESOURCE_FAILED, Status.INTERNAL_SERVER_ERROR, result.getFailureCause()); } } - /** - * Extract the related-Link from Json payload. For example - * { - * "related-to": "vnfc", - * "related-link": "/aai/v11/network/vnfcs/vnfc/zrdm5aepdg01vmg003", - * "relationship-data": [ - * { - * "relationship-key": "vnfc.vnfc-name", - * "relationship-value": "zrdm5aepdg01vmg003" - * } - * ] - * } - */ - private static List extractRelatedLink(JSONObject payload, String catalog) throws DiscoveryException { - List relatedLinkList = new ArrayList(); - JSONArray relationships = null; - logger.info("Fetching relationships for resource type: " + catalog); - try { - JSONObject relationshipLst = payload.getJSONObject("relationship-list"); - if (relationshipLst != null) { - relationships = relationshipLst.getJSONArray("relationship"); - } - - } catch (Exception e) { - logger.error(e.getMessage()); - throw new DiscoveryException(RELATIONSHIP_LINK_PARSE_ERROR, Status.INTERNAL_SERVER_ERROR, e.getMessage()); - } - - if (relationships != null && relationships.length() > 0) { - for (int i = 0; i < relationships.length(); i++) { - Object relatedToObj = null; - Object relatedLinkObj = null; - - JSONObject obj = relationships.optJSONObject(i); - relatedToObj = obj.get(JSON_ATT_RELATED_TO); - - if (relatedToObj.toString().equals(catalog)) { - relatedLinkObj = obj.get(JSON_ATT_RELATED_LINK); - if (relatedLinkObj != null) { - relatedLinkList.add(relatedLinkObj.toString()); - } - } - - } - } - if (relatedLinkList != null) { - logger.info( - "Number of relationships found for resource type: " + catalog + " are: " + relatedLinkList.size()); - } - return relatedLinkList; - } - - - private static Map> buildHeaders(String aaiBasicAuthorization, String transactionId) { - MultivaluedMap headers = new MultivaluedMapImpl(); + MultivaluedMap headers = new MultivaluedHashMap<>(); headers.put(TRANSACTION_ID, Collections.singletonList(transactionId)); headers.put(FROM_APP_ID, Collections.singletonList(APP_NAME)); headers.put(AUTHORIZATION, Collections.singletonList(aaiBasicAuthorization)); @@ -351,7 +376,7 @@ public class RestUtil { } private static List getResourceTypes(String aaiResourceList) { - List resources = new ArrayList(); + List resources = new ArrayList<>(); String noSpaceAaiResourceList = aaiResourceList.replaceAll("\\s", ""); String[] resourceList = noSpaceAaiResourceList.split(","); for (int i = 0; i < resourceList.length; i++) { diff --git a/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/AuthorizationConfigurationTest.java b/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/AuthorizationConfigurationTest.java index 4c7830b..319230a 100644 --- a/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/AuthorizationConfigurationTest.java +++ b/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/AuthorizationConfigurationTest.java @@ -25,10 +25,8 @@ import static org.mockito.Mockito.when; import org.junit.Test; import org.onap.sdnc.apps.pomba.servicedecomposition.AuthorizationConfiguration; -public class AuthorizationConfigurationTest -{ - AuthorizationConfiguration authorizationConfiguration = - mock(AuthorizationConfiguration.class); +public class AuthorizationConfigurationTest { + AuthorizationConfiguration authorizationConfiguration = mock(AuthorizationConfiguration.class); @Test public void testGetSdBasicAuthHeader() { diff --git a/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/ServiceDecompositionTest.java b/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/ServiceDecompositionTest.java index 37a5518..0680842 100644 --- a/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/ServiceDecompositionTest.java +++ b/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/ServiceDecompositionTest.java @@ -42,6 +42,7 @@ import org.json.JSONObject; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.sdnc.apps.pomba.servicedecomposition.service.rs.RestService; import org.springframework.beans.factory.annotation.Autowired; @@ -63,13 +64,15 @@ import org.springframework.test.context.web.WebAppConfiguration; "aai.servicePort=8081", "basicAuth.username=admin", "basicAuth.password=OBF:1u2a1toa1w8v1tok1u30" -}) + }) public class ServiceDecompositionTest { private static final String AUTH = "Basic " + Base64.getEncoder().encodeToString(( "admin:" + Password.deobfuscate("OBF:1u2a1toa1w8v1tok1u30")).getBytes()); + private HttpServletRequest httpRequest = Mockito.mock(HttpServletRequest.class); + // TODO missing code coverage for VNFC resources @Rule @@ -120,7 +123,6 @@ public class ServiceDecompositionTest { final String networkId1 = "HNP1d77c-1094-41ec-b7f3-94bb30951870"; final String networkId2 = "HNP1d77c-1094-41ec-b7f3-94bb30951872"; - HttpServletRequest httpRequest = new TestHttpServletRequest(); Response response = this.service.getContext(httpRequest, AUTH, "network-discovery-context-builder", null, serviceInstanceId); assertEquals(200, response.getStatus()); @@ -151,13 +153,80 @@ public class ServiceDecompositionTest { } } + @Test + public void testDemoFirewallServiceWithL3Networks() throws Exception { + // setup A&AI responses + addResponse( + "/aai/v13/nodes/service-instance/c6456519-6acf-4adb-997c-3c363dd4caaf", + "junit/aai-service-instance2.json"); + addResponse( + "/aai/v13/network/generic-vnfs/generic-vnf/6700c313-fbb7-4cf9-ac70-0293ec56df68?depth=2", + "junit/aai-generic-vnf1.json"); + addResponse( + "/aai/v13/network/generic-vnfs/generic-vnf/8a9ddb25-2e79-449c-a40d-5011bac0da39?depth=2", + "junit/aai-generic-vnf2.json"); + addResponse( + "/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/CloudOwner/RegionOne/tenants/tenant" + + "/b49b830686654191bb1e952a74b014ad/vservers/vserver/b494cd6e-b9f3-45e0-afe7-e1d1a5f5d74a", + "junit/aai-vserver.json"); + addResponse( + "/aai/v13/network/l3-networks/l3-network/HNP1d77c-1094-41ec-b7f3-94bb30951870", + "junit/aai-l3-network1.json"); + addResponse( + "/aai/v13/network/l3-networks/l3-network/HNP1d77c-1094-41ec-b7f3-94bb30951872", + "junit/aai-l3-network2.json"); + + final String serviceInstanceId = "c6456519-6acf-4adb-997c-3c363dd4caaf"; + final String vnfId1 = "6700c313-fbb7-4cf9-ac70-0293ec56df68"; + final String vnfId2 = "8a9ddb25-2e79-449c-a40d-5011bac0da39"; + final String vserverId = "b494cd6e-b9f3-45e0-afe7-e1d1a5f5d74a"; + final String networkId1 = "HNP1d77c-1094-41ec-b7f3-94bb30951870"; + final String networkId2 = "HNP1d77c-1094-41ec-b7f3-94bb30951872"; + + Response response = this.service.getContext(httpRequest, AUTH, "network-discovery-context-builder", null, + serviceInstanceId); + assertEquals(200, response.getStatus()); + + JSONObject serviceInstance = new JSONObject((String)response.getEntity()); + + // verify two generic-vnfs added to service instance data + verifyResource(serviceInstance, "generic-vnfs", "vnf-id", vnfId1); + verifyResource(serviceInstance, "generic-vnfs", "vnf-id", vnfId2); + verifyResource(serviceInstance, "l3-networks", "network-id", networkId1); + + JSONArray vnfs = serviceInstance.getJSONArray("generic-vnfs"); + for (int i = 0; i < vnfs.length(); i++) { + JSONObject vnf = vnfs.getJSONObject(i); + String vnfId = vnf.getString("vnf-id"); + switch (vnfId) { + case vnfId1: + // verify vserver resource + verifyResource(vnf, "vservers", "vserver-id", vserverId); + break; + case vnfId2: + // verify network resources + verifyResource(vnf, "l3-networks", "network-id", networkId1); + verifyResource(vnf, "l3-networks", "network-id", networkId2); + JSONObject vfmodules = vnf.getJSONObject("vf-modules"); + JSONArray vfmoduleList = vfmodules.getJSONArray("vf-module"); + for (int j = 0; j < vfmoduleList.length(); j++) { + JSONObject vfmodule = vfmoduleList.getJSONObject(j); + verifyResource(vfmodule, "l3-networks", "network-id", networkId1); + } + break; + default: + fail("Unexpected generic-vnf " + vnfId); + } + } + } + @Test public void testNoAuthHeader() throws Exception { String fromAppId = "junit"; String transactionId = null; String serviceInstanceId = "aServiceInstanceId"; // no Authorization header - Response response = this.service.getContext(new TestHttpServletRequest(), null, fromAppId, transactionId, + Response response = this.service.getContext(httpRequest, null, fromAppId, transactionId, serviceInstanceId); assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); // should get WWW-Authenticate header in response @@ -172,7 +241,7 @@ public class ServiceDecompositionTest { String transactionId = null; String serviceInstanceId = "aServiceInstanceId"; - Response response = this.service.getContext(new TestHttpServletRequest(), authorization, fromAppId, + Response response = this.service.getContext(httpRequest, authorization, fromAppId, transactionId, serviceInstanceId); assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); // should not get WWW-Authenticate header in response @@ -186,7 +255,7 @@ public class ServiceDecompositionTest { String transactionId = null; String serviceInstanceId = "someValue"; - Response response = this.service.getContext(new TestHttpServletRequest(), AUTH, fromAppId, transactionId, + Response response = this.service.getContext(httpRequest, AUTH, fromAppId, transactionId, serviceInstanceId); assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus()); assertTrue(((String)response.getEntity()).contains(ONAPLogConstants.Headers.PARTNER_NAME)); @@ -199,7 +268,7 @@ public class ServiceDecompositionTest { String transactionId = null; String serviceInstanceId = null; - Response response = this.service.getContext(new TestHttpServletRequest(), AUTH, fromAppId, transactionId, + Response response = this.service.getContext(httpRequest, AUTH, fromAppId, transactionId, serviceInstanceId); assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus()); assertTrue(((String)response.getEntity()).contains("service-instance-id")); @@ -211,7 +280,7 @@ public class ServiceDecompositionTest { aai.stubFor(get("/aai/v13/nodes/service-instance/noSuchServiceId").willReturn(notFound())); Response response = - this.service.getContext(new TestHttpServletRequest(), AUTH, "junit", null, "noSuchServiceId"); + this.service.getContext(httpRequest, AUTH, "junit", null, "noSuchServiceId"); assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); } diff --git a/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/TestHttpServletRequest.java b/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/TestHttpServletRequest.java deleted file mode 100644 index fc00a61..0000000 --- a/pomba/service-decomposition/src/test/java/org/onap/sdnc/apps/pomba/servicedecomposition/test/TestHttpServletRequest.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * ============LICENSE_START=================================================== - * Copyright (c) 2018 Amdocs - * ============================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END===================================================== - */ - -package org.onap.sdnc.apps.pomba.servicedecomposition.test; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.Principal; -import java.util.Collection; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map; -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpUpgradeHandler; -import javax.servlet.http.Part; - -public class TestHttpServletRequest implements HttpServletRequest { - @Override - public String getHeader(String name) { - return null; - } - - @Override - public String getRemoteAddr() { - return "localhost"; - } - - @Override - public String getServerName() { - return "localhost"; - } - - @Override - public String getRequestURI() { - return "/test"; - } - - - @Override - public Object getAttribute(String name) { - throw new UnsupportedOperationException("getAttribute"); - } - - @Override - public Enumeration getAttributeNames() { - throw new UnsupportedOperationException("getAttributeNames"); - } - - @Override - public String getCharacterEncoding() { - throw new UnsupportedOperationException("getCharacterEncoding"); - } - - @Override - public void setCharacterEncoding(String env) throws UnsupportedEncodingException { - throw new UnsupportedOperationException("setCharacterEncoding"); - } - - @Override - public int getContentLength() { - throw new UnsupportedOperationException("getContentLength"); - } - - @Override - public long getContentLengthLong() { - throw new UnsupportedOperationException("getContentLengthLong"); - } - - @Override - public String getContentType() { - throw new UnsupportedOperationException("getContentType"); - } - - @Override - public ServletInputStream getInputStream() throws IOException { - throw new UnsupportedOperationException("getInputStream"); - } - - @Override - public String getParameter(String name) { - throw new UnsupportedOperationException("getParameter"); - } - - @Override - public Enumeration getParameterNames() { - throw new UnsupportedOperationException("getParameterNames"); - } - - @Override - public String[] getParameterValues(String name) { - throw new UnsupportedOperationException("getParameterValues"); - } - - @Override - public Map getParameterMap() { - throw new UnsupportedOperationException("getParameterMap"); - } - - @Override - public String getProtocol() { - throw new UnsupportedOperationException("getProtocol"); - } - - @Override - public String getScheme() { - throw new UnsupportedOperationException("getScheme"); - } - - @Override - public int getServerPort() { - throw new UnsupportedOperationException("getServerPort"); - } - - @Override - public BufferedReader getReader() throws IOException { - throw new UnsupportedOperationException("getReader"); - } - - @Override - public String getRemoteHost() { - throw new UnsupportedOperationException("getRemoteHost"); - } - - @Override - public void setAttribute(String name, Object obj) { - throw new UnsupportedOperationException("setAttribute"); - } - - @Override - public void removeAttribute(String name) { - throw new UnsupportedOperationException("removeAttribute"); - } - - @Override - public Locale getLocale() { - throw new UnsupportedOperationException("getLocale"); - } - - @Override - public Enumeration getLocales() { - throw new UnsupportedOperationException("getLocales"); - } - - @Override - public boolean isSecure() { - throw new UnsupportedOperationException("isSecure"); - } - - @Override - public RequestDispatcher getRequestDispatcher(String path) { - throw new UnsupportedOperationException("getRequestDispatcher"); - } - - @Override - public String getRealPath(String path) { - throw new UnsupportedOperationException("getRealPath"); - } - - @Override - public int getRemotePort() { - throw new UnsupportedOperationException("getRemotePort"); - } - - @Override - public String getLocalName() { - throw new UnsupportedOperationException("getLocalName"); - } - - @Override - public String getLocalAddr() { - throw new UnsupportedOperationException("getLocalAddr"); - } - - @Override - public int getLocalPort() { - throw new UnsupportedOperationException("getLocalPort"); - } - - @Override - public ServletContext getServletContext() { - throw new UnsupportedOperationException("getServletContext"); - } - - @Override - public AsyncContext startAsync() throws IllegalStateException { - throw new UnsupportedOperationException("startAsync"); - } - - @Override - public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) - throws IllegalStateException { - throw new UnsupportedOperationException("startAsync"); - } - - @Override - public boolean isAsyncStarted() { - throw new UnsupportedOperationException("isAsyncStarted"); - } - - @Override - public boolean isAsyncSupported() { - throw new UnsupportedOperationException("isAsyncSupported"); - } - - @Override - public AsyncContext getAsyncContext() { - throw new UnsupportedOperationException("getAsyncContext"); - } - - @Override - public DispatcherType getDispatcherType() { - throw new UnsupportedOperationException("getDispatcherType"); - } - - @Override - public String getAuthType() { - throw new UnsupportedOperationException("getAuthType"); - } - - @Override - public Cookie[] getCookies() { - throw new UnsupportedOperationException("getCookies"); - } - - @Override - public long getDateHeader(String name) { - throw new UnsupportedOperationException("getDateHeader"); - } - - @Override - public Enumeration getHeaders(String name) { - throw new UnsupportedOperationException("getHeaders"); - } - - @Override - public Enumeration getHeaderNames() { - throw new UnsupportedOperationException("getHeaderNames"); - } - - @Override - public int getIntHeader(String name) { - throw new UnsupportedOperationException("getIntHeader"); - } - - @Override - public String getMethod() { - throw new UnsupportedOperationException("getMethod"); - } - - @Override - public String getPathInfo() { - throw new UnsupportedOperationException("getPathInfo"); - } - - @Override - public String getPathTranslated() { - throw new UnsupportedOperationException("getPathTranslated"); - } - - @Override - public String getContextPath() { - throw new UnsupportedOperationException("getContextPath"); - } - - @Override - public String getQueryString() { - throw new UnsupportedOperationException("getQueryString"); - } - - @Override - public String getRemoteUser() { - throw new UnsupportedOperationException("getRemoteUser"); - } - - @Override - public boolean isUserInRole(String role) { - throw new UnsupportedOperationException("isUserInRole"); - } - - @Override - public Principal getUserPrincipal() { - throw new UnsupportedOperationException("getUserPrincipal"); - } - - @Override - public String getRequestedSessionId() { - throw new UnsupportedOperationException("getRequestedSessionId"); - } - - @Override - public StringBuffer getRequestURL() { - throw new UnsupportedOperationException("getRequestURL"); - } - - @Override - public String getServletPath() { - throw new UnsupportedOperationException("getServletPath"); - } - - @Override - public HttpSession getSession(boolean create) { - throw new UnsupportedOperationException("getSession"); - } - - @Override - public HttpSession getSession() { - throw new UnsupportedOperationException("getSession"); - } - - @Override - public String changeSessionId() { - throw new UnsupportedOperationException("changeSessionId"); - } - - @Override - public boolean isRequestedSessionIdValid() { - throw new UnsupportedOperationException("isRequestedSessionIdValid"); - } - - @Override - public boolean isRequestedSessionIdFromCookie() { - throw new UnsupportedOperationException("isRequestedSessionIdFromCookie"); - } - - @Override - public boolean isRequestedSessionIdFromURL() { - throw new UnsupportedOperationException("isRequestedSessionIdFromURL"); - } - - @Override - public boolean isRequestedSessionIdFromUrl() { - throw new UnsupportedOperationException("isRequestedSessionIdFromUrl"); - } - - @Override - public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { - throw new UnsupportedOperationException("authenticate"); - } - - @Override - public void login(String username, String password) throws ServletException { - throw new UnsupportedOperationException("login"); - } - - @Override - public void logout() throws ServletException { - throw new UnsupportedOperationException("logout"); - } - - @Override - public Collection getParts() throws IOException, ServletException { - throw new UnsupportedOperationException("getParts"); - } - - @Override - public Part getPart(String name) throws IOException, ServletException { - throw new UnsupportedOperationException("getPart"); - } - - @Override - public T upgrade(Class httpUpgradeHandlerClass) - throws IOException, ServletException { - throw new UnsupportedOperationException("upgrade"); - } -} diff --git a/pomba/service-decomposition/src/test/resources/junit/aai-generic-vnf2.json b/pomba/service-decomposition/src/test/resources/junit/aai-generic-vnf2.json index f96431e..8ea03bf 100644 --- a/pomba/service-decomposition/src/test/resources/junit/aai-generic-vnf2.json +++ b/pomba/service-decomposition/src/test/resources/junit/aai-generic-vnf2.json @@ -89,7 +89,14 @@ "model-invariant-id": "74bc1518-282d-4148-860f-8892b6369456", "model-version-id": "4e3d28cf-d654-41af-a47b-04b4bd0ac58e", "model-customization-id": "cc51ab7d-9b03-4bd6-9104-09df0c7c7907", - "module-index": 0 + "module-index": 0, + "relationship-list": { + "relationship": [ + { + "related-to": "l3-network", + "related-link": "/aai/v13/network/l3-networks/l3-network/HNP1d77c-1094-41ec-b7f3-94bb30951870" + }] + } } ] } diff --git a/pomba/service-decomposition/src/test/resources/junit/aai-service-instance2.json b/pomba/service-decomposition/src/test/resources/junit/aai-service-instance2.json new file mode 100644 index 0000000..2d3acc8 --- /dev/null +++ b/pomba/service-decomposition/src/test/resources/junit/aai-service-instance2.json @@ -0,0 +1,47 @@ +{ + "service-instance-id": "c6456519-6acf-4adb-997c-3c363dd4caaf", + "service-instance-name": "Firewall1", + "model-invariant-id": "0c5a20de-87ad-442c-9190-f38ab0a6bb7f", + "model-version-id": "d3d6cf83-d03a-43cc-99ff-206d40bb9a72", + "resource-version": "1527637758480", + "relationship-list": { + "relationship": [ + { + "related-to": "l3-network", + "related-link": "/aai/v13/network/l3-networks/l3-network/HNP1d77c-1094-41ec-b7f3-94bb30951870" + }, + { + "related-to": "generic-vnf", + "related-link": "/aai/v13/network/generic-vnfs/generic-vnf/6700c313-fbb7-4cf9-ac70-0293ec56df68", + "relationship-data": [ + { + "relationship-key": "generic-vnf.vnf-id", + "relationship-value": "6700c313-fbb7-4cf9-ac70-0293ec56df68" + } + ], + "related-to-property": [ + { + "property-key": "generic-vnf.vnf-name", + "property-value": "PacketGenerator-1" + } + ] + }, + { + "related-to": "generic-vnf", + "related-link": "/aai/v13/network/generic-vnfs/generic-vnf/8a9ddb25-2e79-449c-a40d-5011bac0da39", + "relationship-data": [ + { + "relationship-key": "generic-vnf.vnf-id", + "relationship-value": "8a9ddb25-2e79-449c-a40d-5011bac0da39" + } + ], + "related-to-property": [ + { + "property-key": "generic-vnf.vnf-name", + "property-value": "Firewall-1" + } + ] + } + ] + } +} -- cgit 1.2.3-korg