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