2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.so.adapters.audit;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Optional;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
33 import org.onap.aai.domain.yang.LInterface;
34 import org.onap.aai.domain.yang.LInterfaces;
35 import org.onap.aai.domain.yang.Vserver;
36 import org.onap.so.openstack.utils.MsoHeatUtils;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.springframework.beans.factory.annotation.Autowired;
40 import org.springframework.stereotype.Component;
42 import com.woorea.openstack.heat.model.Link;
43 import com.woorea.openstack.heat.model.Resource;
44 import com.woorea.openstack.heat.model.Resources;
45 import com.woorea.openstack.heat.model.Stack;
48 public class HeatStackAudit {
50 private static final String RESOURCES = "/resources";
52 protected static final Logger logger = LoggerFactory.getLogger(HeatStackAudit.class);
55 protected MsoHeatUtils heat;
58 protected AuditVServer auditVservers;
60 public boolean auditHeatStackCreate(String cloudRegion, String cloudOwner, String tenantId, String heatStackName) {
62 return auditStack(cloudRegion,cloudOwner,tenantId,heatStackName,true);
63 } catch (Exception e) {
64 logger.error("Error during auditing stack resources", e);
69 public boolean auditHeatStackDeleted(String cloudRegion, String cloudOwner, String tenantId, String heatStackName) {
71 return auditStack(cloudRegion,cloudOwner,tenantId,heatStackName,false);
72 } catch (Exception e) {
73 logger.error("Error during auditing stack resources", e);
78 private boolean auditStack(String cloudRegion, String cloudOwner, String tenantId, String heatStackName,boolean isCreateAudit) throws Exception{
79 logger.debug("Fetching Top Level Stack Information");
80 Resources resources = heat.queryStackResources(cloudRegion, tenantId, heatStackName);
81 List<Resource> novaResources = extractNovaResources(resources);
82 if(novaResources.isEmpty())
85 List<Resource> resourceGroups = extractResourceGroups(resources);
86 Set<Vserver> vserversToAudit = createVserverSet(resources, novaResources);
87 Set<Vserver> vserversWithSubInterfaces = processSubInterfaces(cloudRegion, tenantId, resourceGroups,
90 return auditVservers.auditAllVserversDoExist(vserversWithSubInterfaces, tenantId, cloudOwner, cloudRegion);
92 return auditVservers.auditAllVserversDoNotExist(vserversWithSubInterfaces, tenantId, cloudOwner, cloudRegion);
97 private List<Resource> extractResourceGroups(Resources resources) {
98 return resources.getList().stream()
99 .filter(p -> "OS::Heat::ResourceGroup".equals(p.getType()) && p.getName().contains("subinterfaces")).collect(Collectors.toList());
102 private List<Resource> extractNovaResources(Resources resources) {
103 return resources.getList().stream()
104 .filter(p -> "OS::Nova::Server".equals(p.getType())).collect(Collectors.toList());
107 protected Set<Vserver> processSubInterfaces(String cloudRegion, String tenantId, List<Resource> resourceGroups,
108 Set<Vserver> vServersToAudit) throws Exception {
109 for (Resource resourceGroup : resourceGroups) {
110 processResourceGroups(cloudRegion, tenantId, vServersToAudit, resourceGroup);
112 return vServersToAudit;
115 protected void processResourceGroups(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface,
116 Resource resourceGroup) throws Exception {
117 Optional<Link> stackLink = resourceGroup.getLinks().stream().filter(link -> "nested".equals(link.getRel()))
119 if (stackLink.isPresent()) {
121 Optional<String> path = extractResourcePathFromHref(stackLink.get().getHref());
122 if (path.isPresent()) {
123 logger.debug("Fetching nested Resource Stack Information");
124 Resources nestedResourceGroupResources = heat.executeHeatClientRequest(path.get(), cloudRegion,
125 tenantId, Resources.class);
126 processNestedResourceGroup(cloudRegion, tenantId, vServersWithLInterface,
127 nestedResourceGroupResources);
129 throw new Exception("Error finding Path from Self Link");
130 } catch (Exception e) {
131 logger.error("Error Parsing Link to obtain Path", e);
132 throw new Exception("Error finding Path from Self Link");
138 protected void processNestedResourceGroup(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface,
139 Resources nestedResourceGroupResources) throws Exception {
140 for (Resource resourceGroupNested : nestedResourceGroupResources) {
141 Optional<Link> subInterfaceStackLink = resourceGroupNested.getLinks().stream()
142 .filter(link -> "nested".equals(link.getRel())).findAny();
143 if (subInterfaceStackLink.isPresent()) {
144 addSubInterface(cloudRegion, tenantId, vServersWithLInterface,subInterfaceStackLink.get());
149 protected void addSubInterface(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface, Link subInterfaceStackLink) throws Exception {
150 Optional<String> resourcePath = extractResourcePathFromHref(subInterfaceStackLink.getHref());
151 Optional<String> stackPath = extractStackPathFromHref(subInterfaceStackLink.getHref());
152 if (resourcePath.isPresent() && stackPath.isPresent()) {
153 logger.debug("Fetching nested Sub-Interface Stack Information");
154 Stack subinterfaceStack = heat.executeHeatClientRequest(stackPath.get(), cloudRegion, tenantId, Stack.class);
155 Resources subinterfaceResources = heat.executeHeatClientRequest(resourcePath.get(), cloudRegion, tenantId, Resources.class);
156 if (subinterfaceStack != null) {
157 addSubInterfaceToVserver(vServersWithLInterface, subinterfaceStack, subinterfaceResources);
160 throw new Exception("Error finding Path from Self Link");
164 protected void addSubInterfaceToVserver(Set<Vserver> vServersWithLInterface, Stack subinterfaceStack, Resources subinterfaceResources) throws Exception {
165 String parentNeutronPortId = (String) subinterfaceStack.getParameters().get("port_interface");
166 logger.debug("Parent neutron Port: {} on SubInterface: {}", parentNeutronPortId, subinterfaceStack.getId());
167 for (Vserver auditVserver : vServersWithLInterface)
168 for (LInterface lInterface : auditVserver.getLInterfaces().getLInterface())
170 if (parentNeutronPortId.equals(lInterface.getInterfaceId())) {
171 logger.debug("Found Parent Port on VServer: {} on Port: {}", auditVserver.getVserverId(), lInterface.getInterfaceId());
172 Resource contrailVm = subinterfaceResources.getList().stream().filter(resource -> "OS::ContrailV2::VirtualMachineInterface".equals(resource.getType())).findAny()
174 if(contrailVm == null){
175 throw new Exception("Cannnot find Contrail Virtual Machine Interface on Stack: "+ subinterfaceStack.getId());
177 LInterface subInterface = new LInterface();
178 subInterface.setInterfaceId(contrailVm.getPhysicalResourceId());
180 if(lInterface.getLInterfaces() == null)
181 lInterface.setLInterfaces(new LInterfaces());
183 lInterface.getLInterfaces().getLInterface().add(subInterface);
185 logger.debug("Did Not Find Parent Port on VServer: {} Parent Port: SubInterface: {}",auditVserver.getVserverId(),
186 lInterface.getInterfaceId(),subinterfaceStack.getId());
189 protected Set<Vserver> createVserverSet(Resources resources, List<Resource> novaResources) {
190 Set<Vserver> vserversToAudit = new HashSet<>();
191 for (Resource novaResource : novaResources) {
192 Vserver auditVserver = new Vserver();
193 auditVserver.setLInterfaces(new LInterfaces());
194 auditVserver.setVserverId(novaResource.getPhysicalResourceId());
195 Stream<Resource> filteredNeutronNetworks = resources.getList().stream()
196 .filter(resource -> resource.getRequiredBy().contains(novaResource.getLogicalResourceId()))
197 .filter(resource -> "OS::Neutron::Port".equals(resource.getType()));
198 filteredNeutronNetworks.forEach(network -> {
199 LInterface lInterface = new LInterface();
200 lInterface.setInterfaceId(network.getPhysicalResourceId());
201 auditVserver.getLInterfaces().getLInterface().add(lInterface);
203 vserversToAudit.add(auditVserver);
205 return vserversToAudit;
208 protected Optional<String> extractResourcePathFromHref(String href) {
210 Optional<String> stackPath = extractStackPathFromHref(href);
211 if (stackPath.isPresent()){
212 return Optional.of(stackPath.get()+RESOURCES);
214 return Optional.empty();
215 } catch (Exception e) {
216 logger.error("Error parsing URI", e);
218 return Optional.empty();
221 protected Optional<String> extractStackPathFromHref(String href) {
223 URI uri = new URI(href);
224 Pattern p = Pattern.compile("/stacks.*");
225 Matcher m = p.matcher(uri.getPath());
227 return Optional.of(m.group());
229 return Optional.empty();
230 } catch (Exception e) {
231 logger.error("Error parsing URI", e);
233 return Optional.empty();