Merge "added in fix to use old volume group name for"
[so.git] / adapters / mso-openstack-adapters / src / main / java / org / onap / so / heatbridge / HeatBridgeImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 /*
22  * Copyright (C) 2018 Bell Canada. All rights reserved.
23  *
24  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
25  * the License. You may obtain a copy of the License at
26  *
27  * http://www.apache.org/licenses/LICENSE-2.0
28  *
29  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
30  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
31  * specific language governing permissions and limitations under the License.
32  */
33 package org.onap.so.heatbridge;
34
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Objects;
39 import java.util.Optional;
40 import java.util.concurrent.ConcurrentHashMap;
41 import java.util.function.Function;
42 import java.util.function.Predicate;
43 import java.util.stream.Collectors;
44 import javax.annotation.Nonnull;
45 import javax.ws.rs.WebApplicationException;
46 import org.apache.commons.collections.CollectionUtils;
47 import org.apache.commons.validator.routines.InetAddressValidator;
48 import org.onap.aai.domain.yang.Flavor;
49 import org.onap.aai.domain.yang.Image;
50 import org.onap.aai.domain.yang.L3InterfaceIpv4AddressList;
51 import org.onap.aai.domain.yang.LInterface;
52 import org.onap.aai.domain.yang.PInterface;
53 import org.onap.aai.domain.yang.Pserver;
54 import org.onap.aai.domain.yang.SriovPf;
55 import org.onap.aai.domain.yang.SriovPfs;
56 import org.onap.aai.domain.yang.SriovVf;
57 import org.onap.aai.domain.yang.SriovVfs;
58 import org.onap.aai.domain.yang.VfModule;
59 import org.onap.aai.domain.yang.Vlan;
60 import org.onap.aai.domain.yang.Vlans;
61 import org.onap.aai.domain.yang.Vserver;
62 import org.onap.aaiclient.client.aai.AAIObjectType;
63 import org.onap.aaiclient.client.aai.AAIResourcesClient;
64 import org.onap.aaiclient.client.aai.AAISingleTransactionClient;
65 import org.onap.aaiclient.client.aai.entities.AAIResultWrapper;
66 import org.onap.aaiclient.client.aai.entities.Relationships;
67 import org.onap.aaiclient.client.aai.entities.uri.AAIResourceUri;
68 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory;
69 import org.onap.aaiclient.client.graphinventory.entities.uri.Depth;
70 import org.onap.aaiclient.client.graphinventory.exceptions.BulkProcessFailed;
71 import org.onap.logging.filter.base.ErrorCode;
72 import org.onap.so.db.catalog.beans.CloudIdentity;
73 import org.onap.so.db.catalog.beans.ServerType;
74 import org.onap.so.heatbridge.constants.HeatBridgeConstants;
75 import org.onap.so.heatbridge.factory.MsoCloudClientFactoryImpl;
76 import org.onap.so.heatbridge.helpers.AaiHelper;
77 import org.onap.so.heatbridge.openstack.api.OpenstackClient;
78 import org.onap.so.heatbridge.openstack.factory.OpenstackClientFactoryImpl;
79 import org.onap.so.heatbridge.utils.HeatBridgeUtils;
80 import org.onap.so.logger.LoggingAnchor;
81 import org.onap.so.logger.MessageEnum;
82 import org.onap.so.spring.SpringContextHelper;
83 import org.openstack4j.model.compute.Server;
84 import org.openstack4j.model.heat.Resource;
85 import org.openstack4j.model.network.IP;
86 import org.openstack4j.model.network.Network;
87 import org.openstack4j.model.network.NetworkType;
88 import org.openstack4j.model.network.Port;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91 import org.springframework.core.env.Environment;
92 import com.google.common.base.Preconditions;
93 import com.google.common.base.Strings;
94 import com.google.common.collect.ImmutableMap;
95
96 /**
97  * This class provides an implementation of {@link HeatBridgeApi}
98  */
99 public class HeatBridgeImpl implements HeatBridgeApi {
100
101     private static final Logger logger = LoggerFactory.getLogger(HeatBridgeImpl.class);
102     private static final String ERR_MSG_NULL_OS_CLIENT =
103             "Initialization error: Null openstack client. Authenticate with Keystone first.";
104     private static final String OOB_MGT_NETWORK_IDENTIFIER = "Management";
105     private OpenstackClient osClient;
106     private AAIResourcesClient resourcesClient;
107     private AAISingleTransactionClient transaction;
108     private String cloudOwner;
109     private String cloudRegionId;
110     private String regionId;
111     private String tenantId;
112     private AaiHelper aaiHelper = new AaiHelper();
113     private CloudIdentity cloudIdentity;
114     private Environment env;
115
116
117     public HeatBridgeImpl(AAIResourcesClient resourcesClient, final CloudIdentity cloudIdentity,
118             @Nonnull final String cloudOwner, @Nonnull final String cloudRegionId, @Nonnull final String regionId,
119             @Nonnull final String tenantId) {
120         Objects.requireNonNull(cloudOwner, "Null cloud-owner value!");
121         Objects.requireNonNull(cloudRegionId, "Null cloud-region identifier!");
122         Objects.requireNonNull(tenantId, "Null tenant identifier!");
123         Objects.requireNonNull(regionId, "Null regionId identifier!");
124
125         this.cloudIdentity = cloudIdentity;
126         this.cloudOwner = cloudOwner;
127         this.cloudRegionId = cloudRegionId;
128         this.regionId = regionId;
129         this.tenantId = tenantId;
130         this.resourcesClient = resourcesClient;
131         if (resourcesClient != null)
132             this.transaction = resourcesClient.beginSingleTransaction();
133         if (SpringContextHelper.getAppContext() != null)
134             this.env = SpringContextHelper.getAppContext().getEnvironment();
135     }
136
137     public HeatBridgeImpl() {
138         this.resourcesClient = new AAIResourcesClient();
139         this.transaction = resourcesClient.beginSingleTransaction();
140     }
141
142     @Override
143     public OpenstackClient authenticate() throws HeatBridgeException {
144         String keystoneVersion = "";
145         if (ServerType.KEYSTONE.equals(cloudIdentity.getIdentityServerType()))
146             keystoneVersion = "v2.0";
147         else if (ServerType.KEYSTONE_V3.equals(cloudIdentity.getIdentityServerType())) {
148             keystoneVersion = "v3";
149         } else {
150             keystoneVersion = "UNKNOWN";
151         }
152         logger.trace("Keystone Version: {} ", keystoneVersion);
153         this.osClient = new MsoCloudClientFactoryImpl(new OpenstackClientFactoryImpl()).getOpenstackClient(
154                 cloudIdentity.getIdentityUrl(), cloudIdentity.getMsoId(), cloudIdentity.getMsoPass(), regionId,
155                 tenantId, keystoneVersion, cloudIdentity.getUserDomainName(), cloudIdentity.getProjectDomainName());
156         logger.trace("Successfully authenticated with keystone for tenant: {} and region: {}", tenantId, regionId);
157         return osClient;
158     }
159
160     @Override
161     public List<Resource> queryNestedHeatStackResources(final String heatStackId) {
162         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
163         Preconditions.checkState(!Strings.isNullOrEmpty(heatStackId), "Invalid heatStackId!");
164         List<Resource> stackBasedResources =
165                 osClient.getStackBasedResources(heatStackId, HeatBridgeConstants.OS_DEFAULT_HEAT_NESTING);
166         logger.debug(stackBasedResources.size() + " heat stack resources are extracted for stack: " + heatStackId);
167         return stackBasedResources;
168     }
169
170     @Override
171     public List<String> extractStackResourceIdsByResourceType(final List<Resource> stackResources,
172             final String resourceType) {
173         return stackResources.stream().filter(stackResource -> stackResource.getType().equals(resourceType))
174                 .map(Resource::getPhysicalResourceId).collect(Collectors.toList());
175     }
176
177     @Override
178     public List<String> extractNetworkIds(final List<String> networkNameList) {
179         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
180         return networkNameList.stream()
181                 .map(netName -> osClient
182                         .listNetworksByFilter(ImmutableMap.of(HeatBridgeConstants.OS_NAME_KEY, netName)))
183                 .filter(nets -> nets != null && nets.size() == 1) // extract network-id only if network-name is unique
184                 .map(nets -> nets.get(0).getId()).collect(Collectors.toList());
185     }
186
187     @Override
188     public List<Server> getAllOpenstackServers(final List<Resource> stackResources) {
189         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
190         // Filter Openstack Compute resources
191         List<String> serverIds =
192                 extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_SERVER_RESOURCE_TYPE);
193         return serverIds.stream().map(serverId -> osClient.getServerById(serverId)).collect(Collectors.toList());
194     }
195
196     @Override
197     public List<org.openstack4j.model.compute.Image> extractOpenstackImagesFromServers(final List<Server> servers) {
198         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
199         return servers.stream().map(Server::getImage)
200                 .filter(distinctByProperty(org.openstack4j.model.compute.Image::getId)).collect(Collectors.toList());
201     }
202
203     @Override
204     public List<org.openstack4j.model.compute.Flavor> extractOpenstackFlavorsFromServers(final List<Server> servers) {
205         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
206         return servers.stream().map(Server::getFlavor)
207                 .filter(distinctByProperty(org.openstack4j.model.compute.Flavor::getId)).collect(Collectors.toList());
208     }
209
210     @Override
211     public void buildAddImagesToAaiAction(final List<org.openstack4j.model.compute.Image> images)
212             throws HeatBridgeException {
213         for (org.openstack4j.model.compute.Image image : images) {
214             Image aaiImage = aaiHelper.buildImage(image);
215             try {
216                 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.IMAGE, cloudOwner, cloudRegionId,
217                         aaiImage.getImageId());
218                 if (!resourcesClient.exists(uri)) {
219                     transaction.create(uri, aaiImage);
220                     logger.debug("Queuing AAI command to add image: " + aaiImage.getImageId());
221                 } else {
222                     logger.debug("Nothing to add since image: " + aaiImage.getImageId() + "already exists in AAI.");
223                 }
224             } catch (WebApplicationException e) {
225                 throw new HeatBridgeException(
226                         "Failed to update image to AAI: " + aaiImage.getImageId() + ". Error" + " cause: " + e, e);
227             }
228         }
229     }
230
231     @Override
232     public void buildAddFlavorsToAaiAction(final List<org.openstack4j.model.compute.Flavor> flavors)
233             throws HeatBridgeException {
234         for (org.openstack4j.model.compute.Flavor flavor : flavors) {
235             Flavor aaiFlavor = aaiHelper.buildFlavor(flavor);
236             try {
237                 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.FLAVOR, cloudOwner, cloudRegionId,
238                         aaiFlavor.getFlavorId());
239                 transaction.createIfNotExists(uri, Optional.of(aaiFlavor));
240             } catch (WebApplicationException e) {
241                 throw new HeatBridgeException(
242                         "Failed to update flavor to AAI: " + aaiFlavor.getFlavorId() + ". Error" + " cause: " + e, e);
243             }
244         }
245     }
246
247     @Override
248     public void buildAddVserversToAaiAction(final String genericVnfId, final String vfModuleId,
249             final List<Server> servers) {
250         servers.forEach(server -> {
251             Vserver vserver = aaiHelper.buildVserver(server.getId(), server);
252
253             // Build vserver relationships to: image, flavor, pserver, vf-module
254             vserver.setRelationshipList(
255                     aaiHelper.getVserverRelationshipList(cloudOwner, cloudRegionId, genericVnfId, vfModuleId, server));
256             transaction.create(AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, cloudRegionId,
257                     tenantId, vserver.getVserverId()), vserver);
258         });
259     }
260
261     @Override
262     public void buildAddVserverLInterfacesToAaiAction(final List<Resource> stackResources,
263             final List<String> oobMgtNetIds, String cloudOwner) {
264         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
265         List<String> portIds =
266                 extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_PORT_RESOURCE_TYPE);
267         for (String portId : portIds) {
268             Port port = osClient.getPortById(portId);
269             LInterface lIf = new LInterface();
270             lIf.setInterfaceId(port.getId());
271             lIf.setInterfaceName(port.getName());
272             lIf.setMacaddr(port.getMacAddress());
273             if (port.getProfile() != null && port.getProfile().get("physical_network") != null) {
274                 lIf.setNetworkName((String) port.getProfile().get("physical_network"));
275             }
276             lIf.setIsPortMirrored(false);
277             lIf.setIsIpUnnumbered(false);
278             lIf.setInMaint(false);
279             if (oobMgtNetIds != null && oobMgtNetIds.contains(port.getNetworkId())) {
280                 lIf.setInterfaceRole(OOB_MGT_NETWORK_IDENTIFIER);
281             } else {
282                 lIf.setInterfaceRole(port.getvNicType());
283             }
284             boolean isL2Multicast = false;
285             if (port.getProfile().get("trusted") != null) {
286                 String trusted = port.getProfile().get("trusted").toString();
287                 if (Boolean.parseBoolean(trusted)) {
288                     isL2Multicast = true;
289                 }
290             }
291             lIf.setL2Multicasting(isL2Multicast);
292             updateLInterfaceIps(port, lIf);
293             if (cloudOwner.equals(env.getProperty("mso.cloudOwner.included", ""))) {
294                 updateLInterfaceVlan(port, lIf);
295             }
296
297             // Update l-interface to the vserver
298             transaction.create(AAIUriFactory.createResourceUri(AAIObjectType.L_INTERFACE, cloudOwner, cloudRegionId,
299                     tenantId, port.getDeviceId(), lIf.getInterfaceName()), lIf);
300         }
301     }
302
303     @Override
304     public void createPserversAndPinterfacesIfNotPresentInAai(final List<Resource> stackResources)
305             throws HeatBridgeException {
306         if (stackResources == null) {
307             return;
308         }
309         Map<String, Pserver> serverHostnames = getPserverMapping(stackResources);
310         createPServerIfNotExists(serverHostnames);
311         List<String> portIds =
312                 extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_PORT_RESOURCE_TYPE);
313         for (String portId : portIds) {
314             Port port = osClient.getPortById(portId);
315             if (port.getvNicType().equalsIgnoreCase(HeatBridgeConstants.OS_SRIOV_PORT_TYPE)) {
316                 createPServerPInterfaceIfNotExists(serverHostnames.get(port.getHostId()).getHostname(),
317                         aaiHelper.buildPInterface(port));
318             }
319         }
320     }
321
322     private Map<String, Pserver> getPserverMapping(final List<Resource> stackResources) {
323         List<Server> osServers = getAllOpenstackServers(stackResources);
324         Map<String, Pserver> pserverMap = new HashMap<>();
325         if (osServers != null) {
326             for (Server server : osServers) {
327                 Pserver pserver = aaiHelper.buildPserver(server);
328                 if (pserver != null) {
329                     pserverMap.put(server.getHost(), pserver);
330                 }
331             }
332         }
333         return pserverMap;
334     }
335
336     private void createPServerIfNotExists(Map<String, Pserver> serverHostnames) {
337         for (Pserver pserver : serverHostnames.values()) {
338             AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, pserver.getHostname());
339             resourcesClient.createIfNotExists(uri, Optional.of(pserver));
340         }
341     }
342
343     private void createPServerPInterfaceIfNotExists(String pserverHostname, PInterface pInterface) {
344         AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.P_INTERFACE, pserverHostname,
345                 pInterface.getInterfaceName());
346         resourcesClient.createIfNotExists(uri, Optional.of(pInterface));
347     }
348
349     private void updateLInterfaceVlan(final Port port, final LInterface lIf) {
350         Vlan vlan = new Vlan();
351         Network network = osClient.getNetworkById(port.getNetworkId());
352         if (network.getNetworkType() != null && network.getNetworkType().equals(NetworkType.VLAN)) {
353             vlan.setVlanInterface(network.getName() + network.getProviderSegID());
354
355             vlan.setVlanIdOuter(Long.parseLong(network.getProviderSegID()));
356             vlan.setVlanIdInner(0L);
357             vlan.setInMaint(false);
358             vlan.setIsIpUnnumbered(false);
359             vlan.setIsPrivate(false);
360             Vlans vlans = new Vlans();
361             List<Vlan> vlanList = vlans.getVlan();
362             vlanList.add(vlan);
363             lIf.setVlans(vlans);
364         }
365         // Build sriov-vf to the l-interface
366         if (port.getvNicType() != null && port.getvNicType().equalsIgnoreCase(HeatBridgeConstants.OS_SRIOV_PORT_TYPE)) {
367             SriovVfs sriovVfs = new SriovVfs();
368             // JAXB does not generate setters for list, however getter ensures its creation.
369             // Thus, all list manipulations must be made on live list.
370             List<SriovVf> sriovVfList = sriovVfs.getSriovVf();
371             SriovVf sriovVf = new SriovVf();
372             sriovVf.setPciId(port.getProfile().get(HeatBridgeConstants.OS_PCI_SLOT_KEY).toString());
373             sriovVf.setNeutronNetworkId(port.getNetworkId());
374             if (port.getVifDetails() != null) {
375                 sriovVf.setVfVlanFilter((String) port.getVifDetails().get(HeatBridgeConstants.OS_VLAN_NETWORK_KEY));
376             }
377             sriovVf.setVfVlanAntiSpoofCheck(false);
378             sriovVf.setVfMacAntiSpoofCheck(false);
379             sriovVfList.add(sriovVf);
380
381             lIf.setSriovVfs(sriovVfs);
382
383             // For the given port create sriov-pf for host pserver/p-interface if absent
384             updateSriovPfToPserver(port, lIf);
385         }
386     }
387
388     /**
389      * Needs to be corrected according to the specification that is in draft If pserver/p-interface does not have a
390      * SRIOV-PF object matching the PCI-ID of the Openstack port object, then create it in AAI. Openstack SRIOV Port
391      * object has pci-id (to match sriov-pf on pserver/p-interface), physical-network ID (that matches the p-interface
392      * name).
393      *
394      * @param port Openstack port object
395      * @param lIf AAI l-interface object
396      */
397     private void updateSriovPfToPserver(final Port port, final LInterface lIf) {
398         if (port.getProfile() == null || Strings
399                 .isNullOrEmpty(port.getProfile().get(HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY).toString())) {
400             logger.debug("The SRIOV port:" + port.getName() + " is missing physical-network-id, cannot update "
401                     + "sriov-pf object for host pserver: " + port.getHostId());
402             return;
403         }
404         Optional<String> matchingPifName = HeatBridgeUtils.getMatchingPserverPifName(
405                 port.getProfile().get(HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY).toString());
406         if (matchingPifName.isPresent()) {
407             // Update l-interface description
408             String pserverHostName = port.getHostId();
409             lIf.setInterfaceDescription("Attached to SR-IOV port: " + pserverHostName + "::" + matchingPifName.get());
410             try {
411                 Optional<PInterface> matchingPIf = resourcesClient.get(PInterface.class,
412                         AAIUriFactory
413                                 .createResourceUri(AAIObjectType.P_INTERFACE, pserverHostName, matchingPifName.get())
414                                 .depth(Depth.ONE));
415                 if (matchingPIf.isPresent()) {
416                     SriovPfs pIfSriovPfs = matchingPIf.get().getSriovPfs();
417                     if (pIfSriovPfs == null) {
418                         pIfSriovPfs = new SriovPfs();
419                     }
420                     // Extract PCI-ID from OS port object
421                     String pfPciId = port.getProfile().get(HeatBridgeConstants.OS_PCI_SLOT_KEY).toString();
422
423                     List<SriovPf> existingSriovPfs = pIfSriovPfs.getSriovPf();
424                     if (CollectionUtils.isEmpty(existingSriovPfs) || existingSriovPfs.stream()
425                             .noneMatch(existingSriovPf -> existingSriovPf.getPfPciId().equals(pfPciId))) {
426                         // Add sriov-pf object with PCI-ID to AAI
427                         SriovPf sriovPf = new SriovPf();
428                         sriovPf.setPfPciId(pfPciId);
429                         logger.debug("Queuing AAI command to update sriov-pf object to pserver: " + pserverHostName
430                                 + "/" + matchingPifName.get());
431                         transaction.create(AAIUriFactory.createResourceUri(AAIObjectType.SRIOV_PF, pserverHostName,
432                                 matchingPifName.get(), sriovPf.getPfPciId()), sriovPf);
433                     }
434                 }
435             } catch (WebApplicationException e) {
436                 // Silently log that we failed to update the Pserver p-interface with PCI-ID
437                 logger.error(LoggingAnchor.NINE, MessageEnum.GENERAL_EXCEPTION, pserverHostName, matchingPifName.get(),
438                         cloudOwner, tenantId, "OpenStack", "Heatbridge", ErrorCode.DataError.getValue(),
439                         "Exception - Failed to add sriov-pf object to pserver", e);
440             }
441         }
442     }
443
444     private void updateLInterfaceIps(final Port port, final LInterface lIf) {
445         List<L3InterfaceIpv4AddressList> lInterfaceIps = lIf.getL3InterfaceIpv4AddressList();
446         for (IP ip : port.getFixedIps()) {
447             String ipAddress = ip.getIpAddress();
448             if (InetAddressValidator.getInstance().isValidInet4Address(ipAddress)) {
449                 L3InterfaceIpv4AddressList lInterfaceIp = new L3InterfaceIpv4AddressList();
450                 lInterfaceIp.setL3InterfaceIpv4Address(ipAddress);
451                 lInterfaceIp.setNeutronNetworkId(port.getNetworkId());
452                 lInterfaceIp.setNeutronSubnetId(ip.getSubnetId());
453                 lInterfaceIp.setL3InterfaceIpv4PrefixLength(32L);
454                 lInterfaceIps.add(lInterfaceIp);
455             }
456         }
457     }
458
459     @Override
460     public void submitToAai(boolean dryrun) throws HeatBridgeException {
461         try {
462             transaction.execute(dryrun);
463         } catch (BulkProcessFailed e) {
464             String msg = "Failed to commit transaction";
465             logger.debug(msg + " with error: " + e);
466             throw new HeatBridgeException(msg, e);
467         }
468     }
469
470     @Override
471     public void deleteVfModuleData(@Nonnull final String vnfId, @Nonnull final String vfModuleId)
472             throws HeatBridgeException {
473         Objects.requireNonNull(vnfId, "Null vnf-id!");
474         Objects.requireNonNull(vfModuleId, "Null vf-module-id!");
475         try {
476             Optional<VfModule> vfModule = resourcesClient.get(VfModule.class,
477                     AAIUriFactory.createResourceUri(AAIObjectType.VF_MODULE, vnfId, vfModuleId).depth(Depth.ONE));
478             logger.debug("vfModule is present: {}", vfModule.isPresent());
479             if (vfModule.isPresent()) {
480
481                 AAIResultWrapper resultWrapper = new AAIResultWrapper(vfModule.get());
482                 Optional<Relationships> relationships = resultWrapper.getRelationships();
483                 logger.debug("relationships is present: {}", relationships.isPresent());
484                 if (relationships.isPresent()) {
485                     List<AAIResourceUri> vserverUris = relationships.get().getRelatedUris(AAIObjectType.VSERVER);
486                     logger.debug("vserverList isEmpty: {}", vserverUris.isEmpty());
487                     createTransactionToDeleteSriovPfFromPserver(vserverUris);
488
489                     if (!vserverUris.isEmpty()) {
490                         for (AAIResourceUri vserverUri : vserverUris) {
491                             logger.debug("Deleting Vservers: {}", vserverUri.toString());
492                             resourcesClient.delete(vserverUri);
493                         }
494                     }
495                 }
496             }
497         } catch (Exception e) {
498             String msg = "Failed to commit delete heatbridge data transaction";
499             logger.debug(msg + " with error: " + e);
500             throw new HeatBridgeException(msg, e);
501         }
502     }
503
504     private void createTransactionToDeleteSriovPfFromPserver(List<AAIResourceUri> vserverUris) {
505         Map<String, List<String>> pserverToPciIdMap = getPserverToPciIdMap(vserverUris);
506         for (Map.Entry<String, List<String>> entry : pserverToPciIdMap.entrySet()) {
507             String pserverName = entry.getKey();
508             List<String> pciIds = entry.getValue();
509             Optional<Pserver> pserver = resourcesClient.get(Pserver.class,
510                     AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, pserverName).depth(Depth.TWO));
511             if (pserver.isPresent()) {
512                 // For each pserver/p-interface match sriov-vfs by pic-id and delete them.
513                 pserver.get().getPInterfaces().getPInterface().stream().filter(
514                         pIf -> pIf.getSriovPfs() != null && CollectionUtils.isNotEmpty(pIf.getSriovPfs().getSriovPf()))
515                         .forEach(pIf -> pIf.getSriovPfs().getSriovPf().forEach(sriovPf -> {
516                             if (pciIds.contains(sriovPf.getPfPciId())) {
517                                 logger.debug("creating transaction to delete SR-IOV PF: " + pIf.getInterfaceName()
518                                         + " from PServer: " + pserverName);
519                                 resourcesClient.delete(AAIUriFactory.createResourceUri(AAIObjectType.SRIOV_PF,
520                                         pserverName, pIf.getInterfaceName(), sriovPf.getPfPciId()));
521                             }
522                         }));
523             }
524         }
525     }
526
527     private Map<String, List<String>> getPserverToPciIdMap(List<AAIResourceUri> vserverUris) {
528         Map<String, List<String>> pserverToPciIdMap = new HashMap<>();
529         for (AAIResourceUri vserverUri : vserverUris) {
530             AAIResultWrapper vserverWrapper = resourcesClient.get(vserverUri.depth(Depth.TWO));
531             Optional<Relationships> vserverRelationships = vserverWrapper.getRelationships();
532             if (vserverRelationships.isPresent()
533                     && CollectionUtils.isNotEmpty(vserverRelationships.get().getRelatedLinks(AAIObjectType.PSERVER))) {
534                 Vserver vserver = vserverWrapper.asBean(Vserver.class).get();
535                 List<String> pciIds = HeatBridgeUtils.extractPciIdsFromVServer(vserver);
536                 if (CollectionUtils.isNotEmpty(pciIds)) {
537                     List<String> matchingPservers = vserverRelationships.get().getRelatedLinks(AAIObjectType.PSERVER);
538                     if (matchingPservers != null && matchingPservers.size() == 1) {
539                         pserverToPciIdMap.put(matchingPservers.get(0), pciIds);
540                     }
541                 }
542             }
543         }
544         return pserverToPciIdMap;
545     }
546
547     private <T> Predicate<T> distinctByProperty(Function<? super T, Object> keyExtractor) {
548         Map<Object, Boolean> map = new ConcurrentHashMap<>();
549         return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
550     }
551 }