Simplified the return condition
[sdc.git] / openecomp-be / lib / openecomp-sdc-enrichment-lib / openecomp-sdc-enrichment-impl / src / main / java / org / openecomp / sdc / enrichment / impl / tosca / PortMirroringEnricher.java
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.sdc.enrichment.impl.tosca;
18
19 import org.apache.commons.collections4.CollectionUtils;
20 import org.apache.commons.collections4.MapUtils;
21 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
22 import org.openecomp.sdc.datatypes.error.ErrorMessage;
23 import org.openecomp.sdc.enrichment.impl.tosca.model.PortMirroringConnectionPointDescription;
24 import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage;
25 import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes;
26 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
27 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
28 import org.openecomp.sdc.tosca.datatypes.model.CapabilityAssignment;
29 import org.openecomp.sdc.tosca.datatypes.model.Import;
30 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
31 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
32 import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition;
33 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
34 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
35 import org.openecomp.sdc.tosca.services.DataModelUtil;
36 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
37 import org.openecomp.sdc.tosca.services.ToscaConstants;
38 import org.openecomp.sdc.tosca.services.ToscaUtil;
39 import org.openecomp.sdc.tosca.services.impl.ToscaAnalyzerServiceImpl;
40 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
41 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
42
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.LinkedList;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Objects;
51 import java.util.Optional;
52 import java.util.Set;
53 import java.util.stream.Collectors;
54
55 import static org.openecomp.sdc.tosca.services.DataModelUtil.getClonedObject;
56 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME;
57 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_ID;
58
59 public class PortMirroringEnricher {
60   //Map of service template file name and map of all port node template ids, node template
61   private Map<String, Map<String, NodeTemplate>> portNodeTemplates = new HashMap<>();
62   //Map of service template file name and map of external port node template ids, node template
63   private Map<String, Map<String, NodeTemplate>> externalPortNodeTemplates = new HashMap<>();
64   //Map of substitution service template name and the list of ports with link requirement from
65   // the abstract
66   private Map<String, List<String>> portNodeTemplateIdsFromAbstract = new HashMap<>();
67   private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage();
68   private Map<String, ServiceTemplate> globalTypesServiceTemplate =
69       GlobalTypesGenerator.getGlobalTypesServiceTemplate(OnboardingTypesEnum.ZIP);
70
71   /**
72    * Enrich tosca for port mirroring.
73    *
74    * @param toscaServiceModel the tosca service model
75    * @return the map          Error descriptor map
76    */
77   public Map<String, List<ErrorMessage>> enrich(ToscaServiceModel toscaServiceModel) {
78     mdcDataDebugMessage.debugEntryMessage(null);
79     Map<String, List<ErrorMessage>> errors = new HashMap<>();
80     Map<String, ServiceTemplate> serviceTemplates = toscaServiceModel.getServiceTemplates();
81     serviceTemplates.entrySet().stream()
82         //Skipping the service templates which do not contain topology template
83         .filter(serviceTemplateEntry -> serviceTemplateEntry.getValue()
84             .getTopology_template() != null)
85         .forEach(serviceTemplateEntry ->
86             //Collect all the ports across all the service templates
87             collectPorts(serviceTemplateEntry.getValue()));
88     //Collect External ports from the list of all ports collected above
89     filterExternalPorts(toscaServiceModel);
90     //Handle external port changes
91     handleExternalPorts(toscaServiceModel);
92     mdcDataDebugMessage.debugExitMessage(null);
93     return errors;
94   }
95
96   private void collectPorts(ServiceTemplate serviceTemplate) {
97     Map<String, NodeTemplate> nodeTemplates =
98         serviceTemplate.getTopology_template().getNode_templates();
99     if (Objects.nonNull(nodeTemplates)) {
100       //Get all concrete port node templates from the service template
101       Map<String, NodeTemplate> serviceTemplatePortNodeTemplates = nodeTemplates.entrySet().stream()
102           .filter(nodeTemplateEntry -> (Objects.nonNull(nodeTemplateEntry.getValue()))
103               && (isPortNodeTemplate(nodeTemplateEntry.getValue().getType())))
104           .collect(Collectors.toMap(nodeTemplateEntry -> nodeTemplateEntry.getKey(),
105               nodeTemplateEntry -> nodeTemplateEntry.getValue()));
106
107       portNodeTemplates.put(ToscaUtil.getServiceTemplateFileName(serviceTemplate),
108           serviceTemplatePortNodeTemplates);
109
110       //Get all linked internal ports from abstract node template link requirements
111       List<String> abstractLinkedPortNodeTemplates = new ArrayList<>();
112       for (Map.Entry<String, NodeTemplate> nodeTemplateEntry : nodeTemplates.entrySet()) {
113         NodeTemplate nodeTemplate = nodeTemplateEntry.getValue();
114         if (isSubstitutableNodeTemplate(nodeTemplate)) {
115           List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
116           if (Objects.nonNull(requirements)) {
117             for (Map<String, RequirementAssignment> requirement : requirements) {
118               String requirementId = requirement.keySet().iterator().next();
119               String abstractLinkRequirementIdPrefix = ToscaConstants.LINK_REQUIREMENT_ID + "_";
120               if (requirementId.startsWith(abstractLinkRequirementIdPrefix)) {
121                 //Collect port node template ids from the link requirement ids in the abstract
122                 // node template
123                 abstractLinkedPortNodeTemplates.add(requirementId.substring(requirementId
124                     .indexOf("_") + 1));
125               }
126             }
127           }
128           if (CollectionUtils.isNotEmpty(abstractLinkedPortNodeTemplates)) {
129             //Populate a map of the substitution service templates and list of internal ports
130             addCollectedPortsToAbstractServiceTemplatePortMap(nodeTemplate,
131                 abstractLinkedPortNodeTemplates);
132           }
133         }
134       }
135     }
136   }
137
138   private void addCollectedPortsToAbstractServiceTemplatePortMap(NodeTemplate nodeTemplate,
139                                                                  List<String>
140                                                                      abstractLinkedPortNodeTemplates) {
141     String substitutionServiceTemplateName = null;
142     if (nodeTemplate.getProperties() != null) {
143       Map serviceTemplateFilter = (Map<String, Object>) nodeTemplate.getProperties()
144           .get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
145       substitutionServiceTemplateName = (String)
146           serviceTemplateFilter.get(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME);
147       if (Objects.nonNull(substitutionServiceTemplateName)) {
148         if (portNodeTemplateIdsFromAbstract.containsKey(substitutionServiceTemplateName)) {
149           List<String> portList =
150               portNodeTemplateIdsFromAbstract.get(substitutionServiceTemplateName);
151           portList.addAll(abstractLinkedPortNodeTemplates);
152           portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, portList);
153         } else {
154           portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName,
155               abstractLinkedPortNodeTemplates);
156         }
157       }
158     }
159   }
160
161   private void filterExternalPorts(ToscaServiceModel toscaServiceModel) {
162     for (Map.Entry<String, Map<String, NodeTemplate>> portNodeTemplateEntry : portNodeTemplates
163         .entrySet()) {
164       Map<String, NodeTemplate> externalPorts = new HashMap<>();
165       String serviceTemplateFileName = portNodeTemplateEntry.getKey();
166       Map<String, NodeTemplate> portNodeTemplateMap = portNodeTemplateEntry.getValue();
167       for (Map.Entry<String, NodeTemplate> portNodeTemplate : portNodeTemplateMap.entrySet()) {
168         String nodeTemplateId = portNodeTemplate.getKey();
169         NodeTemplate nodeTemplate = portNodeTemplate.getValue();
170         String newPortNodeType = nodeTemplate.getType();
171         if (!isInternalPort(serviceTemplateFileName, nodeTemplateId, nodeTemplate)) {
172           //External Port
173           externalPorts.putIfAbsent(nodeTemplateId, nodeTemplate);
174         }
175       }
176       externalPortNodeTemplates.putIfAbsent(serviceTemplateFileName, externalPorts);
177     }
178   }
179
180   private void updateExternalPortNodeTemplate(NodeTemplate externalPortNodeTemplate,
181                                               ToscaServiceModel toscaServiceModel) {
182     String currentPortNodeType = externalPortNodeTemplate.getType();
183     if (currentPortNodeType.equals(ToscaNodeType.CONTRAIL_PORT)
184         || currentPortNodeType.equals(ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE)) {
185       //Set external contrail port node type
186       externalPortNodeTemplate.setType(ToscaNodeType.EXTERNAL_CONTRAIL_PORT);
187       addPortMirroringCapability(externalPortNodeTemplate);
188     } else if (currentPortNodeType.equals(ToscaNodeType.NEUTRON_PORT)) {
189       //Set external neutron port node type
190       externalPortNodeTemplate.setType(ToscaNodeType.EXTERNAL_NEUTRON_PORT);
191       addPortMirroringCapability(externalPortNodeTemplate);
192     }
193   }
194
195   private void handleExternalPorts(ToscaServiceModel toscaServiceModel) {
196
197     for (Map.Entry<String, Map<String, NodeTemplate>> entry : externalPortNodeTemplates
198         .entrySet()) {
199       String serviceTemplateName = entry.getKey();
200       ServiceTemplate serviceTemplate =
201           toscaServiceModel.getServiceTemplates().get(serviceTemplateName);
202       Map<String, NodeTemplate> externalNodeTemplates = entry.getValue();
203       if (MapUtils.isNotEmpty(externalNodeTemplates)) {
204         for (Map.Entry<String, NodeTemplate> externalNodeTemplate : externalNodeTemplates
205             .entrySet()) {
206           String externalPortNodeTemplateId = externalNodeTemplate.getKey();
207           updateExternalPortNodeTemplate(externalNodeTemplate.getValue(), toscaServiceModel);
208           if (serviceTemplate.getTopology_template().getSubstitution_mappings() != null) {
209             //Add port mirroring capability to substitution mapping for external ports
210             addPortMirroringSubstitutionMappingCapability(serviceTemplate,
211                 externalPortNodeTemplateId);
212           }
213           handleExternalPortProperties(externalNodeTemplate.getValue(), serviceTemplate, toscaServiceModel);
214         }
215         addGlobalTypeImport(serviceTemplate);
216       }
217     }
218   }
219
220   private void handleExternalPortProperties(NodeTemplate portNodeTemplate,
221                                             ServiceTemplate serviceTemplate,
222                                             ToscaServiceModel toscaServiceModel){
223
224     ToscaAnalyzerService toscaAnalyzerService = new ToscaAnalyzerServiceImpl();
225     String externalPortType = portNodeTemplate.getType();
226     Map<String, PropertyDefinition> globalTypesportProperties = new HashMap<>();
227     NodeType flatNodeType =
228         (NodeType) toscaAnalyzerService.getFlatEntity(ToscaElementTypes.NODE_TYPE, externalPortType, serviceTemplate, toscaServiceModel);
229     globalTypesportProperties.putAll(flatNodeType.getProperties());
230
231     Map<String, Object> properties = portNodeTemplate.getProperties();
232     Map<String, Object> filteredProperties = new HashMap<>();
233
234     if(MapUtils.isEmpty(properties)){
235       return;
236     }
237
238     for(Map.Entry<String, Object> propertyEntry: properties.entrySet()){
239       if(globalTypesportProperties.containsKey(propertyEntry.getKey())){
240         filteredProperties.put(propertyEntry.getKey(), propertyEntry.getValue());
241       }
242     }
243
244     if(!MapUtils.isEmpty(filteredProperties)) {
245       portNodeTemplate.setProperties(filteredProperties);
246     }else{
247       portNodeTemplate.setProperties(null);
248     }
249
250   }
251
252   private void addPortMirroringSubstitutionMappingCapability(ServiceTemplate serviceTemplate,
253                                                              String externalPortNodeTemplateId) {
254     List<String> portMirroringCapability = new LinkedList<>();
255     portMirroringCapability.add(externalPortNodeTemplateId);
256     portMirroringCapability.add(PORT_MIRRORING_CAPABILITY_ID);
257     String substitutionMappingCapabilityId = PORT_MIRRORING_CAPABILITY_ID + "_"
258         + externalPortNodeTemplateId;
259     DataModelUtil.addSubstitutionMappingCapability(serviceTemplate,
260         substitutionMappingCapabilityId, portMirroringCapability);
261   }
262
263   private void addPortMirroringCapability(NodeTemplate portNodeTemplate) {
264     List<Map<String, CapabilityAssignment>> capabilities = portNodeTemplate.getCapabilities();
265     if (Objects.isNull(capabilities)) {
266       capabilities = new ArrayList<>();
267     }
268     Map<String, Object> portMirroringCapabilityProperties = new HashMap<>();
269     PortMirroringConnectionPointDescription connectionPoint = new
270         PortMirroringConnectionPointDescription();
271     //Get Network role property
272     if (Objects.nonNull(portNodeTemplate.getProperties())) {
273       Object networkRolePropertyValue =
274           portNodeTemplate.getProperties().get(ToscaConstants.PORT_NETWORK_ROLE_PROPERTY_NAME);
275       if (Objects.nonNull(networkRolePropertyValue)) {
276         Object portMirroringNetworkRolePropertyVal = getClonedObject(networkRolePropertyValue);
277         connectionPoint.setNetwork_role(portMirroringNetworkRolePropertyVal);
278       }
279     }
280     //Get NFC_Type from the binding requirement node
281     if (Objects.nonNull(portNodeTemplate.getRequirements())) {
282       Optional<List<RequirementAssignment>> requirementAssignment =
283           DataModelUtil.getRequirementAssignment(portNodeTemplate.getRequirements(), ToscaConstants
284               .BINDING_REQUIREMENT_ID);
285       if (requirementAssignment.isPresent()) {
286         RequirementAssignment bindingRequirementAssignment = requirementAssignment.get().get(0);
287         String node = bindingRequirementAssignment.getNode();
288         connectionPoint.setNfc_type(node);
289       }
290     }
291
292     if (!connectionPoint.isEmpty()) {
293       portMirroringCapabilityProperties.put(PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME,
294           connectionPoint);
295       DataModelUtil.addNodeTemplateCapability(portNodeTemplate,
296           PORT_MIRRORING_CAPABILITY_ID, portMirroringCapabilityProperties, null);
297     }
298   }
299
300   private void addGlobalTypeImport(ServiceTemplate serviceTemplate) {
301     List<Map<String, Import>> imports = serviceTemplate.getImports();
302     Map<String, Import> openecompIndexImport = new HashMap<>();
303     openecompIndexImport.put("openecomp_index",
304         HeatToToscaUtil.createServiceTemplateImport(globalTypesServiceTemplate
305             .get("openecomp/_index.yml")));
306     imports.add(openecompIndexImport);
307   }
308
309   private boolean isPortNodeTemplate(String nodeType) {
310     //Check if node corresponds to a concrete port node
311     Set<String> portNodeTypes = getPortNodeTypes();
312     return Objects.nonNull(nodeType)
313         && portNodeTypes.contains(nodeType);
314   }
315
316   private Set<String> getPortNodeTypes(){
317     return new HashSet<>(Arrays.asList(ToscaNodeType.NEUTRON_PORT,
318         ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE,
319         ToscaNodeType.CONTRAIL_PORT));
320   }
321
322   private boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
323     if (Objects.nonNull(nodeTemplate.getDirectives())) {
324       return nodeTemplate.getDirectives().contains(ToscaConstants
325           .NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
326     }
327     return false;
328   }
329
330   private boolean isInternalPort(String serviceTemplateFileName, String nodeTemplateId,
331                                  NodeTemplate nodeTemplate) {
332     return isAbstractInternalPort(serviceTemplateFileName, nodeTemplateId)
333         || isConcreteInternalPort(nodeTemplate);
334   }
335
336   private boolean isAbstractInternalPort(String serviceTemplateFileName, String nodeTemplateId) {
337     //Check if port corresponds to an abstract internal port
338     if (portNodeTemplateIdsFromAbstract.containsKey(serviceTemplateFileName)) {
339       return portNodeTemplateIdsFromAbstract.get(serviceTemplateFileName).contains(nodeTemplateId);
340     }
341     return false;
342   }
343
344
345   private boolean isConcreteInternalPort(NodeTemplate nodeTemplate) {
346     //Check if node template contains a link requirement
347     List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
348     if (Objects.nonNull(requirements)) {
349       for (Map<String, RequirementAssignment> requirement : requirements) {
350         String requirementId = requirement.keySet().iterator().next();
351         if (requirementId.equals(ToscaConstants.LINK_REQUIREMENT_ID)) {
352           return true;
353         }
354       }
355     }
356     return false;
357   }
358 }