Merge "Merge Casablanca"
[so.git] / adapters / mso-openstack-adapters / src / main / java / org / onap / so / adapters / audit / HeatStackAudit.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
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
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 package org.onap.so.adapters.audit;
22
23 import java.net.URI;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.stream.Collectors;
29 import java.util.stream.Stream;
30
31 import org.onap.aai.domain.yang.LInterface;
32 import org.onap.aai.domain.yang.LInterfaces;
33 import org.onap.aai.domain.yang.Vserver;
34 import org.onap.so.openstack.utils.MsoHeatUtils;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.springframework.beans.factory.annotation.Autowired;
38 import org.springframework.stereotype.Component;
39
40 import com.woorea.openstack.heat.model.Link;
41 import com.woorea.openstack.heat.model.Resource;
42 import com.woorea.openstack.heat.model.Resources;
43 import com.woorea.openstack.heat.model.Stack;
44
45 @Component
46 public class HeatStackAudit {
47
48         private static final String RESOURCES = "/resources";
49
50         protected static final Logger logger = LoggerFactory.getLogger(HeatStackAudit.class);
51
52         @Autowired
53         protected MsoHeatUtils heat;
54
55         @Autowired
56         protected AuditVServer auditVservers;
57
58         public boolean auditHeatStack(String cloudRegion, String cloudOwner, String tenantId, String heatStackName) {
59                 try {
60                         logger.debug("Fetching Top Level Stack Information");
61                         Resources resources = heat.queryStackResources(cloudRegion, tenantId, heatStackName);
62                         List<Resource> novaResources = resources.getList().stream()
63                                         .filter(p -> "OS::Nova::Server".equals(p.getType())).collect(Collectors.toList());
64                         List<Resource> resourceGroups = resources.getList().stream()
65                                         .filter(p -> "OS::Heat::ResourceGroup".equals(p.getType()) && p.getName().contains("subinterfaces")).collect(Collectors.toList());
66                         Set<Vserver> vserversToAudit = createVserverSet(resources, novaResources);
67                         Set<Vserver> vserversWithSubInterfaces = processSubInterfaces(cloudRegion, tenantId, resourceGroups,
68                                         vserversToAudit); 
69                         return auditVservers.auditVservers(vserversWithSubInterfaces, tenantId, cloudOwner, cloudRegion);
70                 } catch (Exception e) {
71                         logger.error("Error during auditing stack resources", e);
72                         return false;
73                 }
74         } 
75
76         protected Set<Vserver> processSubInterfaces(String cloudRegion, String tenantId, List<Resource> resourceGroups,
77                         Set<Vserver> vServersToAudit) throws Exception {
78                 for (Resource resourceGroup : resourceGroups) {
79                         processResourceGroups(cloudRegion, tenantId, vServersToAudit, resourceGroup);
80                 }
81                 return vServersToAudit;
82         }
83
84         protected void processResourceGroups(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface,
85                         Resource resourceGroup) throws Exception {
86                 Optional<Link> stackLink = resourceGroup.getLinks().stream().filter(link -> "nested".equals(link.getRel()))
87                                 .findAny();
88                 if (stackLink.isPresent()) {
89                         try {
90                                 Optional<String> path = extractResourcePathFromHref(stackLink.get().getHref());
91                                 if (path.isPresent()) {
92                                         logger.debug("Fetching nested Resource Stack Information");
93                                         Resources nestedResourceGroupResources = heat.executeHeatClientRequest(path.get(), cloudRegion,
94                                                         tenantId, Resources.class);
95                                         processNestedResourceGroup(cloudRegion, tenantId, vServersWithLInterface,
96                                                         nestedResourceGroupResources);
97                                 } else
98                                         throw new Exception("Error finding Path from Self Link");
99                         } catch (Exception e) {
100                                 logger.error("Error Parsing Link to obtain Path", e);
101                                 throw new Exception("Error finding Path from Self Link");
102                         }
103
104                 }
105         }
106
107         protected void processNestedResourceGroup(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface,
108                         Resources nestedResourceGroupResources) throws Exception {
109                 for (Resource resourceGroupNested : nestedResourceGroupResources) {
110                         Optional<Link> subInterfaceStackLink = resourceGroupNested.getLinks().stream()
111                                         .filter(link -> "nested".equals(link.getRel())).findAny();
112                         if (subInterfaceStackLink.isPresent()) {
113                                 addSubInterface(cloudRegion, tenantId, vServersWithLInterface,subInterfaceStackLink.get());
114                         }
115                 }
116         }
117
118         protected void addSubInterface(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface, Link subInterfaceStackLink) throws Exception {
119                         Optional<String> resourcePath = extractResourcePathFromHref(subInterfaceStackLink.getHref());
120                         Optional<String> stackPath = extractStackPathFromHref(subInterfaceStackLink.getHref());
121                         if (resourcePath.isPresent() && stackPath.isPresent()) {
122                                 logger.debug("Fetching nested Sub-Interface Stack Information");
123                                 Stack subinterfaceStack = heat.executeHeatClientRequest(stackPath.get(), cloudRegion, tenantId, Stack.class);
124                                 Resources subinterfaceResources = heat.executeHeatClientRequest(resourcePath.get(), cloudRegion, tenantId, Resources.class);
125                                 if (subinterfaceStack != null) {
126                                         addSubInterfaceToVserver(vServersWithLInterface, subinterfaceStack, subinterfaceResources);
127                                 }
128                         } else
129                                 throw new Exception("Error finding Path from Self Link");
130                 
131         }
132
133         protected void addSubInterfaceToVserver(Set<Vserver> vServersWithLInterface, Stack subinterfaceStack, Resources subinterfaceResources) throws Exception {
134                 String parentNeutronPortId = (String) subinterfaceStack.getParameters().get("port_interface");
135                 logger.debug("Parent neutron Port: {} on SubInterface: {}", parentNeutronPortId, subinterfaceStack.getId());
136                 for (Vserver auditVserver : vServersWithLInterface)
137                         for (LInterface lInterface : auditVserver.getLInterfaces().getLInterface())
138                                 
139                                 if (parentNeutronPortId.equals(lInterface.getInterfaceId())) {
140                                         logger.debug("Found Parent Port on VServer: {} on Port: {}", auditVserver.getVserverId(), lInterface.getInterfaceId());
141                                         Resource contrailVm = subinterfaceResources.getList().stream().filter(resource -> "OS::ContrailV2::VirtualMachineInterface".equals(resource.getType())).findAny()
142                         .orElse(null);
143                                         if(contrailVm == null){
144                                                 throw new Exception("Cannnot find Contrail Virtual Machine Interface on Stack: "+ subinterfaceStack.getId());
145                                         }
146                                         LInterface subInterface = new LInterface();
147                                         subInterface.setInterfaceId(contrailVm.getPhysicalResourceId());
148                                         
149                                         if(lInterface.getLInterfaces() == null)
150                                                 lInterface.setLInterfaces(new LInterfaces());
151                                         
152                                         lInterface.getLInterfaces().getLInterface().add(subInterface);
153                                 }else
154                                         logger.debug("Did Not Find Parent Port on VServer: {} Parent Port: SubInterface: {}",auditVserver.getVserverId(), 
155                                                         lInterface.getInterfaceId(),subinterfaceStack.getId());
156         }
157
158         protected Set<Vserver> createVserverSet(Resources resources, List<Resource> novaResources) {
159                 Set<Vserver> vserversToAudit = new HashSet<>();
160                 for (Resource novaResource : novaResources) {
161                         Vserver auditVserver = new Vserver();
162                         auditVserver.setLInterfaces(new LInterfaces());
163                         auditVserver.setVserverId(novaResource.getPhysicalResourceId());
164                         Stream<Resource> filteredNeutronNetworks = resources.getList().stream()
165                                         .filter(network -> network.getRequiredBy().contains(novaResource.getLogicalResourceId()));
166                         filteredNeutronNetworks.forEach(network -> {
167                                 LInterface lInterface = new LInterface();
168                                 lInterface.setInterfaceId(network.getPhysicalResourceId());
169                                 auditVserver.getLInterfaces().getLInterface().add(lInterface);
170                         });
171                         vserversToAudit.add(auditVserver);
172                 }
173                 return vserversToAudit;
174         }
175
176         protected Optional<String> extractResourcePathFromHref(String href) {
177                 URI uri;
178                 try {
179                         uri = new URI(href);                    
180                         return Optional.of(uri.getPath().replaceFirst("/v\\d+", "")+RESOURCES);                 
181                 } catch (Exception e) {
182                         logger.error("Error parsing URI", e);
183                 }
184                 return Optional.empty();
185         }
186         
187         protected Optional<String> extractStackPathFromHref(String href) {
188                 URI uri;
189                 try {
190                         uri = new URI(href);                    
191                         return Optional.of(uri.getPath().replaceFirst("/v\\d+", ""));                   
192                 } catch (Exception e) {
193                         logger.error("Error parsing URI", e);
194                 }
195                 return Optional.empty();
196         }
197         
198         
199 }