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