6598d1a6acc9e1c28afeb762107c45e5199ea2c4
[sdc.git] /
1 /*
2  * Copyright © 2016-2018 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 static org.openecomp.sdc.tosca.services.DataModelUtil.getClonedObject;
20 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME;
21 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_ID;
22
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32 import java.util.Optional;
33 import java.util.Set;
34 import java.util.stream.Collectors;
35
36 import org.apache.commons.collections4.CollectionUtils;
37 import org.apache.commons.collections4.MapUtils;
38 import org.onap.sdc.tosca.datatypes.model.Import;
39 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
40 import org.onap.sdc.tosca.datatypes.model.RequirementAssignment;
41 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
42 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
43 import org.openecomp.sdc.datatypes.error.ErrorMessage;
44 import org.openecomp.sdc.enrichment.impl.tosca.model.PortMirroringConnectionPointDescription;
45 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
46 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
47 import org.openecomp.sdc.tosca.services.DataModelUtil;
48 import org.openecomp.sdc.tosca.services.ToscaConstants;
49 import org.openecomp.sdc.tosca.services.ToscaUtil;
50 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
51 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
52
53 public class PortMirroringEnricher {
54   //Map of service template file name and map of all port node template ids, node template
55   private final Map<String, Map<String, NodeTemplate>> portNodeTemplates = new HashMap<>();
56   //Map of service template file name and map of external port node template ids, node template
57   private final Map<String, Map<String, NodeTemplate>> externalPortNodeTemplates = new HashMap<>();
58   //Map of substitution service template name and the list of ports with link requirement from the abstract
59   private final Map<String, List<String>> portNodeTemplateIdsFromAbstract = new HashMap<>();
60   private final Map<String, ServiceTemplate> globalTypesServiceTemplate =
61       GlobalTypesGenerator.getGlobalTypesServiceTemplate(OnboardingTypesEnum.ZIP);
62
63   private static final String ABSTRACT_LINK_REQUIREMENT_ID_PREFIX = ToscaConstants.LINK_REQUIREMENT_ID + "_";
64   private static final int ABSTRACT_LINK_REQUIREMENT_ID_PREFIX_LENGTH = ABSTRACT_LINK_REQUIREMENT_ID_PREFIX.length();
65
66   private static final Map<String, String> nodeTypeExternalNodeType =
67       Collections.unmodifiableMap(initializeNodeTypeExternalNodeType());
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();
87     //Handle external port changes
88     handleExternalPorts(toscaServiceModel);
89     return errors;
90   }
91
92   private void collectPorts(ServiceTemplate serviceTemplate) {
93     Map<String, NodeTemplate> nodeTemplates = DataModelUtil.getNodeTemplates(serviceTemplate);
94     if (Objects.isNull(nodeTemplates)) {
95       return;
96     }
97     //Get all concrete port node templates from the service template
98     Map<String, NodeTemplate> serviceTemplatePortNodeTemplates = nodeTemplates.entrySet().stream()
99         .filter(nodeTemplateEntry -> (Objects.nonNull(nodeTemplateEntry.getValue()))
100             && (isPortNodeTemplate(nodeTemplateEntry.getValue().getType())))
101         .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
102
103     portNodeTemplates.put(ToscaUtil.getServiceTemplateFileName(serviceTemplate),
104         serviceTemplatePortNodeTemplates);
105     //Get all linked internal ports from abstract node template link requirements
106     collectLinkedInternalPorts(nodeTemplates);
107   }
108
109   private void collectLinkedInternalPorts(Map<String, NodeTemplate> nodeTemplates) {
110     List<String> abstractLinkedPortNodeTemplates = new ArrayList<>();
111     for (Map.Entry<String, NodeTemplate> nodeTemplateEntry : nodeTemplates.entrySet()) {
112       NodeTemplate nodeTemplate = nodeTemplateEntry.getValue();
113       if (isSubstitutableNodeTemplate(nodeTemplate)) {
114         handleSubstitutableNodeTemplate(abstractLinkedPortNodeTemplates, nodeTemplate);
115       }
116     }
117   }
118
119   private void handleSubstitutableNodeTemplate(List<String> abstractLinkedPortNodeTemplates,
120                                                NodeTemplate nodeTemplate) {
121     List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
122     if (Objects.isNull(requirements)) {
123       return;
124     }
125     requirements.forEach(requirement -> addInternalPortToAbstractNode(requirement, abstractLinkedPortNodeTemplates));
126     if (CollectionUtils.isNotEmpty(abstractLinkedPortNodeTemplates)) {
127       //Populate a map of the substitution service templates and list of internal ports
128       addCollectedPortsToAbstractServiceTemplatePortMap(nodeTemplate,
129           abstractLinkedPortNodeTemplates);
130     }
131   }
132
133   private void addInternalPortToAbstractNode(Map<String, RequirementAssignment> requirement,
134                                              List<String> abstractLinkedPortNodeTemplates) {
135     String requirementId = requirement.keySet().iterator().next();
136     if (requirementId.startsWith(ABSTRACT_LINK_REQUIREMENT_ID_PREFIX)) {
137       //Collect port node template ids from the link requirement ids in the abstract node template
138       abstractLinkedPortNodeTemplates.add(requirementId.substring(ABSTRACT_LINK_REQUIREMENT_ID_PREFIX_LENGTH));
139     }
140   }
141
142   private void addCollectedPortsToAbstractServiceTemplatePortMap(NodeTemplate nodeTemplate,
143                                                                  List<String> abstractLinkedPortNodeTemplates) {
144     String substitutionServiceTemplateName;
145     if (Objects.isNull(nodeTemplate.getProperties())) {
146       return;
147     }
148     Map serviceTemplateFilter = (Map<String, Object>) nodeTemplate.getProperties()
149         .get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
150     substitutionServiceTemplateName = (String)
151         serviceTemplateFilter.get(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME);
152     if (Objects.isNull(substitutionServiceTemplateName)) {
153       return;
154     }
155     if (portNodeTemplateIdsFromAbstract.containsKey(substitutionServiceTemplateName)) {
156       List<String> portList = portNodeTemplateIdsFromAbstract.get(substitutionServiceTemplateName);
157       portList.addAll(abstractLinkedPortNodeTemplates);
158       portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, portList);
159     } else {
160       portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, abstractLinkedPortNodeTemplates);
161     }
162   }
163
164   private void filterExternalPorts() {
165     for (Map.Entry<String, Map<String, NodeTemplate>> portNodeTemplateEntry : portNodeTemplates.entrySet()) {
166       Map<String, NodeTemplate> externalPorts = new HashMap<>();
167       String serviceTemplateFileName = portNodeTemplateEntry.getKey();
168       Map<String, NodeTemplate> portNodeTemplateMap = portNodeTemplateEntry.getValue();
169       for (Map.Entry<String, NodeTemplate> portNodeTemplate : portNodeTemplateMap.entrySet()) {
170         String nodeTemplateId = portNodeTemplate.getKey();
171         NodeTemplate nodeTemplate = portNodeTemplate.getValue();
172         if (!isInternalPort(serviceTemplateFileName, nodeTemplateId, nodeTemplate)) {
173           //External Port
174           externalPorts.putIfAbsent(nodeTemplateId, nodeTemplate);
175         }
176       }
177       externalPortNodeTemplates.putIfAbsent(serviceTemplateFileName, externalPorts);
178     }
179   }
180
181   private void updateExternalPortNodeTemplate(NodeTemplate externalPortNodeTemplate) {
182     String currentPortNodeType = externalPortNodeTemplate.getType();
183     if (nodeTypeExternalNodeType.containsKey(currentPortNodeType)) {
184       externalPortNodeTemplate.setType(nodeTypeExternalNodeType.get(currentPortNodeType));
185     }
186     addPortMirroringCapability(externalPortNodeTemplate);
187   }
188
189   private void handleExternalPorts(ToscaServiceModel toscaServiceModel) {
190     for (Map.Entry<String, Map<String, NodeTemplate>> entry : externalPortNodeTemplates.entrySet()) {
191       ServiceTemplate serviceTemplate = toscaServiceModel.getServiceTemplates().get(entry.getKey());
192       Map<String, NodeTemplate> serviceTemplateExternalPortNodeTemplates = entry.getValue();
193       if (MapUtils.isEmpty(serviceTemplateExternalPortNodeTemplates)) {
194         continue;
195       }
196       handleExternalPortNodeTemplates(serviceTemplate, serviceTemplateExternalPortNodeTemplates);
197       addGlobalTypeImport(serviceTemplate);
198     }
199   }
200
201   private void handleExternalPortNodeTemplates(ServiceTemplate serviceTemplate,
202                                                Map<String, NodeTemplate> externalPortNodeTemplates) {
203     for (Map.Entry<String, NodeTemplate> externalNodeTemplate : externalPortNodeTemplates.entrySet()) {
204       updateExternalPortNodeTemplate(externalNodeTemplate.getValue());
205       if (Objects.nonNull(DataModelUtil.getSubstitutionMappings(serviceTemplate))) {
206         //Add port mirroring capability to substitution mapping for external ports
207         addPortMirroringSubstitutionMappingCapability(serviceTemplate, externalNodeTemplate.getKey());
208       }
209     }
210   }
211
212   private void addPortMirroringSubstitutionMappingCapability(ServiceTemplate serviceTemplate,
213                                                              String externalPortNodeTemplateId) {
214     List<String> portMirroringCapability = new LinkedList<>();
215     portMirroringCapability.add(externalPortNodeTemplateId);
216     portMirroringCapability.add(PORT_MIRRORING_CAPABILITY_ID);
217     String substitutionMappingCapabilityId = PORT_MIRRORING_CAPABILITY_ID + "_" + externalPortNodeTemplateId;
218     DataModelUtil.addSubstitutionMappingCapability(serviceTemplate,
219         substitutionMappingCapabilityId, portMirroringCapability);
220   }
221
222   private void addPortMirroringCapability(NodeTemplate portNodeTemplate) {
223     Map<String, Object> portMirroringCapabilityProperties = new HashMap<>();
224     PortMirroringConnectionPointDescription connectionPoint = new PortMirroringConnectionPointDescription();
225     if (Objects.nonNull(portNodeTemplate.getProperties())) {
226       setConnectionPointNetworkRole(portNodeTemplate, connectionPoint);
227     }
228     if (Objects.nonNull(portNodeTemplate.getRequirements())) {
229       setConnectionPointNfcType(portNodeTemplate, connectionPoint);
230     }
231     if (!connectionPoint.isEmpty()) {
232       portMirroringCapabilityProperties.put(PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME, connectionPoint);
233       DataModelUtil.addNodeTemplateCapability(portNodeTemplate,
234           PORT_MIRRORING_CAPABILITY_ID, portMirroringCapabilityProperties, null);
235     }
236   }
237
238   private void setConnectionPointNfcType(NodeTemplate portNodeTemplate,
239                                          PortMirroringConnectionPointDescription connectionPoint) {
240     //Get NFC_Type from the binding requirement node
241     Optional<List<RequirementAssignment>> requirementAssignment =
242         DataModelUtil.getRequirementAssignment(portNodeTemplate.getRequirements(), ToscaConstants
243             .BINDING_REQUIREMENT_ID);
244     if (requirementAssignment.isPresent()) {
245       RequirementAssignment bindingRequirementAssignment = requirementAssignment.get().get(0);
246       String node = bindingRequirementAssignment.getNode();
247       connectionPoint.setNfc_type(node);
248     }
249   }
250
251   private void setConnectionPointNetworkRole(NodeTemplate portNodeTemplate,
252                                              PortMirroringConnectionPointDescription connectionPoint) {
253     Object networkRolePropertyValue =
254         portNodeTemplate.getProperties().get(ToscaConstants.PORT_NETWORK_ROLE_PROPERTY_NAME);
255     if (Objects.nonNull(networkRolePropertyValue)) {
256       Object portMirroringNetworkRolePropertyVal = getClonedObject(networkRolePropertyValue);
257       connectionPoint.setNetwork_role(portMirroringNetworkRolePropertyVal);
258     }
259   }
260
261   private void addGlobalTypeImport(ServiceTemplate serviceTemplate) {
262     List<Map<String, Import>> imports = serviceTemplate.getImports();
263     Map<String, Import> openecompIndexImport = new HashMap<>();
264     openecompIndexImport.put("openecomp_index",
265         HeatToToscaUtil.createServiceTemplateImport(globalTypesServiceTemplate
266             .get("openecomp/_index.yml")));
267     imports.add(openecompIndexImport);
268   }
269
270   private boolean isPortNodeTemplate(String nodeType) {
271     //Check if node corresponds to a concrete port node
272     Set<String> portNodeTypes = getPortNodeTypes();
273     return Objects.nonNull(nodeType) && portNodeTypes.contains(nodeType);
274   }
275
276   private Set<String> getPortNodeTypes() {
277     return new HashSet<>(Arrays.asList(ToscaNodeType.NEUTRON_PORT,
278         ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE,
279         ToscaNodeType.CONTRAIL_PORT));
280   }
281
282   private boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
283     return Objects.nonNull(nodeTemplate.getDirectives())
284         && nodeTemplate.getDirectives()
285         .contains(ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
286   }
287
288   private boolean isInternalPort(String serviceTemplateFileName, String nodeTemplateId,
289                                  NodeTemplate nodeTemplate) {
290     return isAbstractInternalPort(serviceTemplateFileName, nodeTemplateId)
291         || isConcreteInternalPort(nodeTemplate);
292   }
293
294   private boolean isAbstractInternalPort(String serviceTemplateFileName, String nodeTemplateId) {
295     //Check if port corresponds to an abstract internal port
296     return portNodeTemplateIdsFromAbstract.containsKey(serviceTemplateFileName)
297         && portNodeTemplateIdsFromAbstract.get(serviceTemplateFileName).contains(nodeTemplateId);
298   }
299
300
301   private boolean isConcreteInternalPort(NodeTemplate nodeTemplate) {
302     //Check if node template contains a link requirement
303     List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
304     if (Objects.isNull(requirements)) {
305       return false;
306     }
307     for (Map<String, RequirementAssignment> requirement : requirements) {
308       String requirementId = requirement.keySet().iterator().next();
309       if (requirementId.equals(ToscaConstants.LINK_REQUIREMENT_ID)) {
310         return true;
311       }
312     }
313     return false;
314   }
315
316   private static Map<String, String> initializeNodeTypeExternalNodeType() {
317     Map<String, String> nodeTypeExternalNodeType = new HashMap<>(3);
318     nodeTypeExternalNodeType.put(ToscaNodeType.CONTRAIL_PORT, ToscaNodeType.EXTERNAL_CONTRAIL_PORT);
319     nodeTypeExternalNodeType.put(ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE, ToscaNodeType.EXTERNAL_VMI_PORT);
320     nodeTypeExternalNodeType.put(ToscaNodeType.NEUTRON_PORT, ToscaNodeType.EXTERNAL_NEUTRON_PORT);
321     return nodeTypeExternalNodeType;
322   }
323 }