package org.onap.so.bpmn.buildingblock;
import static org.apache.commons.lang3.StringUtils.*;
-
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-
import org.apache.commons.lang.SerializationUtils;
import org.camunda.bpm.engine.delegate.BpmnError;
import org.json.JSONArray;
import org.onap.so.bpmn.servicedecomposition.modelinfo.ModelInfoServiceInstance;
import org.onap.so.client.exception.BadResponseException;
import org.onap.so.client.exception.ExceptionBuilder;
-
import org.onap.so.client.sniro.SniroClient;
import static org.onap.so.client.sniro.SniroValidator.*;
-
import org.onap.so.client.sniro.beans.Demand;
import org.onap.so.client.sniro.beans.LicenseInfo;
import org.onap.so.client.sniro.beans.ModelInfo;
/**
- * The sniro homing building block obtains licensing and homing solutions for a given
- * resource or set of resources.
+ * The sniro homing building block obtains licensing and homing solutions for a given resource or set of resources.
*
* @author cb645j
*
@Component("SniroHoming")
public class SniroHomingV2 {
- private static final Logger logger = LoggerFactory.getLogger(SniroHomingV2.class);
- private JsonUtils jsonUtils = new JsonUtils();
- @Autowired
- private Environment env;
- @Autowired
- private SniroClient client;
- @Autowired
- private ExceptionBuilder exceptionUtil;
- private static final String MODEL_NAME = "modelName";
- private static final String MODEL_INVARIANT_ID = "modelInvariantId";
- private static final String MODEL_VERSION_ID = "modelVersionId";
- private static final String MODEL_VERSION = "modelVersion";
- private static final String SERVICE_RESOURCE_ID = "serviceResourceId";
- private static final String RESOURCE_MODULE_NAME = "resourceModuleName";
- private static final String RESOURCE_MODEL_INFO = "resourceModelInfo";
- private static final String IDENTIFIER_TYPE = "identifierType";
- private static final String SOLUTIONS = "solutions";
- private static final String RESOURCE_MISSING_DATA = "Resource does not contain: ";
- private static final String SERVICE_MISSING_DATA = "Service Instance does not contain: ";
- private static final String UNPROCESSABLE = "422";
- private static final int INTERNAL = 500;
-
- /**
- * Generates the request payload then sends to sniro manager to perform homing and
- * licensing for the provided demands
- *
- * @param execution
- */
- public void callSniro(BuildingBlockExecution execution){
- logger.debug("Started Sniro Homing Call Sniro");
- try{
- GeneralBuildingBlock bb = execution.getGeneralBuildingBlock();
-
- RequestContext requestContext = bb.getRequestContext();
- RequestParameters requestParams = requestContext.getRequestParameters();
- String requestId = requestContext.getMsoRequestId();
-
- ServiceInstance serviceInstance = bb.getCustomer().getServiceSubscription().getServiceInstances().get(0);
- Customer customer = bb.getCustomer();
-
- String timeout = execution.getVariable("timeout");
- if(isBlank(timeout)){
- timeout = env.getProperty("sniro.manager.timeout", "PT30M");
- }
-
- SniroManagerRequest request = new SniroManagerRequest();
-
- RequestInfo requestInfo = buildRequestInfo(requestId, timeout);
- request.setRequestInformation(requestInfo);
-
- ServiceInfo serviceInfo = buildServiceInfo(serviceInstance);
- request.setServiceInformation(serviceInfo);
-
- PlacementInfo placementInfo = buildPlacementInfo(customer, requestParams);
-
- List<Demand> placementDemands = buildPlacementDemands(serviceInstance);
- placementInfo.setDemands(placementDemands);
- request.setPlacementInformation(placementInfo);
-
- LicenseInfo licenseInfo = new LicenseInfo();
-
- List<Demand> licenseDemands = buildLicenseDemands(serviceInstance);
- licenseInfo.setDemands(licenseDemands);
- request.setLicenseInformation(licenseInfo);
-
- if(placementDemands.size() > 0 || licenseDemands.size() > 0){
- client.postDemands(request);
- }else{
- logger.debug(SERVICE_MISSING_DATA + "resources eligible for homing or licensing");
- throw new BpmnError(UNPROCESSABLE, SERVICE_MISSING_DATA + "resources eligible for homing or licensing");
- }
-
- //Variables for ReceiveWorkflowMessage subflow
- execution.setVariable("asyncCorrelator", requestId);
- execution.setVariable("asyncMessageType", "SNIROResponse");
- execution.setVariable("asyncTimeout", timeout);
-
- logger.trace("Completed Sniro Homing Call Sniro");
- }catch(BpmnError e){
- logger.error("Exception occurred", e);
- exceptionUtil.buildAndThrowWorkflowException(execution, Integer.parseInt(e.getErrorCode()), e.getMessage());
- }catch(BadResponseException e){
- logger.error("Exception occurred", e);
- exceptionUtil.buildAndThrowWorkflowException(execution, 400, e.getMessage());
- }catch(Exception e){
- logger.error("Exception occurred", e);
- exceptionUtil.buildAndThrowWorkflowException(execution, INTERNAL, "Internal Error - occurred while preparing sniro request: " + e.getMessage());
- }
- }
-
- /**
- * Validates, processes, and sets the homing and licensing solutions that are returned by
- * sniro manager
- *
- * @param execution
- * @param asyncResponse
- */
- public void processSolution(BuildingBlockExecution execution, String asyncResponse){
- logger.trace("Started Sniro Homing Process Solution");
- try{
- //TODO improve handling multiple solutions but is dependent on sniro enhancing api + work with sniro conductor to improve "inventoryType" representation
- validateSolution(asyncResponse);
- ServiceInstance serviceInstance = execution.getGeneralBuildingBlock().getCustomer().getServiceSubscription().getServiceInstances().get(0);
-
- logger.debug("Processing sniro manager asyncronous response");
- JSONObject response = new JSONObject(asyncResponse);
- if(response.has(SOLUTIONS)){
- JSONObject allSolutions = response.getJSONObject(SOLUTIONS);
- if(allSolutions.has("placementSolutions")){
- JSONArray placementSolutions = allSolutions.getJSONArray("placementSolutions");
- for(int i = 0; i < placementSolutions.length(); i++){
- JSONArray placements = placementSolutions.getJSONArray(i);
- processPlacementSolution(serviceInstance, placements, i);
- }
- }
- if(allSolutions.has("licenseSolutions")){
- JSONArray licenseSolutions = allSolutions.getJSONArray("licenseSolutions");
- if(licenseSolutions.length() > 0){
- processLicenseSolution(serviceInstance, licenseSolutions);
- }
- }
- }else{
- throw new BpmnError(UNPROCESSABLE, "Sniro Managers response does not contain: " + SOLUTIONS);
- }
-
- execution.setVariable("generalBuildingBlock", execution.getGeneralBuildingBlock());
-
- logger.trace("Completed Sniro Homing Process Solution");
- }catch(BpmnError e){
- logger.error("Exception occurred", e);
- exceptionUtil.buildAndThrowWorkflowException(execution, Integer.parseInt(e.getErrorCode()), e.getMessage());
- }catch(BadResponseException e){
- logger.error("Exception occurred", e);
- exceptionUtil.buildAndThrowWorkflowException(execution, 400, e.getMessage());
- }catch(Exception e){
- logger.error("Exception occurred", e);
- exceptionUtil.buildAndThrowWorkflowException(execution, INTERNAL, "Internal Error - occurred while processing sniro asynchronous response: " + e.getMessage());
- }
- }
-
- /**
- * Builds the request information section for the homing/licensing request
- *
- * @throws Exception
- */
- private RequestInfo buildRequestInfo(String requestId, String timeout) throws Exception{
- logger.trace("Building request information");
- RequestInfo requestInfo = new RequestInfo();
- if(requestId != null){
- String host = env.getProperty("mso.workflow.message.endpoint");
- String callbackUrl = host + "/" + UriUtils.encodePathSegment("SNIROResponse", "UTF-8") + "/" + UriUtils.encodePathSegment(requestId, "UTF-8");
-
- Duration d = Duration.parse(timeout);
-
- requestInfo.setTransactionId(requestId);
- requestInfo.setRequestId(requestId);
- requestInfo.setCallbackUrl(callbackUrl);
- requestInfo.setRequestType("create");
- requestInfo.setTimeout(d.getSeconds());
-
- } else{
- throw new BpmnError(UNPROCESSABLE, "Request Context does not contain: requestId");
- }
- return requestInfo;
- }
-
- /**
- * Builds the request information section for the homing/licensing request
- *
- */
- private ServiceInfo buildServiceInfo(ServiceInstance serviceInstance){
- logger.trace("Building service information");
- ServiceInfo info = new ServiceInfo();
- ModelInfoServiceInstance modelInfo = serviceInstance.getModelInfoServiceInstance();
- if(isNotBlank(modelInfo.getModelInvariantUuid()) && isNotBlank(modelInfo.getModelUuid())){
- info.setServiceInstanceId(serviceInstance.getServiceInstanceId());
- if(modelInfo.getServiceType() != null && modelInfo.getServiceType().length() > 0){ //temp solution
- info.setServiceName(modelInfo.getServiceType());
- }
- if(modelInfo.getServiceRole() != null){
- info.setServiceRole(modelInfo.getServiceRole());
- }
- info.setModelInfo(buildModelInfo(modelInfo));
- }else{
- throw new BpmnError(UNPROCESSABLE, SERVICE_MISSING_DATA + MODEL_VERSION_ID + ", " + MODEL_INVARIANT_ID);
- }
- return info;
- }
-
- /**
- * Builds initial section of placement info for the homing/licensing request
- *
- */
- private PlacementInfo buildPlacementInfo(Customer customer, RequestParameters requestParams){
- PlacementInfo placementInfo = new PlacementInfo();
- if(customer != null){
- logger.debug("Adding subscriber to placement information");
- SubscriberInfo subscriber = new SubscriberInfo();
- subscriber.setGlobalSubscriberId(customer.getGlobalCustomerId());
- subscriber.setSubscriberName(customer.getSubscriberName());
- subscriber.setSubscriberCommonSiteId(customer.getSubscriberCommonSiteId());
- placementInfo.setSubscriberInfo(subscriber);
- if(requestParams != null){
- logger.debug("Adding request parameters to placement information");
- placementInfo.setRequestParameters(requestParams.toJsonString());
- }
- }else{
- throw new BpmnError(UNPROCESSABLE, SERVICE_MISSING_DATA + "customer");
- }
- return placementInfo;
-
- }
-
- /**
- * Builds the placement demand list for the homing/licensing request
- *
- */
- private List<Demand> buildPlacementDemands(ServiceInstance serviceInstance){
- logger.trace("Building placement information demands");
- List<Demand> placementDemands = new ArrayList<Demand>();
-
- List<AllottedResource> allottedResourceList = serviceInstance.getAllottedResources();
- if(!allottedResourceList.isEmpty()){
- logger.debug("Adding allotted resources to placement demands list");
- for(AllottedResource ar : allottedResourceList){
- if(isBlank(ar.getId())){
- ar.setId(UUID.randomUUID().toString());
- }
- Demand demand = buildDemand(ar.getId(), ar.getModelInfoAllottedResource());
- addCandidates(ar, demand);
- placementDemands.add(demand);
- }
- }
- List<VpnBondingLink> vpnBondingLinkList = serviceInstance.getVpnBondingLinks();
- if(!vpnBondingLinkList.isEmpty()){
- logger.debug("Adding vpn bonding links to placement demands list");
- for(VpnBondingLink vbl:vpnBondingLinkList){
- List<ServiceProxy> serviceProxyList = vbl.getServiceProxies();
- for(ServiceProxy sp : serviceProxyList){
- if(isBlank(sp.getId())){
- sp.setId(UUID.randomUUID().toString());
- }
- Demand demand = buildDemand(sp.getId(), sp.getModelInfoServiceProxy());
- addCandidates(sp, demand);
- placementDemands.add(demand);
- }
- }
- }
- return placementDemands;
- }
-
- /**
- * Builds the license demand list for the homing/licensing request
- *
- */
- private List<Demand> buildLicenseDemands(ServiceInstance serviceInstance){
- logger.trace("Building license information");
- List<Demand> licenseDemands = new ArrayList<Demand>();
- List<GenericVnf> vnfList = serviceInstance.getVnfs();
- if(!vnfList.isEmpty()){
- logger.debug("Adding vnfs to license demands list");
- for(GenericVnf vnf : vnfList){
- Demand demand = buildDemand(vnf.getVnfId(), vnf.getModelInfoGenericVnf());
- licenseDemands.add(demand);
- }
- }
- return licenseDemands;
- }
-
- /**
- * Builds a single demand object
- *
- */
- private Demand buildDemand(String id, ModelInfoMetadata metadata){
- logger.debug("Building demand for service or resource: " + id);
- Demand demand = new Demand();
- if(isNotBlank(id) && isNotBlank(metadata.getModelInstanceName())){
- demand.setServiceResourceId(id);
- demand.setResourceModuleName(metadata.getModelInstanceName());
- demand.setModelInfo(buildModelInfo(metadata));
- }else{
- throw new BpmnError(UNPROCESSABLE, RESOURCE_MISSING_DATA + "modelInstanceName");
- }
- return demand;
- }
-
- /**
- * Builds the resource model info section
- *
- */
- private ModelInfo buildModelInfo(ModelInfoMetadata metadata){
- ModelInfo object = new ModelInfo();
- String invariantUuid = metadata.getModelInvariantUuid();
- String modelUuid = metadata.getModelUuid();
- if(isNotBlank(invariantUuid) && isNotBlank(modelUuid)){
- object.setModelInvariantId(invariantUuid);
- object.setModelVersionId(modelUuid);
- object.setModelName(metadata.getModelName());
- object.setModelVersion(metadata.getModelVersion());
- }else if(isNotBlank(invariantUuid)){
- throw new BpmnError(UNPROCESSABLE, RESOURCE_MISSING_DATA + MODEL_VERSION_ID);
- }else{
- throw new BpmnError(UNPROCESSABLE, RESOURCE_MISSING_DATA + MODEL_INVARIANT_ID);
- }
- return object;
- }
-
- /**
- * Adds required, excluded, and existing candidates to a demand
- *
- */
- private void addCandidates(SolutionCandidates candidates, Demand demand){
- List<Candidate> required = candidates.getRequiredCandidates();
- List<Candidate> excluded = candidates.getExcludedCandidates();
- if(!required.isEmpty()){
- List<org.onap.so.client.sniro.beans.Candidate> cans = new ArrayList<org.onap.so.client.sniro.beans.Candidate>();
- for(Candidate c:required){
- org.onap.so.client.sniro.beans.Candidate can = new org.onap.so.client.sniro.beans.Candidate();
- can.setIdentifierType(c.getIdentifierType());
- can.setIdentifiers(c.getIdentifiers());
- can.setCloudOwner(c.getCloudOwner());
- cans.add(can);
- }
- demand.setRequiredCandidates(cans);
- }
- if(!excluded.isEmpty()){
- List<org.onap.so.client.sniro.beans.Candidate> cans = new ArrayList<org.onap.so.client.sniro.beans.Candidate>();
- for(Candidate c:excluded){
- org.onap.so.client.sniro.beans.Candidate can = new org.onap.so.client.sniro.beans.Candidate();
- can.setIdentifierType(c.getIdentifierType());
- can.setIdentifiers(c.getIdentifiers());
- can.setCloudOwner(c.getCloudOwner());
- cans.add(can);
- }
- demand.setExcludedCandidates(cans);
- }
- //TODO support existing candidates
- }
-
- /**
- * Processes the license solutions and sets to the corresponding generic vnf
- *
- */
- private void processLicenseSolution(ServiceInstance serviceInstance, JSONArray licenseSolutions){
- List<GenericVnf> vnfs = serviceInstance.getVnfs();
-
- logger.debug("Processing the license solution");
- for(int i = 0; i < licenseSolutions.length(); i++){
- JSONObject licenseSolution = licenseSolutions.getJSONObject(i);
- for(GenericVnf vnf:vnfs){
- if(licenseSolution.getString(SERVICE_RESOURCE_ID).equals(vnf.getVnfId())){
- License license = new License();
- JSONArray entitlementPools = licenseSolution.getJSONArray("entitlementPoolUUID");
- List<String> entitlementPoolsList = jsonUtils.StringArrayToList(entitlementPools);
- license.setEntitlementPoolUuids(entitlementPoolsList);
- JSONArray licenseKeys = licenseSolution.getJSONArray("licenseKeyGroupUUID");
- List<String> licenseKeysList = jsonUtils.StringArrayToList(licenseKeys);
- license.setLicenseKeyGroupUuids(licenseKeysList);
-
- vnf.setLicense(license);
- }
- }
- }
- }
-
- /**
- * Processes a placement solution list then correlates and sets each placement solution
- * to its corresponding resource
- *
- */
- private void processPlacementSolution(ServiceInstance serviceInstance, JSONArray placements, int i){
- List<VpnBondingLink> links = serviceInstance.getVpnBondingLinks();
- List<AllottedResource> allottes = serviceInstance.getAllottedResources();
- List<GenericVnf> vnfs = serviceInstance.getVnfs();
-
- logger.debug("Processing placement solution " + i+1);
- for(int p = 0; p < placements.length(); p++){
- JSONObject placement = placements.getJSONObject(p);
- SolutionInfo solutionInfo = new SolutionInfo();
- solutionInfo.setSolutionId(i + 1);
- search: {
- for(VpnBondingLink vbl:links){
- List<ServiceProxy> proxies = vbl.getServiceProxies();
- for(ServiceProxy sp:proxies){
- if(placement.getString(SERVICE_RESOURCE_ID).equals(sp.getId())){
- if(i > 0){
- if(p % 2 == 0){
- VpnBondingLink vblNew = (VpnBondingLink) SerializationUtils.clone(vbl);
- vblNew.setVpnBondingLinkId(UUID.randomUUID().toString());
- links.add(vblNew);
- }
- links.get(links.size() - 1).getServiceProxy(sp.getId()).setServiceInstance(setSolution(solutionInfo, placement));
- }else{
- sp.setServiceInstance(setSolution(solutionInfo, placement));
- }
- break search;
- }
- }
- }
- for(AllottedResource ar:allottes){
- if(placement.getString(SERVICE_RESOURCE_ID).equals(ar.getId())){
- ar.setParentServiceInstance(setSolution(solutionInfo, placement));
- break search;
- }
- }
- for(GenericVnf vnf:vnfs){
- if(placement.getString(SERVICE_RESOURCE_ID).equals(vnf.getVnfId())){
- ServiceInstance si = setSolution(solutionInfo, placement);
- serviceInstance.setSolutionInfo(si.getSolutionInfo());
- serviceInstance.getVnfs().add(si.getVnfs().get(0));
- break search;
- }
- }
- }
- }
- }
-
-
- /**
- * Creates and sets necessary pojos with placement solution data for a given demand
- *
- */
- private ServiceInstance setSolution(SolutionInfo solutionInfo, JSONObject placement){
- logger.debug("Mapping placement solution");
- String invalidMessage = "Sniro Managers Response contains invalid: ";
-
- JSONObject solution = placement.getJSONObject("solution");
- String identifierType = solution.getString(IDENTIFIER_TYPE);
- List<String> identifiersList = jsonUtils.StringArrayToList(solution.getJSONArray("identifiers").toString());
- String identifierValue = identifiersList.get(0);
-
- JSONArray assignments = placement.getJSONArray("assignmentInfo");
- Map<String, String> assignmentsMap = jsonUtils.entryArrayToMap(assignments.toString(), "key", "value");
- solutionInfo.setRehome(Boolean.parseBoolean(assignmentsMap.get("isRehome")));
-
- ServiceInstance si = new ServiceInstance();
- CloudRegion cloud = setCloud(assignmentsMap);
- if(identifierType.equals(CandidateType.SERVICE_INSTANCE_ID.toString())){
- solutionInfo.setHomed(true);
- si.setServiceInstanceId(identifierValue);
- si.setOrchestrationStatus(OrchestrationStatus.CREATED);
- cloud.setLcpCloudRegionId(assignmentsMap.get("cloudRegionId"));
- if(assignmentsMap.containsKey("vnfHostName")){
- logger.debug("Resources has been homed to a vnf");
- GenericVnf vnf = setVnf(assignmentsMap);
- vnf.setCloudRegion(cloud);
- si.getVnfs().add(vnf);
-
- }else if(assignmentsMap.containsKey("primaryPnfName")){
- logger.debug("Resources has been homed to a pnf");
- Pnf priPnf = setPnf(assignmentsMap, "primary");
- priPnf.setCloudRegion(cloud);
- si.getPnfs().add(priPnf);
- if(assignmentsMap.containsKey("secondaryPnfName")){
- Pnf secPnf = setPnf(assignmentsMap, "secondary");
- secPnf.setCloudRegion(cloud);
- si.getPnfs().add(secPnf);
- }
- }
- }else if(identifierType.equals(CandidateType.CLOUD_REGION_ID.toString())){
- logger.debug("Resources has been homed to a cloud region");
- cloud.setLcpCloudRegionId(identifierValue);
- solutionInfo.setHomed(false);
- solutionInfo.setTargetedCloudRegion(cloud);
- si.setOrchestrationStatus(OrchestrationStatus.PRECREATED);
- }else{
- logger.debug(invalidMessage + IDENTIFIER_TYPE);
- throw new BpmnError(UNPROCESSABLE, invalidMessage + IDENTIFIER_TYPE);
- }
- si.setSolutionInfo(solutionInfo);
- return si;
- }
-
- /**
- * Sets the cloud data to a cloud region object
- *
- */
- private CloudRegion setCloud(Map<String, String> assignmentsMap){
- CloudRegion cloud = new CloudRegion();
- cloud.setCloudOwner(assignmentsMap.get("cloudOwner"));
- cloud.setCloudRegionVersion(assignmentsMap.get("aicVersion"));
- cloud.setComplex(assignmentsMap.get("aicClli"));
- return cloud;
- }
-
- /**
- * Sets the vnf data to a generic vnf object
- *
- */
- private GenericVnf setVnf(Map<String, String> assignmentsMap){
- GenericVnf vnf = new GenericVnf();
- vnf.setOrchestrationStatus(OrchestrationStatus.CREATED);
- vnf.setVnfName(assignmentsMap.get("vnfHostName"));
- vnf.setVnfId(assignmentsMap.get("vnfId"));
- return vnf;
- }
-
- /**
- * Sets the pnf data to a pnf object
- *
- */
- private Pnf setPnf(Map<String, String> assignmentsMap, String role){
- Pnf pnf = new Pnf();
- pnf.setRole(role);
- pnf.setOrchestrationStatus(OrchestrationStatus.CREATED);
- pnf.setPnfName(assignmentsMap.get(role + "PnfName"));
- return pnf;
- }
+ private static final Logger logger = LoggerFactory.getLogger(SniroHomingV2.class);
+ private JsonUtils jsonUtils = new JsonUtils();
+ @Autowired
+ private Environment env;
+ @Autowired
+ private SniroClient client;
+ @Autowired
+ private ExceptionBuilder exceptionUtil;
+ private static final String MODEL_NAME = "modelName";
+ private static final String MODEL_INVARIANT_ID = "modelInvariantId";
+ private static final String MODEL_VERSION_ID = "modelVersionId";
+ private static final String MODEL_VERSION = "modelVersion";
+ private static final String SERVICE_RESOURCE_ID = "serviceResourceId";
+ private static final String RESOURCE_MODULE_NAME = "resourceModuleName";
+ private static final String RESOURCE_MODEL_INFO = "resourceModelInfo";
+ private static final String IDENTIFIER_TYPE = "identifierType";
+ private static final String SOLUTIONS = "solutions";
+ private static final String RESOURCE_MISSING_DATA = "Resource does not contain: ";
+ private static final String SERVICE_MISSING_DATA = "Service Instance does not contain: ";
+ private static final String UNPROCESSABLE = "422";
+ private static final int INTERNAL = 500;
+
+ /**
+ * Generates the request payload then sends to sniro manager to perform homing and licensing for the provided
+ * demands
+ *
+ * @param execution
+ */
+ public void callSniro(BuildingBlockExecution execution) {
+ logger.debug("Started Sniro Homing Call Sniro");
+ try {
+ GeneralBuildingBlock bb = execution.getGeneralBuildingBlock();
+
+ RequestContext requestContext = bb.getRequestContext();
+ RequestParameters requestParams = requestContext.getRequestParameters();
+ String requestId = requestContext.getMsoRequestId();
+
+ ServiceInstance serviceInstance = bb.getCustomer().getServiceSubscription().getServiceInstances().get(0);
+ Customer customer = bb.getCustomer();
+
+ String timeout = execution.getVariable("timeout");
+ if (isBlank(timeout)) {
+ timeout = env.getProperty("sniro.manager.timeout", "PT30M");
+ }
+
+ SniroManagerRequest request = new SniroManagerRequest();
+
+ RequestInfo requestInfo = buildRequestInfo(requestId, timeout);
+ request.setRequestInformation(requestInfo);
+
+ ServiceInfo serviceInfo = buildServiceInfo(serviceInstance);
+ request.setServiceInformation(serviceInfo);
+
+ PlacementInfo placementInfo = buildPlacementInfo(customer, requestParams);
+
+ List<Demand> placementDemands = buildPlacementDemands(serviceInstance);
+ placementInfo.setDemands(placementDemands);
+ request.setPlacementInformation(placementInfo);
+
+ LicenseInfo licenseInfo = new LicenseInfo();
+
+ List<Demand> licenseDemands = buildLicenseDemands(serviceInstance);
+ licenseInfo.setDemands(licenseDemands);
+ request.setLicenseInformation(licenseInfo);
+
+ if (placementDemands.size() > 0 || licenseDemands.size() > 0) {
+ client.postDemands(request);
+ } else {
+ logger.debug(SERVICE_MISSING_DATA + "resources eligible for homing or licensing");
+ throw new BpmnError(UNPROCESSABLE, SERVICE_MISSING_DATA + "resources eligible for homing or licensing");
+ }
+
+ // Variables for ReceiveWorkflowMessage subflow
+ execution.setVariable("asyncCorrelator", requestId);
+ execution.setVariable("asyncMessageType", "SNIROResponse");
+ execution.setVariable("asyncTimeout", timeout);
+
+ logger.trace("Completed Sniro Homing Call Sniro");
+ } catch (BpmnError e) {
+ logger.error("Exception occurred", e);
+ exceptionUtil.buildAndThrowWorkflowException(execution, Integer.parseInt(e.getErrorCode()), e.getMessage());
+ } catch (BadResponseException e) {
+ logger.error("Exception occurred", e);
+ exceptionUtil.buildAndThrowWorkflowException(execution, 400, e.getMessage());
+ } catch (Exception e) {
+ logger.error("Exception occurred", e);
+ exceptionUtil.buildAndThrowWorkflowException(execution, INTERNAL,
+ "Internal Error - occurred while preparing sniro request: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Validates, processes, and sets the homing and licensing solutions that are returned by sniro manager
+ *
+ * @param execution
+ * @param asyncResponse
+ */
+ public void processSolution(BuildingBlockExecution execution, String asyncResponse) {
+ logger.trace("Started Sniro Homing Process Solution");
+ try {
+ // TODO improve handling multiple solutions but is dependent on sniro enhancing api + work with sniro
+ // conductor to improve "inventoryType" representation
+ validateSolution(asyncResponse);
+ ServiceInstance serviceInstance = execution.getGeneralBuildingBlock().getCustomer().getServiceSubscription()
+ .getServiceInstances().get(0);
+
+ logger.debug("Processing sniro manager asyncronous response");
+ JSONObject response = new JSONObject(asyncResponse);
+ if (response.has(SOLUTIONS)) {
+ JSONObject allSolutions = response.getJSONObject(SOLUTIONS);
+ if (allSolutions.has("placementSolutions")) {
+ JSONArray placementSolutions = allSolutions.getJSONArray("placementSolutions");
+ for (int i = 0; i < placementSolutions.length(); i++) {
+ JSONArray placements = placementSolutions.getJSONArray(i);
+ processPlacementSolution(serviceInstance, placements, i);
+ }
+ }
+ if (allSolutions.has("licenseSolutions")) {
+ JSONArray licenseSolutions = allSolutions.getJSONArray("licenseSolutions");
+ if (licenseSolutions.length() > 0) {
+ processLicenseSolution(serviceInstance, licenseSolutions);
+ }
+ }
+ } else {
+ throw new BpmnError(UNPROCESSABLE, "Sniro Managers response does not contain: " + SOLUTIONS);
+ }
+
+ execution.setVariable("generalBuildingBlock", execution.getGeneralBuildingBlock());
+
+ logger.trace("Completed Sniro Homing Process Solution");
+ } catch (BpmnError e) {
+ logger.error("Exception occurred", e);
+ exceptionUtil.buildAndThrowWorkflowException(execution, Integer.parseInt(e.getErrorCode()), e.getMessage());
+ } catch (BadResponseException e) {
+ logger.error("Exception occurred", e);
+ exceptionUtil.buildAndThrowWorkflowException(execution, 400, e.getMessage());
+ } catch (Exception e) {
+ logger.error("Exception occurred", e);
+ exceptionUtil.buildAndThrowWorkflowException(execution, INTERNAL,
+ "Internal Error - occurred while processing sniro asynchronous response: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Builds the request information section for the homing/licensing request
+ *
+ * @throws Exception
+ */
+ private RequestInfo buildRequestInfo(String requestId, String timeout) throws Exception {
+ logger.trace("Building request information");
+ RequestInfo requestInfo = new RequestInfo();
+ if (requestId != null) {
+ String host = env.getProperty("mso.workflow.message.endpoint");
+ String callbackUrl = host + "/" + UriUtils.encodePathSegment("SNIROResponse", "UTF-8") + "/"
+ + UriUtils.encodePathSegment(requestId, "UTF-8");
+
+ Duration d = Duration.parse(timeout);
+
+ requestInfo.setTransactionId(requestId);
+ requestInfo.setRequestId(requestId);
+ requestInfo.setCallbackUrl(callbackUrl);
+ requestInfo.setRequestType("create");
+ requestInfo.setTimeout(d.getSeconds());
+
+ } else {
+ throw new BpmnError(UNPROCESSABLE, "Request Context does not contain: requestId");
+ }
+ return requestInfo;
+ }
+
+ /**
+ * Builds the request information section for the homing/licensing request
+ *
+ */
+ private ServiceInfo buildServiceInfo(ServiceInstance serviceInstance) {
+ logger.trace("Building service information");
+ ServiceInfo info = new ServiceInfo();
+ ModelInfoServiceInstance modelInfo = serviceInstance.getModelInfoServiceInstance();
+ if (isNotBlank(modelInfo.getModelInvariantUuid()) && isNotBlank(modelInfo.getModelUuid())) {
+ info.setServiceInstanceId(serviceInstance.getServiceInstanceId());
+ if (modelInfo.getServiceType() != null && modelInfo.getServiceType().length() > 0) { // temp solution
+ info.setServiceName(modelInfo.getServiceType());
+ }
+ if (modelInfo.getServiceRole() != null) {
+ info.setServiceRole(modelInfo.getServiceRole());
+ }
+ info.setModelInfo(buildModelInfo(modelInfo));
+ } else {
+ throw new BpmnError(UNPROCESSABLE, SERVICE_MISSING_DATA + MODEL_VERSION_ID + ", " + MODEL_INVARIANT_ID);
+ }
+ return info;
+ }
+
+ /**
+ * Builds initial section of placement info for the homing/licensing request
+ *
+ */
+ private PlacementInfo buildPlacementInfo(Customer customer, RequestParameters requestParams) {
+ PlacementInfo placementInfo = new PlacementInfo();
+ if (customer != null) {
+ logger.debug("Adding subscriber to placement information");
+ SubscriberInfo subscriber = new SubscriberInfo();
+ subscriber.setGlobalSubscriberId(customer.getGlobalCustomerId());
+ subscriber.setSubscriberName(customer.getSubscriberName());
+ subscriber.setSubscriberCommonSiteId(customer.getSubscriberCommonSiteId());
+ placementInfo.setSubscriberInfo(subscriber);
+ if (requestParams != null) {
+ logger.debug("Adding request parameters to placement information");
+ placementInfo.setRequestParameters(requestParams.toJsonString());
+ }
+ } else {
+ throw new BpmnError(UNPROCESSABLE, SERVICE_MISSING_DATA + "customer");
+ }
+ return placementInfo;
+
+ }
+
+ /**
+ * Builds the placement demand list for the homing/licensing request
+ *
+ */
+ private List<Demand> buildPlacementDemands(ServiceInstance serviceInstance) {
+ logger.trace("Building placement information demands");
+ List<Demand> placementDemands = new ArrayList<Demand>();
+
+ List<AllottedResource> allottedResourceList = serviceInstance.getAllottedResources();
+ if (!allottedResourceList.isEmpty()) {
+ logger.debug("Adding allotted resources to placement demands list");
+ for (AllottedResource ar : allottedResourceList) {
+ if (isBlank(ar.getId())) {
+ ar.setId(UUID.randomUUID().toString());
+ }
+ Demand demand = buildDemand(ar.getId(), ar.getModelInfoAllottedResource());
+ addCandidates(ar, demand);
+ placementDemands.add(demand);
+ }
+ }
+ List<VpnBondingLink> vpnBondingLinkList = serviceInstance.getVpnBondingLinks();
+ if (!vpnBondingLinkList.isEmpty()) {
+ logger.debug("Adding vpn bonding links to placement demands list");
+ for (VpnBondingLink vbl : vpnBondingLinkList) {
+ List<ServiceProxy> serviceProxyList = vbl.getServiceProxies();
+ for (ServiceProxy sp : serviceProxyList) {
+ if (isBlank(sp.getId())) {
+ sp.setId(UUID.randomUUID().toString());
+ }
+ Demand demand = buildDemand(sp.getId(), sp.getModelInfoServiceProxy());
+ addCandidates(sp, demand);
+ placementDemands.add(demand);
+ }
+ }
+ }
+ return placementDemands;
+ }
+
+ /**
+ * Builds the license demand list for the homing/licensing request
+ *
+ */
+ private List<Demand> buildLicenseDemands(ServiceInstance serviceInstance) {
+ logger.trace("Building license information");
+ List<Demand> licenseDemands = new ArrayList<Demand>();
+ List<GenericVnf> vnfList = serviceInstance.getVnfs();
+ if (!vnfList.isEmpty()) {
+ logger.debug("Adding vnfs to license demands list");
+ for (GenericVnf vnf : vnfList) {
+ Demand demand = buildDemand(vnf.getVnfId(), vnf.getModelInfoGenericVnf());
+ licenseDemands.add(demand);
+ }
+ }
+ return licenseDemands;
+ }
+
+ /**
+ * Builds a single demand object
+ *
+ */
+ private Demand buildDemand(String id, ModelInfoMetadata metadata) {
+ logger.debug("Building demand for service or resource: " + id);
+ Demand demand = new Demand();
+ if (isNotBlank(id) && isNotBlank(metadata.getModelInstanceName())) {
+ demand.setServiceResourceId(id);
+ demand.setResourceModuleName(metadata.getModelInstanceName());
+ demand.setModelInfo(buildModelInfo(metadata));
+ } else {
+ throw new BpmnError(UNPROCESSABLE, RESOURCE_MISSING_DATA + "modelInstanceName");
+ }
+ return demand;
+ }
+
+ /**
+ * Builds the resource model info section
+ *
+ */
+ private ModelInfo buildModelInfo(ModelInfoMetadata metadata) {
+ ModelInfo object = new ModelInfo();
+ String invariantUuid = metadata.getModelInvariantUuid();
+ String modelUuid = metadata.getModelUuid();
+ if (isNotBlank(invariantUuid) && isNotBlank(modelUuid)) {
+ object.setModelInvariantId(invariantUuid);
+ object.setModelVersionId(modelUuid);
+ object.setModelName(metadata.getModelName());
+ object.setModelVersion(metadata.getModelVersion());
+ } else if (isNotBlank(invariantUuid)) {
+ throw new BpmnError(UNPROCESSABLE, RESOURCE_MISSING_DATA + MODEL_VERSION_ID);
+ } else {
+ throw new BpmnError(UNPROCESSABLE, RESOURCE_MISSING_DATA + MODEL_INVARIANT_ID);
+ }
+ return object;
+ }
+
+ /**
+ * Adds required, excluded, and existing candidates to a demand
+ *
+ */
+ private void addCandidates(SolutionCandidates candidates, Demand demand) {
+ List<Candidate> required = candidates.getRequiredCandidates();
+ List<Candidate> excluded = candidates.getExcludedCandidates();
+ if (!required.isEmpty()) {
+ List<org.onap.so.client.sniro.beans.Candidate> cans =
+ new ArrayList<org.onap.so.client.sniro.beans.Candidate>();
+ for (Candidate c : required) {
+ org.onap.so.client.sniro.beans.Candidate can = new org.onap.so.client.sniro.beans.Candidate();
+ can.setIdentifierType(c.getIdentifierType());
+ can.setIdentifiers(c.getIdentifiers());
+ can.setCloudOwner(c.getCloudOwner());
+ cans.add(can);
+ }
+ demand.setRequiredCandidates(cans);
+ }
+ if (!excluded.isEmpty()) {
+ List<org.onap.so.client.sniro.beans.Candidate> cans =
+ new ArrayList<org.onap.so.client.sniro.beans.Candidate>();
+ for (Candidate c : excluded) {
+ org.onap.so.client.sniro.beans.Candidate can = new org.onap.so.client.sniro.beans.Candidate();
+ can.setIdentifierType(c.getIdentifierType());
+ can.setIdentifiers(c.getIdentifiers());
+ can.setCloudOwner(c.getCloudOwner());
+ cans.add(can);
+ }
+ demand.setExcludedCandidates(cans);
+ }
+ // TODO support existing candidates
+ }
+
+ /**
+ * Processes the license solutions and sets to the corresponding generic vnf
+ *
+ */
+ private void processLicenseSolution(ServiceInstance serviceInstance, JSONArray licenseSolutions) {
+ List<GenericVnf> vnfs = serviceInstance.getVnfs();
+
+ logger.debug("Processing the license solution");
+ for (int i = 0; i < licenseSolutions.length(); i++) {
+ JSONObject licenseSolution = licenseSolutions.getJSONObject(i);
+ for (GenericVnf vnf : vnfs) {
+ if (licenseSolution.getString(SERVICE_RESOURCE_ID).equals(vnf.getVnfId())) {
+ License license = new License();
+ JSONArray entitlementPools = licenseSolution.getJSONArray("entitlementPoolUUID");
+ List<String> entitlementPoolsList = jsonUtils.StringArrayToList(entitlementPools);
+ license.setEntitlementPoolUuids(entitlementPoolsList);
+ JSONArray licenseKeys = licenseSolution.getJSONArray("licenseKeyGroupUUID");
+ List<String> licenseKeysList = jsonUtils.StringArrayToList(licenseKeys);
+ license.setLicenseKeyGroupUuids(licenseKeysList);
+
+ vnf.setLicense(license);
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes a placement solution list then correlates and sets each placement solution to its corresponding
+ * resource
+ *
+ */
+ private void processPlacementSolution(ServiceInstance serviceInstance, JSONArray placements, int i) {
+ List<VpnBondingLink> links = serviceInstance.getVpnBondingLinks();
+ List<AllottedResource> allottes = serviceInstance.getAllottedResources();
+ List<GenericVnf> vnfs = serviceInstance.getVnfs();
+
+ logger.debug("Processing placement solution " + i + 1);
+ for (int p = 0; p < placements.length(); p++) {
+ JSONObject placement = placements.getJSONObject(p);
+ SolutionInfo solutionInfo = new SolutionInfo();
+ solutionInfo.setSolutionId(i + 1);
+ search: {
+ for (VpnBondingLink vbl : links) {
+ List<ServiceProxy> proxies = vbl.getServiceProxies();
+ for (ServiceProxy sp : proxies) {
+ if (placement.getString(SERVICE_RESOURCE_ID).equals(sp.getId())) {
+ if (i > 0) {
+ if (p % 2 == 0) {
+ VpnBondingLink vblNew = (VpnBondingLink) SerializationUtils.clone(vbl);
+ vblNew.setVpnBondingLinkId(UUID.randomUUID().toString());
+ links.add(vblNew);
+ }
+ links.get(links.size() - 1).getServiceProxy(sp.getId())
+ .setServiceInstance(setSolution(solutionInfo, placement));
+ } else {
+ sp.setServiceInstance(setSolution(solutionInfo, placement));
+ }
+ break search;
+ }
+ }
+ }
+ for (AllottedResource ar : allottes) {
+ if (placement.getString(SERVICE_RESOURCE_ID).equals(ar.getId())) {
+ ar.setParentServiceInstance(setSolution(solutionInfo, placement));
+ break search;
+ }
+ }
+ for (GenericVnf vnf : vnfs) {
+ if (placement.getString(SERVICE_RESOURCE_ID).equals(vnf.getVnfId())) {
+ ServiceInstance si = setSolution(solutionInfo, placement);
+ serviceInstance.setSolutionInfo(si.getSolutionInfo());
+ serviceInstance.getVnfs().add(si.getVnfs().get(0));
+ break search;
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Creates and sets necessary pojos with placement solution data for a given demand
+ *
+ */
+ private ServiceInstance setSolution(SolutionInfo solutionInfo, JSONObject placement) {
+ logger.debug("Mapping placement solution");
+ String invalidMessage = "Sniro Managers Response contains invalid: ";
+
+ JSONObject solution = placement.getJSONObject("solution");
+ String identifierType = solution.getString(IDENTIFIER_TYPE);
+ List<String> identifiersList = jsonUtils.StringArrayToList(solution.getJSONArray("identifiers").toString());
+ String identifierValue = identifiersList.get(0);
+
+ JSONArray assignments = placement.getJSONArray("assignmentInfo");
+ Map<String, String> assignmentsMap = jsonUtils.entryArrayToMap(assignments.toString(), "key", "value");
+ solutionInfo.setRehome(Boolean.parseBoolean(assignmentsMap.get("isRehome")));
+
+ ServiceInstance si = new ServiceInstance();
+ CloudRegion cloud = setCloud(assignmentsMap);
+ if (identifierType.equals(CandidateType.SERVICE_INSTANCE_ID.toString())) {
+ solutionInfo.setHomed(true);
+ si.setServiceInstanceId(identifierValue);
+ si.setOrchestrationStatus(OrchestrationStatus.CREATED);
+ cloud.setLcpCloudRegionId(assignmentsMap.get("cloudRegionId"));
+ if (assignmentsMap.containsKey("vnfHostName")) {
+ logger.debug("Resources has been homed to a vnf");
+ GenericVnf vnf = setVnf(assignmentsMap);
+ vnf.setCloudRegion(cloud);
+ si.getVnfs().add(vnf);
+
+ } else if (assignmentsMap.containsKey("primaryPnfName")) {
+ logger.debug("Resources has been homed to a pnf");
+ Pnf priPnf = setPnf(assignmentsMap, "primary");
+ priPnf.setCloudRegion(cloud);
+ si.getPnfs().add(priPnf);
+ if (assignmentsMap.containsKey("secondaryPnfName")) {
+ Pnf secPnf = setPnf(assignmentsMap, "secondary");
+ secPnf.setCloudRegion(cloud);
+ si.getPnfs().add(secPnf);
+ }
+ }
+ } else if (identifierType.equals(CandidateType.CLOUD_REGION_ID.toString())) {
+ logger.debug("Resources has been homed to a cloud region");
+ cloud.setLcpCloudRegionId(identifierValue);
+ solutionInfo.setHomed(false);
+ solutionInfo.setTargetedCloudRegion(cloud);
+ si.setOrchestrationStatus(OrchestrationStatus.PRECREATED);
+ } else {
+ logger.debug(invalidMessage + IDENTIFIER_TYPE);
+ throw new BpmnError(UNPROCESSABLE, invalidMessage + IDENTIFIER_TYPE);
+ }
+ si.setSolutionInfo(solutionInfo);
+ return si;
+ }
+
+ /**
+ * Sets the cloud data to a cloud region object
+ *
+ */
+ private CloudRegion setCloud(Map<String, String> assignmentsMap) {
+ CloudRegion cloud = new CloudRegion();
+ cloud.setCloudOwner(assignmentsMap.get("cloudOwner"));
+ cloud.setCloudRegionVersion(assignmentsMap.get("aicVersion"));
+ cloud.setComplex(assignmentsMap.get("aicClli"));
+ return cloud;
+ }
+
+ /**
+ * Sets the vnf data to a generic vnf object
+ *
+ */
+ private GenericVnf setVnf(Map<String, String> assignmentsMap) {
+ GenericVnf vnf = new GenericVnf();
+ vnf.setOrchestrationStatus(OrchestrationStatus.CREATED);
+ vnf.setVnfName(assignmentsMap.get("vnfHostName"));
+ vnf.setVnfId(assignmentsMap.get("vnfId"));
+ return vnf;
+ }
+
+ /**
+ * Sets the pnf data to a pnf object
+ *
+ */
+ private Pnf setPnf(Map<String, String> assignmentsMap, String role) {
+ Pnf pnf = new Pnf();
+ pnf.setRole(role);
+ pnf.setOrchestrationStatus(OrchestrationStatus.CREATED);
+ pnf.setPnfName(assignmentsMap.get(role + "PnfName"));
+ return pnf;
+ }