2 * Copyright © 2016-2018 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.openecomp.sdc.enrichment.impl.tosca;
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;
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;
31 import java.util.Objects;
32 import java.util.Optional;
34 import java.util.stream.Collectors;
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;
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);
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();
66 private static final Map<String, String> nodeTypeExternalNodeType =
67 Collections.unmodifiableMap(initializeNodeTypeExternalNodeType());
70 * Enrich tosca for port mirroring.
72 * @param toscaServiceModel the tosca service model
73 * @return the map Error descriptor map
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);
92 private void collectPorts(ServiceTemplate serviceTemplate) {
93 Map<String, NodeTemplate> nodeTemplates = DataModelUtil.getNodeTemplates(serviceTemplate);
94 if (Objects.isNull(nodeTemplates)) {
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));
103 portNodeTemplates.put(ToscaUtil.getServiceTemplateFileName(serviceTemplate),
104 serviceTemplatePortNodeTemplates);
105 //Get all linked internal ports from abstract node template link requirements
106 collectLinkedInternalPorts(nodeTemplates);
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);
119 private void handleSubstitutableNodeTemplate(List<String> abstractLinkedPortNodeTemplates,
120 NodeTemplate nodeTemplate) {
121 List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
122 if (Objects.isNull(requirements)) {
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);
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));
142 private void addCollectedPortsToAbstractServiceTemplatePortMap(NodeTemplate nodeTemplate,
143 List<String> abstractLinkedPortNodeTemplates) {
144 String substitutionServiceTemplateName;
145 if (Objects.isNull(nodeTemplate.getProperties())) {
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)) {
155 if (portNodeTemplateIdsFromAbstract.containsKey(substitutionServiceTemplateName)) {
156 List<String> portList = portNodeTemplateIdsFromAbstract.get(substitutionServiceTemplateName);
157 portList.addAll(abstractLinkedPortNodeTemplates);
158 portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, portList);
160 portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, abstractLinkedPortNodeTemplates);
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)) {
174 externalPorts.putIfAbsent(nodeTemplateId, nodeTemplate);
177 externalPortNodeTemplates.putIfAbsent(serviceTemplateFileName, externalPorts);
181 private void updateExternalPortNodeTemplate(NodeTemplate externalPortNodeTemplate) {
182 String currentPortNodeType = externalPortNodeTemplate.getType();
183 if (nodeTypeExternalNodeType.containsKey(currentPortNodeType)) {
184 externalPortNodeTemplate.setType(nodeTypeExternalNodeType.get(currentPortNodeType));
186 addPortMirroringCapability(externalPortNodeTemplate);
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)) {
196 handleExternalPortNodeTemplates(serviceTemplate, serviceTemplateExternalPortNodeTemplates);
197 addGlobalTypeImport(serviceTemplate);
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());
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);
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);
228 if (Objects.nonNull(portNodeTemplate.getRequirements())) {
229 setConnectionPointNfcType(portNodeTemplate, connectionPoint);
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);
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);
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);
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);
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);
276 private Set<String> getPortNodeTypes() {
277 return new HashSet<>(Arrays.asList(ToscaNodeType.NEUTRON_PORT,
278 ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE,
279 ToscaNodeType.CONTRAIL_PORT));
282 private boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
283 return Objects.nonNull(nodeTemplate.getDirectives())
284 && nodeTemplate.getDirectives()
285 .contains(ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
288 private boolean isInternalPort(String serviceTemplateFileName, String nodeTemplateId,
289 NodeTemplate nodeTemplate) {
290 return isAbstractInternalPort(serviceTemplateFileName, nodeTemplateId)
291 || isConcreteInternalPort(nodeTemplate);
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);
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)) {
307 for (Map<String, RequirementAssignment> requirement : requirements) {
308 String requirementId = requirement.keySet().iterator().next();
309 if (requirementId.equals(ToscaConstants.LINK_REQUIREMENT_ID)) {
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;