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