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