Merge "add junit coverage"
[so.git] / bpmn / so-bpmn-tasks / src / main / java / org / onap / so / bpmn / infrastructure / aai / tasks / AAICreateTasks.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright (c) 2019 Samsung
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.so.bpmn.infrastructure.aai.tasks;
24
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Optional;
28 import java.util.TreeSet;
29 import java.util.UUID;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32 import org.onap.so.logger.LoggingAnchor;
33 import org.camunda.bpm.engine.delegate.BpmnError;
34 import org.onap.so.bpmn.common.BuildingBlockExecution;
35 import org.onap.so.bpmn.servicedecomposition.bbobjects.CloudRegion;
36 import org.onap.so.bpmn.servicedecomposition.bbobjects.Collection;
37 import org.onap.so.bpmn.servicedecomposition.bbobjects.Configuration;
38 import org.onap.so.bpmn.servicedecomposition.bbobjects.Customer;
39 import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
40 import org.onap.so.bpmn.servicedecomposition.bbobjects.InstanceGroup;
41 import org.onap.so.bpmn.servicedecomposition.bbobjects.L3Network;
42 import org.onap.so.bpmn.servicedecomposition.bbobjects.LineOfBusiness;
43 import org.onap.so.bpmn.servicedecomposition.bbobjects.NetworkPolicy;
44 import org.onap.so.bpmn.servicedecomposition.bbobjects.OwningEntity;
45 import org.onap.so.bpmn.servicedecomposition.bbobjects.Platform;
46 import org.onap.so.bpmn.servicedecomposition.bbobjects.Project;
47 import org.onap.so.bpmn.servicedecomposition.bbobjects.ServiceInstance;
48 import org.onap.so.bpmn.servicedecomposition.bbobjects.VfModule;
49 import org.onap.so.bpmn.servicedecomposition.bbobjects.VolumeGroup;
50 import org.onap.so.bpmn.servicedecomposition.entities.GeneralBuildingBlock;
51 import org.onap.so.bpmn.servicedecomposition.entities.ResourceKey;
52 import org.onap.so.bpmn.servicedecomposition.tasks.ExtractPojosForBB;
53 import org.onap.so.bpmn.servicedecomposition.tasks.exceptions.DuplicateNameException;
54 import org.onap.so.client.aai.AAIObjectPlurals;
55 import org.onap.so.client.aai.entities.uri.AAIResourceUri;
56 import org.onap.so.client.aai.entities.uri.AAIUriFactory;
57 import org.onap.so.client.exception.BBObjectNotFoundException;
58 import org.onap.so.client.exception.ExceptionBuilder;
59 import org.onap.so.client.orchestration.AAIConfigurationResources;
60 import org.onap.so.client.orchestration.AAIInstanceGroupResources;
61 import org.onap.so.client.orchestration.AAINetworkResources;
62 import org.onap.so.client.orchestration.AAIServiceInstanceResources;
63 import org.onap.so.client.orchestration.AAIVfModuleResources;
64 import org.onap.so.client.orchestration.AAIVnfResources;
65 import org.onap.so.client.orchestration.AAIVolumeGroupResources;
66 import org.onap.so.client.orchestration.AAIVpnBindingResources;
67 import org.onap.so.logger.ErrorCode;
68 import org.onap.so.logger.MessageEnum;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71 import org.springframework.beans.factory.annotation.Autowired;
72 import org.springframework.core.env.Environment;
73 import org.springframework.stereotype.Component;
74 import com.google.common.base.Strings;
75
76 @Component
77 public class AAICreateTasks {
78
79     private static final Logger logger = LoggerFactory.getLogger(AAICreateTasks.class);
80     private static final String networkTypeProvider = "PROVIDER";
81     private static String NETWORK_COLLECTION_NAME = "networkCollectionName";
82     private static String CONTRAIL_NETWORK_POLICY_FQDN_LIST = "contrailNetworkPolicyFqdnList";
83     private static String HEAT_STACK_ID = "heatStackId";
84     private static String NETWORK_POLICY_FQDN_PARAM = "network-policy-fqdn";
85     @Autowired
86     private AAIServiceInstanceResources aaiSIResources;
87     @Autowired
88     private AAIVnfResources aaiVnfResources;
89     @Autowired
90     private ExceptionBuilder exceptionUtil;
91     @Autowired
92     private ExtractPojosForBB extractPojosForBB;
93     @Autowired
94     private AAIVolumeGroupResources aaiVolumeGroupResources;
95     @Autowired
96     private AAIVfModuleResources aaiVfModuleResources;
97     @Autowired
98     private AAINetworkResources aaiNetworkResources;
99     @Autowired
100     private AAIVpnBindingResources aaiVpnBindingResources;
101     @Autowired
102     private AAIConfigurationResources aaiConfigurationResources;
103     @Autowired
104     private AAIInstanceGroupResources aaiInstanceGroupResources;
105     @Autowired
106     private Environment env;
107
108     /**
109      * This method is used for creating the service instance in A&AI.
110      *
111      * It will check the alaCarte and create the service instance in A&AI.
112      *
113      * @param execution
114      * @throws @return
115      */
116     public void createServiceInstance(BuildingBlockExecution execution) {
117         try {
118             ServiceInstance serviceInstance =
119                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
120             Customer customer = execution.getGeneralBuildingBlock().getCustomer();
121             aaiSIResources.createServiceInstance(serviceInstance, customer);
122         } catch (Exception ex) {
123             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
124         }
125     }
126
127     /**
128      * This method is used for creating and subscribing the service in A&AI.
129      *
130      * @param execution
131      * @throws @return
132      */
133     public void createServiceSubscription(BuildingBlockExecution execution) {
134         try {
135             ServiceInstance serviceInstance =
136                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
137             Customer customer = execution.getGeneralBuildingBlock().getCustomer();
138             if (null == customer) {
139                 String errorMessage =
140                         "Exception in creating ServiceSubscription. Customer not present for ServiceInstanceID: "
141                                 + serviceInstance.getServiceInstanceId();
142                 logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), errorMessage,
143                         "BPMN", ErrorCode.UnknownError.getValue(), errorMessage);
144                 exceptionUtil.buildAndThrowWorkflowException(execution, 7000, errorMessage);
145             }
146             aaiSIResources.createServiceSubscription(customer);
147         } catch (BpmnError ex) {
148             throw ex;
149         } catch (Exception ex) {
150             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
151         }
152     }
153
154     /**
155      * This method is used for creation of the project A&AI.
156      *
157      * @param execution
158      * @throws @return
159      */
160     public void createProject(BuildingBlockExecution execution) {
161         try {
162             ServiceInstance serviceInstance =
163                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
164             Project project = serviceInstance.getProject();
165             if (project != null) {
166                 if (project.getProjectName() == null || "".equals(project.getProjectName())) {
167                     logger.info("ProjectName is null in input. Skipping create project...");
168                 } else {
169                     aaiSIResources.createProjectandConnectServiceInstance(project, serviceInstance);
170                 }
171             }
172         } catch (Exception ex) {
173             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
174         }
175     }
176
177     /**
178      * This method is used for creating OwningEntity A&AI.
179      *
180      * @param execution
181      * @throws @return
182      */
183     public void createOwningEntity(BuildingBlockExecution execution) {
184         try {
185             ServiceInstance serviceInstance =
186                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
187             OwningEntity owningEntity = serviceInstance.getOwningEntity();
188             if (Strings.isNullOrEmpty(owningEntity.getOwningEntityId())
189                     && Strings.isNullOrEmpty(owningEntity.getOwningEntityName())) {
190                 String msg = "Exception in AAICreateOwningEntity. OwningEntityId and Name are null.";
191                 execution.setVariable("ErrorCreateOEAAI", msg);
192                 exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg);
193             } else if (Strings.isNullOrEmpty(owningEntity.getOwningEntityId())
194                     && !Strings.isNullOrEmpty(owningEntity.getOwningEntityName())) {
195                 if (aaiSIResources.existsOwningEntityName(owningEntity.getOwningEntityName())) {
196                     org.onap.aai.domain.yang.OwningEntity aaiEntity =
197                             aaiSIResources.getOwningEntityByName(owningEntity.getOwningEntityName());
198                     owningEntity.setOwningEntityId(aaiEntity.getOwningEntityId());
199                     owningEntity.setOwningEntityName(owningEntity.getOwningEntityName());
200                     aaiSIResources.connectOwningEntityandServiceInstance(owningEntity, serviceInstance);
201                 } else {
202                     owningEntity.setOwningEntityId(UUID.randomUUID().toString());
203                     aaiSIResources.createOwningEntityandConnectServiceInstance(owningEntity, serviceInstance);
204                 }
205             } else {
206                 if (aaiSIResources.existsOwningEntity(owningEntity)) {
207                     aaiSIResources.connectOwningEntityandServiceInstance(owningEntity, serviceInstance);
208                 } else {
209                     if (Strings.isNullOrEmpty(owningEntity.getOwningEntityName())) {
210                         String msg =
211                                 "Exception in AAICreateOwningEntity. Can't create an owningEntity with no owningEntityName.";
212                         logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
213                                 ErrorCode.UnknownError.getValue(), msg);
214                         exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg);
215                     } else {
216                         if (aaiSIResources.existsOwningEntityName(owningEntity.getOwningEntityName())) {
217                             String msg =
218                                     "Exception in AAICreateOwningEntity. Can't create OwningEntity as name already exists in AAI associated with a different owning-entity-id (name must be unique)";
219                             logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg,
220                                     "BPMN", ErrorCode.UnknownError.getValue(), msg);
221                             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg);
222                         } else {
223                             aaiSIResources.createOwningEntityandConnectServiceInstance(owningEntity, serviceInstance);
224                         }
225                     }
226                 }
227             }
228         } catch (Exception ex) {
229             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
230         }
231     }
232
233     /**
234      * This method is used for creating Vnf in A&AI.
235      *
236      * It will check if the Vnf Name is exits in A&AI then it will throw the duplicate name exception.
237      *
238      * Otherwise it will create the vnf amd connect to the serviceinstance.
239      *
240      * @param execution
241      * @throws @return
242      */
243     public void createVnf(BuildingBlockExecution execution) {
244         try {
245             GenericVnf vnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
246             ServiceInstance serviceInstance =
247                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
248             execution.setVariable("homing", Boolean.TRUE.equals(vnf.isCallHoming()));
249             aaiVnfResources.createVnfandConnectServiceInstance(vnf, serviceInstance);
250         } catch (Exception ex) {
251             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
252         }
253     }
254
255     /**
256      * This method is used for separating (,) from the string.
257      *
258      * @param str
259      * @throws @return
260      */
261     public void createPlatform(BuildingBlockExecution execution) {
262         try {
263             GenericVnf vnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
264             Platform platform = vnf.getPlatform();
265             if (platform != null) {
266                 if (platform.getPlatformName() == null || "".equals(platform.getPlatformName())) {
267                     logger.debug("PlatformName is null in input. Skipping create platform...");
268                 } else {
269                     List<String> platforms = splitCDL(platform.getPlatformName());
270                     platforms.stream().forEach(platformName -> aaiVnfResources
271                             .createPlatformandConnectVnf(new Platform(platformName), vnf));
272                 }
273             }
274         } catch (Exception ex) {
275             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
276         }
277
278     }
279
280     /**
281      * This method is used for separating (,) from the string.
282      *
283      * @param str
284      * @throws @return
285      */
286     public List<String> splitCDL(String str) {
287         return Stream.of(str.split(",")).map(String::trim).map(elem -> new String(elem)).collect(Collectors.toList());
288     }
289
290     /**
291      * This method is used for creating the type of business in A&AI.
292      *
293      * @param execution
294      * @throws @return
295      */
296     public void createLineOfBusiness(BuildingBlockExecution execution) {
297         try {
298             GenericVnf vnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
299             LineOfBusiness lineOfBusiness = vnf.getLineOfBusiness();
300             if (lineOfBusiness != null) {
301                 if (lineOfBusiness.getLineOfBusinessName() == null
302                         || "".equals(lineOfBusiness.getLineOfBusinessName())) {
303                     logger.info("lineOfBusiness is null in input. Skipping create lineOfBusiness...");
304                 } else {
305                     List<String> lineOfBussinesses = splitCDL(lineOfBusiness.getLineOfBusinessName());
306                     lineOfBussinesses.stream().forEach(lobName -> aaiVnfResources
307                             .createLineOfBusinessandConnectVnf(new LineOfBusiness(lobName), vnf));
308                 }
309             }
310         } catch (Exception ex) {
311             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
312         }
313     }
314
315     /**
316      * This method is used for creating the volume group in A&AI.
317      *
318      * @param execution
319      * @throws @return
320      */
321     public void createVolumeGroup(BuildingBlockExecution execution) {
322         try {
323             GeneralBuildingBlock gBBInput = execution.getGeneralBuildingBlock();
324
325             GenericVnf genericVnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
326             VolumeGroup volumeGroup = extractPojosForBB.extractByKey(execution, ResourceKey.VOLUME_GROUP_ID);
327             CloudRegion cloudRegion = gBBInput.getCloudRegion();
328             aaiVolumeGroupResources.createVolumeGroup(volumeGroup, cloudRegion);
329             aaiVolumeGroupResources.connectVolumeGroupToVnf(genericVnf, volumeGroup, cloudRegion);
330             aaiVolumeGroupResources.connectVolumeGroupToTenant(volumeGroup, cloudRegion);
331         } catch (Exception ex) {
332             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
333         }
334     }
335
336     /**
337      * This method is used for creating the vfModule in A&AI.
338      *
339      * @param execution
340      * @throws @return
341      */
342     public void createVfModule(BuildingBlockExecution execution) {
343         try {
344             GenericVnf vnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
345             VfModule vfModule = extractPojosForBB.extractByKey(execution, ResourceKey.VF_MODULE_ID);
346             int moduleIndex = 0;
347             if (vfModule.getModelInfoVfModule() != null
348                     && !Boolean.TRUE.equals(vfModule.getModelInfoVfModule().getIsBaseBoolean())) {
349                 moduleIndex = this.getLowestUnusedVfModuleIndexFromAAIVnfResponse(vnf, vfModule);
350             }
351             vfModule.setModuleIndex(moduleIndex);
352             aaiVfModuleResources.createVfModule(vfModule, vnf);
353         } catch (Exception ex) {
354             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
355         }
356     }
357
358     /**
359      * BPMN access method to establish relationships in AAI
360      *
361      * @param execution
362      * @throws Exception
363      */
364     public void connectVfModuleToVolumeGroup(BuildingBlockExecution execution) {
365         try {
366             GenericVnf vnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
367             VfModule vfModule = extractPojosForBB.extractByKey(execution, ResourceKey.VF_MODULE_ID);
368             VolumeGroup volumeGroup = null;
369             try {
370                 volumeGroup = extractPojosForBB.extractByKey(execution, ResourceKey.VOLUME_GROUP_ID);
371             } catch (BBObjectNotFoundException e) {
372                 logger.info("VolumeGroup not found. Skipping Connect between VfModule and VolumeGroup");
373             }
374             if (volumeGroup != null) {
375                 logger.debug("Connecting VfModule to VolumGroup");
376                 aaiVfModuleResources.connectVfModuleToVolumeGroup(vnf, vfModule, volumeGroup,
377                         execution.getGeneralBuildingBlock().getCloudRegion());
378             }
379         } catch (Exception ex) {
380             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
381         }
382     }
383
384     /**
385      * BPMN access method to execute Create L3Network operation (PUT )in AAI
386      *
387      * @param execution
388      * @throws Exception
389      */
390     public void createNetwork(BuildingBlockExecution execution) {
391         try {
392             ServiceInstance serviceInstance =
393                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
394             L3Network l3network = extractPojosForBB.extractByKey(execution, ResourceKey.NETWORK_ID);
395             // set default to false. ToBe updated by SDNC
396             l3network.setIsBoundToVpn(false);
397             // define is bound to vpn flag as true if NEUTRON_NETWORK_TYPE is PROVIDER
398             if (l3network.getModelInfoNetwork().getNeutronNetworkType().equalsIgnoreCase(networkTypeProvider))
399                 l3network.setIsBoundToVpn(true);
400             // put network shell in AAI
401             aaiNetworkResources.createNetworkConnectToServiceInstance(l3network, serviceInstance);
402         } catch (Exception ex) {
403             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
404         }
405     }
406
407     /**
408      * This method is used for creating the customer in A&AI.
409      *
410      * @param execution
411      * @throws Exception
412      */
413     public void createCustomer(BuildingBlockExecution execution) throws Exception {
414         try {
415             Customer customer = execution.getGeneralBuildingBlock().getCustomer();
416
417             aaiVpnBindingResources.createCustomer(customer);
418         } catch (Exception ex) {
419             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
420         }
421     }
422
423     /**
424      * BPMN access method to execute NetworkCollection operation (PUT) in AAI
425      *
426      * @param execution
427      * @throws Exception
428      */
429     public void createNetworkCollection(BuildingBlockExecution execution) {
430         try {
431             ServiceInstance serviceInstance =
432                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
433             Collection networkCollection = serviceInstance.getCollection();
434             // pass name generated for NetworkCollection/NetworkCollectionInstanceGroup in previous step of the BB flow
435             // put shell in AAI
436             networkCollection.setName(execution.getVariable(NETWORK_COLLECTION_NAME));
437             aaiNetworkResources.createNetworkCollection(networkCollection);
438         } catch (Exception ex) {
439             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
440         }
441     }
442
443     /**
444      * BPMN access method to execute NetworkCollectionInstanceGroup operation (PUT) in AAI
445      *
446      * @param execution
447      * @throws Exception
448      */
449     public void createNetworkCollectionInstanceGroup(BuildingBlockExecution execution) {
450         try {
451             ServiceInstance serviceInstance =
452                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
453             InstanceGroup instanceGroup = serviceInstance.getCollection().getInstanceGroup();
454             // set name generated for NetworkCollection/NetworkCollectionInstanceGroup in previous step of the BB flow
455             instanceGroup.setInstanceGroupName(execution.getVariable(NETWORK_COLLECTION_NAME));
456             // put shell in AAI
457             aaiNetworkResources.createNetworkInstanceGroup(instanceGroup);
458         } catch (Exception ex) {
459             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
460         }
461     }
462
463
464     /**
465      * BPMN access method to establish relationships in AAI
466      *
467      * @param execution
468      * @throws Exception
469      */
470     public void connectNetworkToTenant(BuildingBlockExecution execution) {
471         try {
472             L3Network l3network = extractPojosForBB.extractByKey(execution, ResourceKey.NETWORK_ID);
473             aaiNetworkResources.connectNetworkToTenant(l3network, execution.getGeneralBuildingBlock().getCloudRegion());
474         } catch (Exception ex) {
475             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
476         }
477     }
478
479     /**
480      * BPMN access method to establish relationships in AAI
481      *
482      * @param execution
483      * @throws Exception
484      */
485     public void connectNetworkToCloudRegion(BuildingBlockExecution execution) {
486         try {
487             L3Network l3network = extractPojosForBB.extractByKey(execution, ResourceKey.NETWORK_ID);
488             aaiNetworkResources.connectNetworkToCloudRegion(l3network,
489                     execution.getGeneralBuildingBlock().getCloudRegion());
490         } catch (Exception ex) {
491             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
492         }
493     }
494
495     /**
496      * BPMN access method to establish relationships in AAI
497      *
498      * @param execution
499      * @throws Exception
500      */
501     public void connectVnfToCloudRegion(BuildingBlockExecution execution) {
502         try {
503             boolean cloudRegionsToSkip = false;
504             String[] cloudRegions = env.getProperty("mso.bpmn.cloudRegionIdsToSkipAddingVnfEdgesTo", String[].class);
505             if (cloudRegions != null) {
506                 cloudRegionsToSkip = Arrays.stream(cloudRegions)
507                         .anyMatch(execution.getGeneralBuildingBlock().getCloudRegion().getLcpCloudRegionId()::equals);
508             }
509             if (!cloudRegionsToSkip) {
510                 GenericVnf vnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
511                 aaiVnfResources.connectVnfToCloudRegion(vnf, execution.getGeneralBuildingBlock().getCloudRegion());
512             }
513         } catch (Exception ex) {
514             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
515         }
516     }
517
518     /**
519      * BPMN access method to establish relationships in AAI
520      *
521      * @param execution
522      * @throws Exception
523      */
524     public void connectVnfToTenant(BuildingBlockExecution execution) {
525         try {
526             GenericVnf vnf = extractPojosForBB.extractByKey(execution, ResourceKey.GENERIC_VNF_ID);
527             aaiVnfResources.connectVnfToTenant(vnf, execution.getGeneralBuildingBlock().getCloudRegion());
528         } catch (Exception ex) {
529             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
530         }
531     }
532
533     /**
534      * BPMN access method to establish relationships in AAI
535      *
536      * @param execution
537      * @throws Exception
538      */
539     public void connectNetworkToNetworkCollectionServiceInstance(BuildingBlockExecution execution) {
540         try {
541             ServiceInstance serviceInstance =
542                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
543             L3Network l3network = extractPojosForBB.extractByKey(execution, ResourceKey.NETWORK_ID);
544             aaiNetworkResources.connectNetworkToNetworkCollectionServiceInstance(l3network, serviceInstance);
545         } catch (Exception ex) {
546             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
547         }
548     }
549
550     /**
551      * BPMN access method to establish relationships in AAI
552      *
553      * @param execution
554      * @throws Exception
555      */
556     public void connectNetworkToNetworkCollectionInstanceGroup(BuildingBlockExecution execution) {
557         try {
558             ServiceInstance serviceInstance =
559                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
560             L3Network l3network = extractPojosForBB.extractByKey(execution, ResourceKey.NETWORK_ID);
561             // connect network only if Instance Group / Collection objects exist
562             if (serviceInstance.getCollection() != null && serviceInstance.getCollection().getInstanceGroup() != null)
563                 aaiNetworkResources.connectNetworkToNetworkCollectionInstanceGroup(l3network,
564                         serviceInstance.getCollection().getInstanceGroup());
565         } catch (Exception ex) {
566             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
567         }
568     }
569
570     /**
571      * This method is used for configuring the service in A&AI.
572      *
573      * @param execution @throws
574      */
575     public void createConfiguration(BuildingBlockExecution execution) {
576         try {
577             Configuration configuration = extractPojosForBB.extractByKey(execution, ResourceKey.CONFIGURATION_ID);
578             aaiConfigurationResources.createConfiguration(configuration);
579         } catch (Exception ex) {
580             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
581         }
582     }
583
584     /**
585      * This method is used for creating vnf instance group in A&AI.
586      *
587      * @param execution @throws
588      */
589     public void createInstanceGroupVnf(BuildingBlockExecution execution) {
590         try {
591             ServiceInstance serviceInstance =
592                     extractPojosForBB.extractByKey(execution, ResourceKey.SERVICE_INSTANCE_ID);
593             InstanceGroup instanceGroup = extractPojosForBB.extractByKey(execution, ResourceKey.INSTANCE_GROUP_ID);
594             aaiInstanceGroupResources.createInstanceGroupandConnectServiceInstance(instanceGroup, serviceInstance);
595         } catch (Exception ex) {
596             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
597         }
598     }
599
600     /**
601      * This method is used to put the network policy in A&AI.
602      *
603      * @param execution @throws
604      */
605     public void createNetworkPolicies(BuildingBlockExecution execution) {
606         try {
607             String fqdns = execution.getVariable(CONTRAIL_NETWORK_POLICY_FQDN_LIST);
608             if (fqdns != null && !fqdns.isEmpty()) {
609                 String fqdnList[] = fqdns.split(",");
610                 int fqdnCount = fqdnList.length;
611                 if (fqdnCount > 0) {
612                     for (int i = 0; i < fqdnCount; i++) {
613                         String fqdn = fqdnList[i];
614                         AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.NETWORK_POLICY);
615                         uri.queryParam(NETWORK_POLICY_FQDN_PARAM, fqdn);
616                         Optional<org.onap.aai.domain.yang.NetworkPolicy> oNetPolicy =
617                                 aaiNetworkResources.getNetworkPolicy(uri);
618                         if (!oNetPolicy.isPresent()) {
619                             logger.debug("This network policy FQDN is not in AAI yet: {}", fqdn);
620                             String networkPolicyId = UUID.randomUUID().toString();
621                             logger.debug("Adding network-policy with network-policy-id {}", networkPolicyId);
622                             NetworkPolicy networkPolicy = new NetworkPolicy();
623                             networkPolicy.setNetworkPolicyId(networkPolicyId);
624                             networkPolicy.setNetworkPolicyFqdn(fqdn);
625                             networkPolicy.setHeatStackId(execution.getVariable(HEAT_STACK_ID));
626
627                             aaiNetworkResources.createNetworkPolicy(networkPolicy);
628                         }
629                     }
630                 }
631             }
632         } catch (Exception ex) {
633             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
634         }
635     }
636
637     /**
638      * Groups existing vf modules by the model uuid of our new vf module and returns the lowest unused index
639      *
640      * if we have a module type A, and there are 3 instances of those, and then module type B has 2 instances, if we are
641      * adding a new module type A, the vf-module-index should be 3 assuming contiguous indices (not 5, or 2)
642      *
643      */
644     protected int getLowestUnusedVfModuleIndexFromAAIVnfResponse(GenericVnf genericVnf, VfModule newVfModule) {
645
646         String newVfModuleModelInvariantUUID = null;
647         if (newVfModule.getModelInfoVfModule() != null) {
648             newVfModuleModelInvariantUUID = newVfModule.getModelInfoVfModule().getModelInvariantUUID();
649         }
650
651
652         if (genericVnf != null && genericVnf.getVfModules() != null && !genericVnf.getVfModules().isEmpty()) {
653             List<VfModule> modules = genericVnf.getVfModules().stream()
654                     .filter(item -> !item.getVfModuleId().equals(newVfModule.getVfModuleId()))
655                     .collect(Collectors.toList());
656             TreeSet<Integer> moduleIndices = new TreeSet<>();
657             int nullIndexFound = 0;
658             for (VfModule vfModule : modules) {
659                 if (vfModule.getModelInfoVfModule() != null) {
660                     if (vfModule.getModelInfoVfModule().getModelInvariantUUID().equals(newVfModuleModelInvariantUUID)) {
661                         if (vfModule.getModuleIndex() != null) {
662                             moduleIndices.add(vfModule.getModuleIndex());
663                         } else {
664                             nullIndexFound++;
665                             logger.warn("Found null index for vf-module-id {} and model-invariant-uuid {}",
666                                     vfModule.getVfModuleId(), vfModule.getModelInfoVfModule().getModelInvariantUUID());
667                         }
668                     }
669                 }
670             }
671
672             return calculateUnusedIndex(moduleIndices, nullIndexFound);
673         } else {
674             return 0;
675         }
676     }
677
678     protected int calculateUnusedIndex(TreeSet<Integer> moduleIndices, int nullIndexFound) {
679         // pad array with nulls
680         Integer[] temp = new Integer[moduleIndices.size() + nullIndexFound];
681         Integer[] array = moduleIndices.toArray(temp);
682         int result = 0;
683         // when a null is found skip that potential value
684         // effectively creates something like, [0,1,3,null,null] -> [0,1,null(2),3,null(4)]
685         for (int i = 0; i < array.length; i++, result++) {
686             if (Integer.valueOf(result) != array[i]) {
687                 if (nullIndexFound > 0) {
688                     nullIndexFound--;
689                     i--;
690                 } else {
691                     break;
692                 }
693             }
694         }
695
696         return result;
697     }
698 }