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