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