Merge "Get id from conductor for auto and speed change"
[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.NotFoundException;
46 import javax.ws.rs.WebApplicationException;
47 import org.apache.commons.collections.CollectionUtils;
48 import org.apache.commons.validator.routines.InetAddressValidator;
49 import org.onap.aai.domain.yang.Flavor;
50 import org.onap.aai.domain.yang.Image;
51 import org.onap.aai.domain.yang.L3InterfaceIpv4AddressList;
52 import org.onap.aai.domain.yang.L3InterfaceIpv6AddressList;
53 import org.onap.aai.domain.yang.L3Network;
54 import org.onap.aai.domain.yang.LInterface;
55 import org.onap.aai.domain.yang.PInterface;
56 import org.onap.aai.domain.yang.Pserver;
57 import org.onap.aai.domain.yang.Relationship;
58 import org.onap.aai.domain.yang.RelationshipList;
59 import org.onap.aai.domain.yang.SriovPf;
60 import org.onap.aai.domain.yang.SriovPfs;
61 import org.onap.aai.domain.yang.Subnets;
62 import org.onap.aai.domain.yang.SriovVf;
63 import org.onap.aai.domain.yang.SriovVfs;
64 import org.onap.aai.domain.yang.VfModule;
65 import org.onap.aai.domain.yang.Vlan;
66 import org.onap.aai.domain.yang.Vlans;
67 import org.onap.aai.domain.yang.Vserver;
68 import org.onap.aaiclient.client.aai.AAIObjectType;
69 import org.onap.aaiclient.client.aai.AAIResourcesClient;
70 import org.onap.aaiclient.client.aai.AAISingleTransactionClient;
71 import org.onap.aaiclient.client.aai.entities.AAIResultWrapper;
72 import org.onap.aaiclient.client.aai.entities.Relationships;
73 import org.onap.aaiclient.client.aai.entities.uri.AAIResourceUri;
74 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory;
75 import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder;
76 import org.onap.aaiclient.client.graphinventory.entities.uri.Depth;
77 import org.onap.aaiclient.client.graphinventory.exceptions.BulkProcessFailed;
78 import org.onap.logging.filter.base.ErrorCode;
79 import org.onap.so.db.catalog.beans.CloudIdentity;
80 import org.onap.so.db.catalog.beans.ServerType;
81 import org.onap.so.heatbridge.constants.HeatBridgeConstants;
82 import org.onap.so.heatbridge.factory.MsoCloudClientFactoryImpl;
83 import org.onap.so.heatbridge.helpers.AaiHelper;
84 import org.onap.so.heatbridge.openstack.api.OpenstackClient;
85 import org.onap.so.heatbridge.openstack.factory.OpenstackClientFactoryImpl;
86 import org.onap.so.heatbridge.utils.HeatBridgeUtils;
87 import org.onap.so.logger.LoggingAnchor;
88 import org.onap.so.logger.MessageEnum;
89 import org.onap.so.spring.SpringContextHelper;
90 import org.openstack4j.model.compute.Server;
91 import org.openstack4j.model.heat.Resource;
92 import org.openstack4j.model.network.IP;
93 import org.openstack4j.model.network.Network;
94 import org.openstack4j.model.network.NetworkType;
95 import org.openstack4j.model.network.Port;
96 import org.openstack4j.model.network.Subnet;
97 import org.slf4j.Logger;
98 import org.slf4j.LoggerFactory;
99 import org.springframework.core.env.Environment;
100 import com.google.common.base.Preconditions;
101 import com.google.common.base.Strings;
102 import com.google.common.collect.ImmutableMap;
103 import inet.ipaddr.IPAddressString;
104
105 /**
106  * This class provides an implementation of {@link HeatBridgeApi}
107  */
108 public class HeatBridgeImpl implements HeatBridgeApi {
109
110     private static final Logger logger = LoggerFactory.getLogger(HeatBridgeImpl.class);
111     private static final String ERR_MSG_NULL_OS_CLIENT =
112             "Initialization error: Null openstack client. Authenticate with Keystone first.";
113     private static final String OOB_MGT_NETWORK_IDENTIFIER = "Management";
114     private OpenstackClient osClient;
115     private AAIResourcesClient resourcesClient;
116     private AAISingleTransactionClient transaction;
117     private String cloudOwner;
118     private String cloudRegionId;
119     private String regionId;
120     private String tenantId;
121     private AaiHelper aaiHelper = new AaiHelper();
122     private CloudIdentity cloudIdentity;
123     private Environment env;
124
125
126     public HeatBridgeImpl(AAIResourcesClient resourcesClient, final CloudIdentity cloudIdentity,
127             @Nonnull final String cloudOwner, @Nonnull final String cloudRegionId, @Nonnull final String regionId,
128             @Nonnull final String tenantId) {
129         Objects.requireNonNull(cloudOwner, "Null cloud-owner value!");
130         Objects.requireNonNull(cloudRegionId, "Null cloud-region identifier!");
131         Objects.requireNonNull(tenantId, "Null tenant identifier!");
132         Objects.requireNonNull(regionId, "Null regionId identifier!");
133
134         this.cloudIdentity = cloudIdentity;
135         this.cloudOwner = cloudOwner;
136         this.cloudRegionId = cloudRegionId;
137         this.regionId = regionId;
138         this.tenantId = tenantId;
139         this.resourcesClient = resourcesClient;
140         if (resourcesClient != null)
141             this.transaction = resourcesClient.beginSingleTransaction();
142         if (SpringContextHelper.getAppContext() != null)
143             this.env = SpringContextHelper.getAppContext().getEnvironment();
144     }
145
146     public HeatBridgeImpl() {
147         this.resourcesClient = new AAIResourcesClient();
148         this.transaction = resourcesClient.beginSingleTransaction();
149     }
150
151     @Override
152     public OpenstackClient authenticate() throws HeatBridgeException {
153         String keystoneVersion = "";
154         if (ServerType.KEYSTONE.equals(cloudIdentity.getIdentityServerType()))
155             keystoneVersion = "v2.0";
156         else if (ServerType.KEYSTONE_V3.equals(cloudIdentity.getIdentityServerType())) {
157             keystoneVersion = "v3";
158         } else {
159             keystoneVersion = "UNKNOWN";
160         }
161         logger.trace("Keystone Version: {} ", keystoneVersion);
162         this.osClient = new MsoCloudClientFactoryImpl(new OpenstackClientFactoryImpl()).getOpenstackClient(
163                 cloudIdentity.getIdentityUrl(), cloudIdentity.getMsoId(), cloudIdentity.getMsoPass(), regionId,
164                 tenantId, keystoneVersion, cloudIdentity.getUserDomainName(), cloudIdentity.getProjectDomainName());
165         logger.trace("Successfully authenticated with keystone for tenant: {} and region: {}", tenantId, regionId);
166         return osClient;
167     }
168
169     @Override
170     public List<Resource> queryNestedHeatStackResources(final String heatStackId) {
171         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
172         Preconditions.checkState(!Strings.isNullOrEmpty(heatStackId), "Invalid heatStackId!");
173         List<Resource> stackBasedResources =
174                 osClient.getStackBasedResources(heatStackId, HeatBridgeConstants.OS_DEFAULT_HEAT_NESTING);
175         logger.debug(stackBasedResources.size() + " heat stack resources are extracted for stack: " + heatStackId);
176         return stackBasedResources;
177     }
178
179     @Override
180     public List<String> extractStackResourceIdsByResourceType(final List<Resource> stackResources,
181             final String resourceType) {
182         return stackResources.stream().filter(stackResource -> stackResource.getType().equals(resourceType))
183                 .map(Resource::getPhysicalResourceId).collect(Collectors.toList());
184     }
185
186     @Override
187     public List<String> extractNetworkIds(final List<String> networkNameList) {
188         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
189         return networkNameList.stream()
190                 .map(netName -> osClient
191                         .listNetworksByFilter(ImmutableMap.of(HeatBridgeConstants.OS_NAME_KEY, netName)))
192                 .filter(nets -> nets != null && nets.size() == 1) // extract network-id only if network-name is unique
193                 .map(nets -> nets.get(0).getId()).collect(Collectors.toList());
194     }
195
196     @Override
197     public List<Server> getAllOpenstackServers(final List<Resource> stackResources) {
198         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
199         // Filter Openstack Compute resources
200         List<String> serverIds =
201                 extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_SERVER_RESOURCE_TYPE);
202         return serverIds.stream().map(serverId -> osClient.getServerById(serverId)).collect(Collectors.toList());
203     }
204
205     @Override
206     public List<Network> getAllOpenstackProviderNetworks(final List<Resource> stackResources) {
207         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
208         // Filter Openstack Compute resources
209         List<String> providerNetworkIds =
210                 extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_NEUTRON_PROVIDERNET);
211         return providerNetworkIds.stream().map(providerNetworkId -> osClient.getNetworkById(providerNetworkId))
212                 .collect(Collectors.toList());
213     }
214
215     @Override
216     public List<org.openstack4j.model.compute.Image> extractOpenstackImagesFromServers(final List<Server> servers) {
217         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
218         return servers.stream().map(Server::getImage)
219                 .filter(distinctByProperty(org.openstack4j.model.compute.Image::getId)).collect(Collectors.toList());
220     }
221
222     @Override
223     public List<org.openstack4j.model.compute.Flavor> extractOpenstackFlavorsFromServers(final List<Server> servers) {
224         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
225         return servers.stream().map(Server::getFlavor)
226                 .filter(distinctByProperty(org.openstack4j.model.compute.Flavor::getId)).collect(Collectors.toList());
227     }
228
229     public void buildAddNetworksToAaiAction(final String genericVnfId, final String vfModuleId,
230             List<Network> networks) {
231         networks.forEach(network -> {
232             L3Network l3Network = aaiHelper.buildNetwork(network);
233             if (l3Network != null) {
234                 l3Network.setSubnets(buildSunets(network));
235
236                 RelationshipList relationshipList = new RelationshipList();
237                 List<Relationship> relationships = relationshipList.getRelationship();
238
239                 relationships.add(aaiHelper.getRelationshipToVfModule(genericVnfId, vfModuleId));
240                 relationships.add(aaiHelper.getRelationshipToTenant(cloudOwner, cloudRegionId, tenantId));
241
242                 l3Network.setRelationshipList(relationshipList);
243                 transaction.createIfNotExists(
244                         AAIUriFactory.createResourceUri(AAIObjectType.L3_NETWORK, l3Network.getNetworkId()),
245                         Optional.of(l3Network));
246             }
247         });
248     }
249
250     @Override
251     public void buildAddImagesToAaiAction(final List<org.openstack4j.model.compute.Image> images)
252             throws HeatBridgeException {
253         for (org.openstack4j.model.compute.Image image : images) {
254             Image aaiImage = aaiHelper.buildImage(image);
255             try {
256                 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.IMAGE, cloudOwner, cloudRegionId,
257                         aaiImage.getImageId());
258                 if (!resourcesClient.exists(uri)) {
259                     transaction.create(uri, aaiImage);
260                     logger.debug("Queuing AAI command to add image: " + aaiImage.getImageId());
261                 } else {
262                     logger.debug("Nothing to add since image: " + aaiImage.getImageId() + "already exists in AAI.");
263                 }
264             } catch (WebApplicationException e) {
265                 throw new HeatBridgeException(
266                         "Failed to update image to AAI: " + aaiImage.getImageId() + ". Error" + " cause: " + e, e);
267             }
268         }
269     }
270
271     @Override
272     public void buildAddFlavorsToAaiAction(final List<org.openstack4j.model.compute.Flavor> flavors)
273             throws HeatBridgeException {
274         for (org.openstack4j.model.compute.Flavor flavor : flavors) {
275             Flavor aaiFlavor = aaiHelper.buildFlavor(flavor);
276             try {
277                 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.FLAVOR, cloudOwner, cloudRegionId,
278                         aaiFlavor.getFlavorId());
279                 transaction.createIfNotExists(uri, Optional.of(aaiFlavor));
280             } catch (WebApplicationException e) {
281                 throw new HeatBridgeException(
282                         "Failed to update flavor to AAI: " + aaiFlavor.getFlavorId() + ". Error" + " cause: " + e, e);
283             }
284         }
285     }
286
287     @Override
288     public void buildAddVserversToAaiAction(final String genericVnfId, final String vfModuleId,
289             final List<Server> servers) {
290         servers.forEach(server -> {
291             Vserver vserver = aaiHelper.buildVserver(server.getId(), server);
292
293             // Build vserver relationships to: image, flavor, pserver, vf-module
294             vserver.setRelationshipList(
295                     aaiHelper.getVserverRelationshipList(cloudOwner, cloudRegionId, genericVnfId, vfModuleId, server));
296             transaction.createIfNotExists(AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner,
297                     cloudRegionId, tenantId, vserver.getVserverId()), Optional.of(vserver));
298         });
299     }
300
301     @Override
302     public void buildAddVserverLInterfacesToAaiAction(final List<Resource> stackResources,
303             final List<String> oobMgtNetIds, String cloudOwner) {
304         Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
305         List<String> portIds =
306                 extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_PORT_RESOURCE_TYPE);
307         if (portIds == null)
308             return;
309         for (String portId : portIds) {
310             Port port = osClient.getPortById(portId);
311             Network network = osClient.getNetworkById(port.getNetworkId());
312             LInterface lIf = new LInterface();
313             lIf.setInterfaceId(port.getId());
314             lIf.setInterfaceName(port.getName());
315             lIf.setMacaddr(port.getMacAddress());
316             lIf.setNetworkName(network.getName());
317             lIf.setIsPortMirrored(false);
318             lIf.setIsIpUnnumbered(false);
319             lIf.setInMaint(false);
320             if (oobMgtNetIds != null && oobMgtNetIds.contains(port.getNetworkId())) {
321                 lIf.setInterfaceRole(OOB_MGT_NETWORK_IDENTIFIER);
322             } else {
323                 lIf.setInterfaceRole(port.getvNicType());
324             }
325             boolean isL2Multicast = false;
326             if (port.getProfile() != null && port.getProfile().get("trusted") != null) {
327                 String trusted = port.getProfile().get("trusted").toString();
328                 if (Boolean.parseBoolean(trusted)) {
329                     isL2Multicast = true;
330                 }
331             }
332             lIf.setL2Multicasting(isL2Multicast);
333
334             transaction.createIfNotExists(AAIUriFactory.createResourceUri(AAIObjectType.L_INTERFACE, cloudOwner,
335                     cloudRegionId, tenantId, port.getDeviceId(), lIf.getInterfaceName()), Optional.of(lIf));
336
337             updateLInterfaceIps(port, lIf);
338             if (cloudOwner.equals(env.getProperty("mso.cloudOwner.included", ""))) {
339                 updateLInterfaceVlan(port, lIf);
340             }
341
342             updateSriovPfToPserver(port, lIf);
343         }
344     }
345
346     @Override
347     public void createPserversAndPinterfacesIfNotPresentInAai(final List<Resource> stackResources)
348             throws HeatBridgeException {
349         if (stackResources == null) {
350             return;
351         }
352         Map<String, Pserver> serverHostnames = getPserverMapping(stackResources);
353         createPServerIfNotExists(serverHostnames);
354         List<String> portIds =
355                 extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_PORT_RESOURCE_TYPE);
356         for (String portId : portIds) {
357             Port port = osClient.getPortById(portId);
358             if (port.getvNicType().equalsIgnoreCase(HeatBridgeConstants.OS_SRIOV_PORT_TYPE)) {
359                 createPServerPInterfaceIfNotExists(serverHostnames.get(port.getHostId()).getHostname(),
360                         aaiHelper.buildPInterface(port));
361             }
362         }
363     }
364
365     private Map<String, Pserver> getPserverMapping(final List<Resource> stackResources) {
366         List<Server> osServers = getAllOpenstackServers(stackResources);
367         Map<String, Pserver> pserverMap = new HashMap<>();
368         if (osServers != null) {
369             for (Server server : osServers) {
370                 Pserver pserver = aaiHelper.buildPserver(server);
371                 if (pserver != null) {
372                     pserverMap.put(server.getHost(), pserver);
373                 }
374             }
375         }
376         return pserverMap;
377     }
378
379     private Subnets buildSunets(Network network) {
380         Subnets aaiSubnets = new Subnets();
381         List<String> subnetIds = network.getSubnets();
382
383         subnetIds.forEach(subnetId -> {
384             Subnet subnet = osClient.getSubnetById(subnetId);
385             org.onap.aai.domain.yang.Subnet aaiSubnet = aaiHelper.buildSubnet(subnet);
386             if (aaiSubnet != null) {
387                 aaiSubnets.getSubnet().add(aaiSubnet);
388             }
389         });
390         return aaiSubnets;
391     }
392
393     private void createPServerIfNotExists(Map<String, Pserver> serverHostnames) {
394         for (Pserver pserver : serverHostnames.values()) {
395             AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, pserver.getHostname());
396             resourcesClient.createIfNotExists(uri, Optional.of(pserver));
397         }
398     }
399
400     private void createPServerPInterfaceIfNotExists(String pserverHostname, PInterface pInterface) {
401         AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.P_INTERFACE, pserverHostname,
402                 pInterface.getInterfaceName());
403         resourcesClient.createIfNotExists(uri, Optional.of(pInterface));
404     }
405
406     private void updateLInterfaceVlan(final Port port, final LInterface lIf) {
407         Vlan vlan = new Vlan();
408         Network network = osClient.getNetworkById(port.getNetworkId());
409         if (network.getNetworkType() != null && network.getNetworkType().equals(NetworkType.VLAN)) {
410             vlan.setVlanInterface(port.getName() + network.getProviderSegID());
411             vlan.setVlanIdOuter(Long.parseLong(network.getProviderSegID()));
412             vlan.setVlanIdInner(0L);
413             vlan.setInMaint(false);
414             vlan.setIsIpUnnumbered(false);
415             vlan.setIsPrivate(false);
416
417             transaction
418                     .createIfNotExists(
419                             AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure()
420                                     .cloudRegion(cloudOwner, cloudRegionId).tenant(tenantId).vserver(port.getDeviceId())
421                                     .lInterface(lIf.getInterfaceName()).vlan(vlan.getVlanInterface())),
422                             Optional.of(vlan));
423         }
424
425         if (port.getvNicType() != null && port.getvNicType().equalsIgnoreCase(HeatBridgeConstants.OS_SRIOV_PORT_TYPE)) {
426             SriovVf sriovVf = new SriovVf();
427             sriovVf.setPciId(port.getProfile().get(HeatBridgeConstants.OS_PCI_SLOT_KEY).toString());
428             sriovVf.setNeutronNetworkId(port.getNetworkId());
429             sriovVf.setVfVlanFilter("0");
430             sriovVf.setVfVlanAntiSpoofCheck(false);
431             sriovVf.setVfMacAntiSpoofCheck(false);
432
433             transaction
434                     .createIfNotExists(
435                             AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure()
436                                     .cloudRegion(cloudOwner, cloudRegionId).tenant(tenantId).vserver(port.getDeviceId())
437                                     .lInterface(lIf.getInterfaceName()).sriovVf(sriovVf.getPciId())),
438                             Optional.of(sriovVf));
439         }
440     }
441
442     /**
443      * Needs to be corrected according to the specification that is in draft If pserver/p-interface does not have a
444      * SRIOV-PF object matching the PCI-ID of the Openstack port object, then create it in AAI. Openstack SRIOV Port
445      * object has pci-id (to match sriov-pf on pserver/p-interface), physical-network ID (that matches the p-interface
446      * name).
447      *
448      * @param port Openstack port object
449      * @param lIf AAI l-interface object
450      */
451     private void updateSriovPfToPserver(final Port port, final LInterface lIf) {
452         if (port.getvNicType().equalsIgnoreCase(HeatBridgeConstants.OS_SRIOV_PORT_TYPE)) {
453             if (port.getProfile() == null || Strings
454                     .isNullOrEmpty(port.getProfile().get(HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY).toString())) {
455                 logger.debug("The SRIOV port:" + port.getName() + " is missing physical-network-id, cannot update "
456                         + "sriov-pf object for host pserver: " + port.getHostId());
457                 return;
458             }
459             Optional<String> matchingPifName = HeatBridgeUtils.getMatchingPserverPifName(
460                     port.getProfile().get(HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY).toString());
461             if (matchingPifName.isPresent()) {
462                 // Update l-interface description
463                 String pserverHostName = port.getHostId();
464                 lIf.setInterfaceDescription(
465                         "Attached to SR-IOV port: " + pserverHostName + "::" + matchingPifName.get());
466                 try {
467                     Optional<PInterface> matchingPIf = resourcesClient.get(PInterface.class, AAIUriFactory
468                             .createResourceUri(AAIObjectType.P_INTERFACE, pserverHostName, matchingPifName.get())
469                             .depth(Depth.ONE));
470                     if (matchingPIf.isPresent()) {
471                         SriovPfs pIfSriovPfs = matchingPIf.get().getSriovPfs();
472                         if (pIfSriovPfs == null) {
473                             pIfSriovPfs = new SriovPfs();
474                         }
475                         // Extract PCI-ID from OS port object
476                         String pfPciId = port.getProfile().get(HeatBridgeConstants.OS_PCI_SLOT_KEY).toString();
477
478                         List<SriovPf> existingSriovPfs = pIfSriovPfs.getSriovPf();
479                         if (CollectionUtils.isEmpty(existingSriovPfs) || existingSriovPfs.stream()
480                                 .noneMatch(existingSriovPf -> existingSriovPf.getPfPciId().equals(pfPciId))) {
481                             // Add sriov-pf object with PCI-ID to AAI
482                             SriovPf sriovPf = new SriovPf();
483                             sriovPf.setPfPciId(pfPciId);
484                             logger.debug("Queuing AAI command to update sriov-pf object to pserver: " + pserverHostName
485                                     + "/" + matchingPifName.get());
486
487                             AAIResourceUri sriovPfUri = AAIUriFactory.createResourceUri(AAIObjectType.SRIOV_PF,
488                                     pserverHostName, matchingPifName.get(), sriovPf.getPfPciId());
489
490                             if (!resourcesClient.exists(sriovPfUri)) {
491                                 transaction.create(sriovPfUri, sriovPf);
492
493                                 AAIResourceUri sriovVfUri = AAIUriFactory.createResourceUri(AAIObjectType.SRIOV_VF,
494                                         cloudOwner, cloudRegionId, tenantId, port.getDeviceId(), lIf.getInterfaceName(),
495                                         port.getProfile().get(HeatBridgeConstants.OS_PCI_SLOT_KEY).toString());
496
497                                 transaction.connect(sriovPfUri, sriovVfUri);
498                             }
499                         }
500                     }
501                 } catch (WebApplicationException e) {
502                     // Silently log that we failed to update the Pserver p-interface with PCI-ID
503                     logger.error(LoggingAnchor.NINE, MessageEnum.GENERAL_EXCEPTION, pserverHostName,
504                             matchingPifName.get(), cloudOwner, tenantId, "OpenStack", "Heatbridge",
505                             ErrorCode.DataError.getValue(), "Exception - Failed to add sriov-pf object to pserver", e);
506                 }
507             }
508         }
509     }
510
511     private void updateLInterfaceIps(final Port port, final LInterface lIf) {
512         for (IP ip : port.getFixedIps()) {
513             String ipAddress = ip.getIpAddress();
514             if (InetAddressValidator.getInstance().isValidInet4Address(ipAddress)) {
515                 Subnet subnet = osClient.getSubnetById(ip.getSubnetId());
516                 IPAddressString cidr = new IPAddressString(subnet.getCidr());
517                 L3InterfaceIpv4AddressList lInterfaceIp = new L3InterfaceIpv4AddressList();
518                 lInterfaceIp.setL3InterfaceIpv4Address(ipAddress);
519                 lInterfaceIp.setNeutronNetworkId(port.getNetworkId());
520                 lInterfaceIp.setNeutronSubnetId(ip.getSubnetId());
521                 lInterfaceIp.setL3InterfaceIpv4PrefixLength(Long.parseLong(cidr.getNetworkPrefixLength().toString()));
522
523                 transaction.createIfNotExists(
524                         AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure()
525                                 .cloudRegion(cloudOwner, cloudRegionId).tenant(tenantId).vserver(port.getDeviceId())
526                                 .lInterface(lIf.getInterfaceName()).l3InterfaceIpv4AddressList(ipAddress)),
527                         Optional.of(lInterfaceIp));
528             } else if (InetAddressValidator.getInstance().isValidInet6Address(ipAddress)) {
529                 Subnet subnet = osClient.getSubnetById(ip.getSubnetId());
530                 IPAddressString cidr = new IPAddressString(subnet.getCidr());
531                 L3InterfaceIpv6AddressList ipv6 = new L3InterfaceIpv6AddressList();
532                 ipv6.setL3InterfaceIpv6Address(ipAddress);
533                 ipv6.setNeutronNetworkId(port.getNetworkId());
534                 ipv6.setNeutronSubnetId(ip.getSubnetId());
535                 ipv6.setL3InterfaceIpv6PrefixLength(Long.parseLong(cidr.getNetworkPrefixLength().toString()));
536
537                 transaction.createIfNotExists(
538                         AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure()
539                                 .cloudRegion(cloudOwner, cloudRegionId).tenant(tenantId).vserver(port.getDeviceId())
540                                 .lInterface(lIf.getInterfaceName()).l3InterfaceIpv6AddressList(ipAddress)),
541                         Optional.of(ipv6));
542             }
543         }
544     }
545
546     @Override
547     public void submitToAai(boolean dryrun) throws HeatBridgeException {
548         try {
549             transaction.execute(dryrun);
550         } catch (BulkProcessFailed e) {
551             String msg = "Failed to commit transaction";
552             logger.debug(msg + " with error: " + e);
553             throw new HeatBridgeException(msg, e);
554         }
555     }
556
557     @Override
558     public void deleteVfModuleData(@Nonnull final String vnfId, @Nonnull final String vfModuleId)
559             throws HeatBridgeException {
560         Objects.requireNonNull(vnfId, "Null vnf-id!");
561         Objects.requireNonNull(vfModuleId, "Null vf-module-id!");
562         try {
563             Optional<VfModule> vfModule = resourcesClient
564                     .get(AAIUriFactory.createResourceUri(AAIObjectType.VF_MODULE, vnfId, vfModuleId).depth(Depth.ONE),
565                             NotFoundException.class)
566                     .asBean(VfModule.class);
567
568             AAIResultWrapper resultWrapper = new AAIResultWrapper(vfModule.get());
569             Optional<Relationships> relationships = resultWrapper.getRelationships();
570             logger.debug("VfModule contains relationships in AAI: {}", relationships.isPresent());
571             if (relationships.isPresent()) {
572
573                 List<AAIResourceUri> l3NetworkUris = relationships.get().getRelatedUris(AAIObjectType.L3_NETWORK);
574                 logger.debug("L3Network contains {} relationships in AAI", l3NetworkUris.size());
575
576                 if (!l3NetworkUris.isEmpty()) {
577                     for (AAIResourceUri l3NetworkUri : l3NetworkUris) {
578                         if (env.getProperty("heatBridgeDryrun", Boolean.class, true)) {
579                             logger.debug("Would delete L3Network: {}", l3NetworkUri.build().toString());
580                         } else {
581                             resourcesClient.delete(l3NetworkUri);
582                         }
583                     }
584                 }
585
586                 List<AAIResourceUri> vserverUris = relationships.get().getRelatedUris(AAIObjectType.VSERVER);
587                 logger.debug("VServer contains {} relationships in AAI", vserverUris.size());
588                 createTransactionToDeleteSriovPfFromPserver(vserverUris);
589
590                 if (!vserverUris.isEmpty()) {
591                     for (AAIResourceUri vserverUri : vserverUris) {
592                         if (env.getProperty("heatBridgeDryrun", Boolean.class, true)) {
593                             logger.debug("Would delete Vserver: {}", vserverUri.build().toString());
594                         } else {
595                             resourcesClient.delete(vserverUri);
596                         }
597                     }
598                 }
599             }
600
601         } catch (NotFoundException e) {
602             String msg = "Failed to commit delete heatbridge data transaction";
603             logger.debug(msg + " with error: " + e);
604             throw new HeatBridgeException(msg, e);
605         } catch (Exception e) {
606             String msg = "Failed to commit delete heatbridge data transaction";
607             logger.debug(msg + " with error: " + e);
608             throw new HeatBridgeException(msg, e);
609         }
610     }
611
612     private void createTransactionToDeleteSriovPfFromPserver(List<AAIResourceUri> vserverUris) {
613         Map<String, List<String>> pserverToPciIdMap = getPserverToPciIdMap(vserverUris);
614         for (Map.Entry<String, List<String>> entry : pserverToPciIdMap.entrySet()) {
615             String pserverName = entry.getKey();
616             List<String> pciIds = entry.getValue();
617             Optional<Pserver> pserver = resourcesClient.get(Pserver.class,
618                     AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, pserverName).depth(Depth.TWO));
619             if (pserver.isPresent()) {
620                 // For each pserver/p-interface match sriov-vfs by pic-id and delete them.
621                 pserver.get().getPInterfaces().getPInterface().stream().filter(
622                         pIf -> pIf.getSriovPfs() != null && CollectionUtils.isNotEmpty(pIf.getSriovPfs().getSriovPf()))
623                         .forEach(pIf -> pIf.getSriovPfs().getSriovPf().forEach(sriovPf -> {
624                             if (pciIds.contains(sriovPf.getPfPciId())) {
625                                 logger.debug("creating transaction to delete SR-IOV PF: " + pIf.getInterfaceName()
626                                         + " from PServer: " + pserverName);
627                                 if (env.getProperty("heatBridgeDryrun", Boolean.class, true)) {
628                                     logger.debug("Would delete Sriov Pf: {}",
629                                             AAIUriFactory
630                                                     .createResourceUri(AAIObjectType.SRIOV_PF, pserverName,
631                                                             pIf.getInterfaceName(), sriovPf.getPfPciId())
632                                                     .build().toString());
633                                 } else {
634                                     resourcesClient.delete(AAIUriFactory.createResourceUri(AAIObjectType.SRIOV_PF,
635                                             pserverName, pIf.getInterfaceName(), sriovPf.getPfPciId()));
636                                 }
637                             }
638                         }));
639             }
640         }
641     }
642
643     private Map<String, List<String>> getPserverToPciIdMap(List<AAIResourceUri> vserverUris) {
644         Map<String, List<String>> pserverToPciIdMap = new HashMap<>();
645         for (AAIResourceUri vserverUri : vserverUris) {
646             AAIResultWrapper vserverWrapper = resourcesClient.get(vserverUri.depth(Depth.TWO));
647             Optional<Relationships> vserverRelationships = vserverWrapper.getRelationships();
648             if (vserverRelationships.isPresent()
649                     && CollectionUtils.isNotEmpty(vserverRelationships.get().getRelatedLinks(AAIObjectType.PSERVER))) {
650                 Vserver vserver = vserverWrapper.asBean(Vserver.class).get();
651                 List<String> pciIds = HeatBridgeUtils.extractPciIdsFromVServer(vserver);
652                 if (CollectionUtils.isNotEmpty(pciIds)) {
653                     List<AAIResourceUri> matchingPservers =
654                             vserverRelationships.get().getRelatedUris(AAIObjectType.PSERVER);
655                     if (matchingPservers != null && matchingPservers.size() == 1) {
656                         pserverToPciIdMap.put(matchingPservers.get(0).getURIKeys().get("hostname"), pciIds);
657                     }
658                 }
659             }
660         }
661         return pserverToPciIdMap;
662     }
663
664     private <T> Predicate<T> distinctByProperty(Function<? super T, Object> keyExtractor) {
665         Map<Object, Boolean> map = new ConcurrentHashMap<>();
666         return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
667     }
668 }