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.
16 package org.openecomp.sdc.enrichment.impl.tosca;
18 import static org.openecomp.sdc.tosca.services.DataModelUtil.getClonedObject;
19 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME;
20 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_ID;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.collect.ImmutableSet;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.LinkedList;
27 import java.util.List;
29 import java.util.Objects;
30 import java.util.Optional;
32 import java.util.stream.Collectors;
33 import org.apache.commons.collections4.CollectionUtils;
34 import org.apache.commons.collections4.MapUtils;
35 import org.onap.sdc.tosca.datatypes.model.Import;
36 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
37 import org.onap.sdc.tosca.datatypes.model.RequirementAssignment;
38 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
39 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
40 import org.openecomp.sdc.datatypes.error.ErrorMessage;
41 import org.openecomp.sdc.enrichment.impl.tosca.model.PortMirroringConnectionPointDescription;
42 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
43 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
44 import org.openecomp.sdc.tosca.services.DataModelUtil;
45 import org.openecomp.sdc.tosca.services.ToscaConstants;
46 import org.openecomp.sdc.tosca.services.ToscaUtil;
47 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
48 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
50 public class PortMirroringEnricher {
52 private static final String ABSTRACT_LINK_REQUIREMENT_ID_PREFIX = ToscaConstants.LINK_REQUIREMENT_ID + "_";
53 private static final int ABSTRACT_LINK_REQUIREMENT_ID_PREFIX_LENGTH = ABSTRACT_LINK_REQUIREMENT_ID_PREFIX.length();
54 private static final Map<String, String> nodeTypeExternalNodeType = initializeNodeTypeExternalNodeType();
55 //Map of service template file name and map of all port node template ids, node template
56 private final Map<String, Map<String, NodeTemplate>> portNodeTemplates = new HashMap<>();
57 //Map of service template file name and map of external port node template ids, node template
58 private final Map<String, Map<String, NodeTemplate>> externalPortNodeTemplates = new HashMap<>();
59 //Map of substitution service template name and the list of ports with link requirement from the abstract
60 private final Map<String, List<String>> portNodeTemplateIdsFromAbstract = new HashMap<>();
61 private final Map<String, ServiceTemplate> globalTypesServiceTemplate = GlobalTypesGenerator
62 .getGlobalTypesServiceTemplate(OnboardingTypesEnum.ZIP);
64 private static ImmutableMap<String, String> initializeNodeTypeExternalNodeType() {
65 return ImmutableMap.<String, String>builder().put(ToscaNodeType.CONTRAIL_PORT, ToscaNodeType.EXTERNAL_CONTRAIL_PORT)
66 .put(ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE, ToscaNodeType.EXTERNAL_VMI_PORT)
67 .put(ToscaNodeType.NEUTRON_PORT, ToscaNodeType.EXTERNAL_NEUTRON_PORT).build();
71 * Enrich tosca for port mirroring.
73 * @param toscaServiceModel the tosca service model
74 * @return the map Error descriptor map
76 public Map<String, List<ErrorMessage>> enrich(ToscaServiceModel toscaServiceModel) {
77 Map<String, List<ErrorMessage>> errors = new HashMap<>();
78 Map<String, ServiceTemplate> serviceTemplates = toscaServiceModel.getServiceTemplates();
79 serviceTemplates.entrySet().stream()
80 //Skipping the service templates which do not contain topology template
81 .filter(serviceTemplateEntry -> serviceTemplateEntry.getValue().getTopology_template() != null).forEach(serviceTemplateEntry ->
82 //Collect all the ports across all the service templates
83 collectPorts(serviceTemplateEntry.getValue()));
84 //Collect External ports from the list of all ports collected above
85 filterExternalPorts();
86 //Handle external port changes
87 handleExternalPorts(toscaServiceModel);
91 private void collectPorts(ServiceTemplate serviceTemplate) {
92 Map<String, NodeTemplate> nodeTemplates = DataModelUtil.getNodeTemplates(serviceTemplate);
93 if (Objects.isNull(nodeTemplates)) {
96 //Get all concrete port node templates from the service template
97 Map<String, NodeTemplate> serviceTemplatePortNodeTemplates = nodeTemplates.entrySet().stream().filter(
98 nodeTemplateEntry -> (Objects.nonNull(nodeTemplateEntry.getValue())) && (isPortNodeTemplate(nodeTemplateEntry.getValue().getType())))
99 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
100 portNodeTemplates.put(ToscaUtil.getServiceTemplateFileName(serviceTemplate), serviceTemplatePortNodeTemplates);
101 //Get all linked internal ports from abstract node template link requirements
102 collectLinkedInternalPorts(nodeTemplates);
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);
115 private void handleSubstitutableNodeTemplate(List<String> abstractLinkedPortNodeTemplates, NodeTemplate nodeTemplate) {
116 List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
117 if (Objects.isNull(requirements)) {
120 requirements.forEach(requirement -> addInternalPortToAbstractNode(requirement, abstractLinkedPortNodeTemplates));
121 if (CollectionUtils.isNotEmpty(abstractLinkedPortNodeTemplates)) {
122 //Populate a map of the substitution service templates and list of internal ports
123 addCollectedPortsToAbstractServiceTemplatePortMap(nodeTemplate, abstractLinkedPortNodeTemplates);
127 private void addInternalPortToAbstractNode(Map<String, RequirementAssignment> requirement, List<String> abstractLinkedPortNodeTemplates) {
128 String requirementId = requirement.keySet().iterator().next();
129 if (requirementId.startsWith(ABSTRACT_LINK_REQUIREMENT_ID_PREFIX)) {
130 //Collect port node template ids from the link requirement ids in the abstract node template
131 abstractLinkedPortNodeTemplates.add(requirementId.substring(ABSTRACT_LINK_REQUIREMENT_ID_PREFIX_LENGTH));
135 private void addCollectedPortsToAbstractServiceTemplatePortMap(NodeTemplate nodeTemplate, List<String> abstractLinkedPortNodeTemplates) {
136 String substitutionServiceTemplateName;
137 if (Objects.isNull(nodeTemplate.getProperties())) {
140 Map serviceTemplateFilter = (Map<String, Object>) nodeTemplate.getProperties().get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
141 substitutionServiceTemplateName = (String) serviceTemplateFilter.get(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME);
142 if (Objects.isNull(substitutionServiceTemplateName)) {
145 if (portNodeTemplateIdsFromAbstract.containsKey(substitutionServiceTemplateName)) {
146 List<String> portList = portNodeTemplateIdsFromAbstract.get(substitutionServiceTemplateName);
147 portList.addAll(abstractLinkedPortNodeTemplates);
148 portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, portList);
150 portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, abstractLinkedPortNodeTemplates);
154 private void filterExternalPorts() {
155 for (Map.Entry<String, Map<String, NodeTemplate>> portNodeTemplateEntry : portNodeTemplates.entrySet()) {
156 Map<String, NodeTemplate> externalPorts = new HashMap<>();
157 String serviceTemplateFileName = portNodeTemplateEntry.getKey();
158 Map<String, NodeTemplate> portNodeTemplateMap = portNodeTemplateEntry.getValue();
159 for (Map.Entry<String, NodeTemplate> portNodeTemplate : portNodeTemplateMap.entrySet()) {
160 String nodeTemplateId = portNodeTemplate.getKey();
161 NodeTemplate nodeTemplate = portNodeTemplate.getValue();
162 if (!isInternalPort(serviceTemplateFileName, nodeTemplateId, nodeTemplate)) {
164 externalPorts.putIfAbsent(nodeTemplateId, nodeTemplate);
167 externalPortNodeTemplates.putIfAbsent(serviceTemplateFileName, externalPorts);
171 private void updateExternalPortNodeTemplate(NodeTemplate externalPortNodeTemplate) {
172 String currentPortNodeType = externalPortNodeTemplate.getType();
173 if (nodeTypeExternalNodeType.containsKey(currentPortNodeType)) {
174 externalPortNodeTemplate.setType(nodeTypeExternalNodeType.get(currentPortNodeType));
176 addPortMirroringCapability(externalPortNodeTemplate);
179 private void handleExternalPorts(ToscaServiceModel toscaServiceModel) {
180 for (Map.Entry<String, Map<String, NodeTemplate>> entry : externalPortNodeTemplates.entrySet()) {
181 ServiceTemplate serviceTemplate = toscaServiceModel.getServiceTemplates().get(entry.getKey());
182 Map<String, NodeTemplate> serviceTemplateExternalPortNodeTemplates = entry.getValue();
183 if (MapUtils.isEmpty(serviceTemplateExternalPortNodeTemplates)) {
186 handleExternalPortNodeTemplates(serviceTemplate, serviceTemplateExternalPortNodeTemplates);
187 addGlobalTypeImport(serviceTemplate);
191 private void handleExternalPortNodeTemplates(ServiceTemplate serviceTemplate, Map<String, NodeTemplate> externalPortNodeTemplates) {
192 for (Map.Entry<String, NodeTemplate> externalNodeTemplate : externalPortNodeTemplates.entrySet()) {
193 updateExternalPortNodeTemplate(externalNodeTemplate.getValue());
194 if (Objects.nonNull(DataModelUtil.getSubstitutionMappings(serviceTemplate))) {
195 //Add port mirroring capability to substitution mapping for external ports
196 addPortMirroringSubstitutionMappingCapability(serviceTemplate, externalNodeTemplate.getKey());
201 private void addPortMirroringSubstitutionMappingCapability(ServiceTemplate serviceTemplate, String externalPortNodeTemplateId) {
202 List<String> portMirroringCapability = new LinkedList<>();
203 portMirroringCapability.add(externalPortNodeTemplateId);
204 portMirroringCapability.add(PORT_MIRRORING_CAPABILITY_ID);
205 String substitutionMappingCapabilityId = PORT_MIRRORING_CAPABILITY_ID + "_" + externalPortNodeTemplateId;
206 DataModelUtil.addSubstitutionMappingCapability(serviceTemplate, substitutionMappingCapabilityId, portMirroringCapability);
209 private void addPortMirroringCapability(NodeTemplate portNodeTemplate) {
210 Map<String, Object> portMirroringCapabilityProperties = new HashMap<>();
211 PortMirroringConnectionPointDescription connectionPoint = new PortMirroringConnectionPointDescription();
212 if (Objects.nonNull(portNodeTemplate.getProperties())) {
213 setConnectionPointNetworkRole(portNodeTemplate, connectionPoint);
215 if (Objects.nonNull(portNodeTemplate.getRequirements())) {
216 setConnectionPointNfcType(portNodeTemplate, connectionPoint);
218 if (!connectionPoint.isEmpty()) {
219 portMirroringCapabilityProperties.put(PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME, connectionPoint);
220 DataModelUtil.addNodeTemplateCapability(portNodeTemplate, PORT_MIRRORING_CAPABILITY_ID, portMirroringCapabilityProperties, null);
224 private void setConnectionPointNfcType(NodeTemplate portNodeTemplate, PortMirroringConnectionPointDescription connectionPoint) {
225 //Get NFC_Type from the binding requirement node
226 Optional<List<RequirementAssignment>> requirementAssignment = DataModelUtil
227 .getRequirementAssignment(portNodeTemplate.getRequirements(), ToscaConstants.BINDING_REQUIREMENT_ID);
228 if (requirementAssignment.isPresent()) {
229 RequirementAssignment bindingRequirementAssignment = requirementAssignment.get().get(0);
230 String node = bindingRequirementAssignment.getNode();
231 connectionPoint.setNfc_naming_code(node);
235 private void setConnectionPointNetworkRole(NodeTemplate portNodeTemplate, PortMirroringConnectionPointDescription connectionPoint) {
236 Object networkRolePropertyValue = portNodeTemplate.getProperties().get(ToscaConstants.PORT_NETWORK_ROLE_PROPERTY_NAME);
237 if (Objects.nonNull(networkRolePropertyValue)) {
238 Object portMirroringNetworkRolePropertyVal = getClonedObject(networkRolePropertyValue);
239 connectionPoint.setNetwork_role(portMirroringNetworkRolePropertyVal);
243 private void addGlobalTypeImport(ServiceTemplate serviceTemplate) {
244 List<Map<String, Import>> imports = serviceTemplate.getImports();
245 Map<String, Import> openecompIndexImport = new HashMap<>();
247 .put("openecomp_index", HeatToToscaUtil.createServiceTemplateImport(globalTypesServiceTemplate.get("openecomp/_index.yml")));
248 imports.add(openecompIndexImport);
251 private boolean isPortNodeTemplate(String nodeType) {
252 //Check if node corresponds to a concrete port node
253 Set<String> portNodeTypes = getPortNodeTypes();
254 return Objects.nonNull(nodeType) && portNodeTypes.contains(nodeType);
257 private Set<String> getPortNodeTypes() {
258 return ImmutableSet.of(ToscaNodeType.NEUTRON_PORT, ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE, ToscaNodeType.CONTRAIL_PORT);
261 private boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
262 return Objects.nonNull(nodeTemplate.getDirectives()) && nodeTemplate.getDirectives()
263 .contains(ToscaConstants.NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
266 private boolean isInternalPort(String serviceTemplateFileName, String nodeTemplateId, NodeTemplate nodeTemplate) {
267 return isAbstractInternalPort(serviceTemplateFileName, nodeTemplateId) || isConcreteInternalPort(nodeTemplate);
270 private boolean isAbstractInternalPort(String serviceTemplateFileName, String nodeTemplateId) {
271 //Check if port corresponds to an abstract internal port
272 return portNodeTemplateIdsFromAbstract.containsKey(serviceTemplateFileName) && portNodeTemplateIdsFromAbstract.get(serviceTemplateFileName)
273 .contains(nodeTemplateId);
276 private boolean isConcreteInternalPort(NodeTemplate nodeTemplate) {
277 //Check if node template contains a link requirement
278 List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
279 if (Objects.isNull(requirements)) {
282 for (Map<String, RequirementAssignment> requirement : requirements) {
283 String requirementId = requirement.keySet().iterator().next();
284 if (requirementId.equals(ToscaConstants.LINK_REQUIREMENT_ID)) {