2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.composition;
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.sdc.logging.api.Logger;
26 import org.openecomp.sdc.logging.api.LoggerFactory;
27 import org.openecomp.sdc.common.errors.CoreException;
28 import org.openecomp.sdc.datatypes.error.ErrorLevel;
29 import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage;
30 import org.openecomp.sdc.logging.context.impl.MdcDataErrorMessage;
31 import org.openecomp.sdc.logging.types.LoggerConstants;
32 import org.openecomp.sdc.logging.types.LoggerErrorCode;
33 import org.openecomp.sdc.logging.types.LoggerErrorDescription;
34 import org.openecomp.sdc.logging.types.LoggerTragetServiceName;
35 import org.openecomp.sdc.tosca.datatypes.ToscaCapabilityType;
36 import org.openecomp.sdc.tosca.datatypes.ToscaFunctions;
37 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
38 import org.openecomp.sdc.tosca.datatypes.ToscaRelationshipType;
39 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
40 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
41 import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition;
42 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
43 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
44 import org.openecomp.sdc.tosca.errors.ToscaInvalidEntryNotFoundErrorBuilder;
45 import org.openecomp.sdc.tosca.errors.ToscaInvalidSubstituteNodeTemplateErrorBuilder;
46 import org.openecomp.sdc.tosca.errors.ToscaMissingSubstitutionMappingForReqCapErrorBuilder;
47 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
48 import org.openecomp.sdc.tosca.services.ToscaConstants;
49 import org.openecomp.sdc.tosca.services.impl.ToscaAnalyzerServiceImpl;
50 import org.openecomp.sdc.tosca.services.yamlutil.ToscaExtensionYamlUtil;
51 import org.openecomp.sdc.vendorsoftwareproduct.services.composition.CompositionDataExtractor;
52 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Component;
53 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ComponentData;
54 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.CompositionData;
55 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.ExtractCompositionDataContext;
56 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Network;
57 import org.openecomp.sdc.vendorsoftwareproduct.types.composition.Nic;
59 import java.util.ArrayList;
60 import java.util.HashMap;
61 import java.util.List;
63 import java.util.Optional;
65 public class CompositionDataExtractorImpl implements CompositionDataExtractor {
67 protected static Logger logger;
68 private static ToscaAnalyzerService toscaAnalyzerService;
69 private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage();
72 logger = LoggerFactory.getLogger(CompositionDataExtractorImpl.class);
73 toscaAnalyzerService = new ToscaAnalyzerServiceImpl();
77 * Extract service composition data composition data.
79 * @param toscaServiceModel the tosca service model
80 * @return the composition data
82 public CompositionData extractServiceCompositionData(ToscaServiceModel toscaServiceModel) {
85 mdcDataDebugMessage.debugEntryMessage(null);
87 ExtractCompositionDataContext context = new ExtractCompositionDataContext();
88 String entryDefinitionServiceTemplateFileName =
89 toscaServiceModel.getEntryDefinitionServiceTemplate();
90 ServiceTemplate entryDefinitionServiceTemplate =
91 toscaServiceModel.getServiceTemplates().get(entryDefinitionServiceTemplateFileName);
92 extractServiceCompositionData(entryDefinitionServiceTemplateFileName,
93 entryDefinitionServiceTemplate, toscaServiceModel, context);
95 CompositionData compositionData = new CompositionData();
96 compositionData.setNetworks(context.getNetworks());
97 compositionData.setComponents(context.getComponents());
99 mdcDataDebugMessage.debugExitMessage(null);
100 return compositionData;
103 private void extractServiceCompositionData(String serviceTemplateFileName,
104 ServiceTemplate serviceTemplate,
105 ToscaServiceModel toscaServiceModel,
106 ExtractCompositionDataContext context) {
107 if (context.getHandledServiceTemplates().contains(serviceTemplateFileName)) {
110 context.addNetworks(extractNetworks(serviceTemplate, toscaServiceModel));
111 extractComponents(serviceTemplate, toscaServiceModel, context);
112 handleSubstitution(serviceTemplate, toscaServiceModel, context);
113 context.addHandledServiceTemplates(serviceTemplateFileName);
116 private void handleSubstitution(ServiceTemplate serviceTemplate,
117 ToscaServiceModel toscaServiceModel,
118 ExtractCompositionDataContext context) {
121 mdcDataDebugMessage.debugEntryMessage(null);
123 Map<String, NodeTemplate> substitutableNodeTemplates =
124 toscaAnalyzerService.getSubstitutableNodeTemplates(serviceTemplate);
126 if (substitutableNodeTemplates != null) {
127 for (String substitutableNodeTemplateId : substitutableNodeTemplates.keySet()) {
128 handleSubstitutableNodeTemplate(serviceTemplate, toscaServiceModel,
129 substitutableNodeTemplateId,
130 substitutableNodeTemplates.get(substitutableNodeTemplateId), context);
134 mdcDataDebugMessage.debugExitMessage(null);
137 private void handleSubstitutableNodeTemplate(ServiceTemplate serviceTemplate,
138 ToscaServiceModel toscaServiceModel,
139 String substitutableNodeTemplateId,
140 NodeTemplate substitutableNodeTemplate,
141 ExtractCompositionDataContext context) {
144 mdcDataDebugMessage.debugEntryMessage(null);
146 ToscaExtensionYamlUtil toscaExtensionYamlUtil = new ToscaExtensionYamlUtil();
147 Optional<String> substituteServiceTemplateFileName = toscaAnalyzerService
148 .getSubstituteServiceTemplateName(substitutableNodeTemplateId, substitutableNodeTemplate);
149 if (!substituteServiceTemplateFileName.isPresent()) {
150 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
151 LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(),
152 LoggerErrorCode.DATA_ERROR.getErrorCode(),
153 LoggerErrorDescription.EXTRACT_COMPOSITION_DATA);
154 throw new CoreException(
155 new ToscaInvalidSubstituteNodeTemplateErrorBuilder(substitutableNodeTemplateId).build());
157 if (context.getHandledServiceTemplates().contains(substituteServiceTemplateFileName.get())) {
158 //each substitution is should be handled once, and will get the connection to the upper
159 // service level according to the first one which was processed
160 mdcDataDebugMessage.debugExitMessage(null);
164 ServiceTemplate substituteServiceTemplate =
165 toscaServiceModel.getServiceTemplates().get(substituteServiceTemplateFileName.get());
166 extractServiceCompositionData(substituteServiceTemplateFileName.get(),
167 substituteServiceTemplate, toscaServiceModel, context);
169 List<Map<String, RequirementAssignment>> substitutableRequirements =
170 substitutableNodeTemplate.getRequirements();
172 if (CollectionUtils.isEmpty(substitutableRequirements)) {
173 mdcDataDebugMessage.debugExitMessage(null);
177 for (Map<String, RequirementAssignment> substitutableReq : substitutableRequirements) {
178 substitutableReq.keySet().stream().filter(reqId -> {
179 RequirementAssignment reqAssignment = toscaExtensionYamlUtil
180 .yamlToObject(toscaExtensionYamlUtil.objectToYaml(substitutableReq.get(reqId)),
181 RequirementAssignment.class);
183 mdcDataDebugMessage.debugExitMessage(null);
184 return isLinkToNetworkRequirementAssignment(reqAssignment);
185 }).forEach(reqId -> {
186 RequirementAssignment linkToNetworkRequirement = toscaExtensionYamlUtil
187 .yamlToObject(toscaExtensionYamlUtil.objectToYaml(substitutableReq.get(reqId)),
188 RequirementAssignment.class);
189 String connectedNodeId = linkToNetworkRequirement.getNode();
190 Optional<NodeTemplate> connectedNodeTemplate =
191 toscaAnalyzerService.getNodeTemplateById(serviceTemplate, connectedNodeId);
193 if (connectedNodeTemplate.isPresent() && toscaAnalyzerService
194 .isTypeOf(connectedNodeTemplate.get(), ToscaNodeType.NATIVE_NETWORK,
195 serviceTemplate, toscaServiceModel)) {
196 Optional<Map.Entry<String, NodeTemplate>> mappedNodeTemplate = toscaAnalyzerService
197 .getSubstitutionMappedNodeTemplateByExposedReq(
198 substituteServiceTemplateFileName.get(), substituteServiceTemplate, reqId);
199 if (!mappedNodeTemplate.isPresent()) {
200 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
201 LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(),
202 LoggerErrorCode.DATA_ERROR.getErrorCode(),
203 LoggerErrorDescription.EXTRACT_COMPOSITION_DATA);
204 throw new CoreException(new ToscaMissingSubstitutionMappingForReqCapErrorBuilder(
205 ToscaMissingSubstitutionMappingForReqCapErrorBuilder.MappingExposedEntry
206 .REQUIREMENT, connectedNodeId).build());
209 if (toscaAnalyzerService.isTypeOf(mappedNodeTemplate.get().getValue(),
210 ToscaNodeType.NATIVE_NETWORK_PORT, serviceTemplate,
211 toscaServiceModel)) {
212 Nic port = context.getNics().get(mappedNodeTemplate.get().getKey());
214 port.setNetworkName(connectedNodeId);
217 "Different ports define for the same component which is used in different "
218 + "substitution service templates.");
221 } else if (!connectedNodeTemplate.isPresent()) {
222 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
223 LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(),
224 LoggerErrorCode.DATA_ERROR.getErrorCode(),
225 LoggerErrorDescription.EXTRACT_COMPOSITION_DATA);
226 throw new CoreException(
227 new ToscaInvalidEntryNotFoundErrorBuilder("Node Template", connectedNodeId).build());
233 private boolean isLinkToNetworkRequirementAssignment(RequirementAssignment requirement) {
234 return toscaAnalyzerService.isDesiredRequirementAssignment(requirement,
235 ToscaCapabilityType.NATIVE_NETWORK_LINKABLE, null,
236 ToscaRelationshipType.NATIVE_NETWORK_LINK_TO);
240 private void connectPortToNetwork(Nic port, NodeTemplate portNodeTemplate) {
243 mdcDataDebugMessage.debugEntryMessage(null);
245 List<RequirementAssignment> linkRequirementsToNetwork =
246 toscaAnalyzerService.getRequirements(portNodeTemplate, ToscaConstants.LINK_REQUIREMENT_ID);
248 //port is connected to one network
249 for (RequirementAssignment linkRequirementToNetwork : linkRequirementsToNetwork) {
250 port.setNetworkName(linkRequirementToNetwork.getNode());
253 mdcDataDebugMessage.debugExitMessage(null);
257 return Map with key - compute node template id, value - list of connected port node template id
259 private Map<String, List<String>> getComputeToPortsConnection(
260 Map<String, NodeTemplate> portNodeTemplates) {
263 mdcDataDebugMessage.debugEntryMessage(null);
265 Map<String, List<String>> computeToPortConnection = new HashMap<>();
266 if (MapUtils.isEmpty(portNodeTemplates)) {
267 return computeToPortConnection;
269 for (String portId : portNodeTemplates.keySet()) {
270 List<RequirementAssignment> bindingRequirementsToCompute = toscaAnalyzerService
271 .getRequirements(portNodeTemplates.get(portId), ToscaConstants.BINDING_REQUIREMENT_ID);
272 for (RequirementAssignment bindingRequirementToCompute : bindingRequirementsToCompute) {
273 computeToPortConnection
274 .putIfAbsent(bindingRequirementToCompute.getNode(), new ArrayList<>());
275 computeToPortConnection.get(bindingRequirementToCompute.getNode()).add(portId);
279 mdcDataDebugMessage.debugExitMessage(null);
280 return computeToPortConnection;
283 private void extractComponents(ServiceTemplate serviceTemplate,
284 ToscaServiceModel toscaServiceModel,
285 ExtractCompositionDataContext context) {
288 mdcDataDebugMessage.debugEntryMessage(null);
290 Map<String, NodeTemplate> computeNodeTemplates = toscaAnalyzerService
291 .getNodeTemplatesByType(serviceTemplate, ToscaNodeType.NATIVE_COMPUTE,
293 if (MapUtils.isEmpty(computeNodeTemplates)) {
296 Map<String, NodeTemplate> portNodeTemplates = toscaAnalyzerService
297 .getNodeTemplatesByType(serviceTemplate, ToscaNodeType.NATIVE_NETWORK_PORT,
299 Map<String, List<String>> computeToPortsConnection =
300 getComputeToPortsConnection(portNodeTemplates);
301 Map<String, List<String>> computesGroupedByType =
302 getNodeTemplatesGroupedByType(computeNodeTemplates);
304 computesGroupedByType.keySet()
307 !context.getCreatedComponents().contains(nodeType))
308 .forEach(nodeType -> extractComponent(serviceTemplate, computeToPortsConnection,
309 computesGroupedByType, nodeType, context));
311 mdcDataDebugMessage.debugExitMessage(null);
314 private void extractComponent(ServiceTemplate serviceTemplate,
315 Map<String, List<String>> computeToPortsConnection,
316 Map<String, List<String>> computesGroupedByType,
317 String computeNodeType,
318 ExtractCompositionDataContext context) {
319 ComponentData component = new ComponentData();
320 component.setName(computeNodeType);
321 component.setDisplayName(getComponentDisplayName(component.getName()));
322 component.setVfcCode(component.getDisplayName());
323 Component componentModel = new Component();
324 componentModel.setData(component);
326 String computeId = computesGroupedByType.get(computeNodeType).get(0);
327 List<String> connectedPortIds = computeToPortsConnection.get(computeId);
329 if (connectedPortIds != null) {
330 componentModel.setNics(new ArrayList<>());
331 for (String portId : connectedPortIds) {
332 Nic port = extractPort(serviceTemplate, portId);
333 componentModel.getNics().add(port);
334 context.addNic(portId, port);
337 context.addComponent(componentModel);
338 context.getCreatedComponents().add(computeNodeType);
341 private Nic extractPort(ServiceTemplate serviceTemplate, String portNodeTemplateId) {
342 Optional<NodeTemplate> portNodeTemplate =
343 toscaAnalyzerService.getNodeTemplateById(serviceTemplate, portNodeTemplateId);
344 if (portNodeTemplate.isPresent()) {
345 Nic port = new Nic();
346 port.setName(portNodeTemplateId);
347 connectPortToNetwork(port, portNodeTemplate.get());
350 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
351 LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(),
352 LoggerErrorCode.DATA_ERROR.getErrorCode(),
353 LoggerErrorDescription.EXTRACT_COMPOSITION_DATA);
354 throw new CoreException(
355 new ToscaInvalidEntryNotFoundErrorBuilder("Node Template", portNodeTemplateId).build());
360 private Map<String, List<String>> getNodeTemplatesGroupedByType(
361 Map<String, NodeTemplate> nodeTemplates) {
364 mdcDataDebugMessage.debugEntryMessage(null);
366 Map<String, List<String>> nodeTemplatesGrouped =
367 new HashMap<>(); //key - node type, value - list of node ids with this type
368 for (String nodeId : nodeTemplates.keySet()) {
369 String nodeType = nodeTemplates.get(nodeId).getType();
370 nodeTemplatesGrouped.putIfAbsent(nodeType, new ArrayList<>());
371 nodeTemplatesGrouped.get(nodeType).add(nodeId);
374 mdcDataDebugMessage.debugExitMessage(null);
375 return nodeTemplatesGrouped;
378 private List<Network> extractNetworks(ServiceTemplate serviceTemplate,
379 ToscaServiceModel toscaServiceModel) {
382 mdcDataDebugMessage.debugEntryMessage(null);
384 List<Network> networks = new ArrayList<>();
385 Map<String, NodeTemplate> networkNodeTemplates = toscaAnalyzerService
386 .getNodeTemplatesByType(serviceTemplate, ToscaNodeType.NATIVE_NETWORK,
388 if (MapUtils.isEmpty(networkNodeTemplates)) {
389 mdcDataDebugMessage.debugExitMessage(null);
392 for (String networkId : networkNodeTemplates.keySet()) {
393 Network network = new Network();
394 network.setName(networkId);
395 Optional<Boolean> networkDhcpValue =
396 getNetworkDhcpValue(serviceTemplate, networkNodeTemplates.get(networkId));
397 network.setDhcp(networkDhcpValue.isPresent() ? networkDhcpValue.get() : true);
398 networks.add(network);
401 mdcDataDebugMessage.debugExitMessage(null);
405 //dhcp default value is true
406 private Optional<Boolean> getNetworkDhcpValue(ServiceTemplate serviceTemplate,
407 NodeTemplate networkNodeTemplate) {
410 mdcDataDebugMessage.debugEntryMessage(null);
412 if (networkNodeTemplate == null) {
413 return Optional.empty();
415 if (networkNodeTemplate.getProperties() == null
416 || networkNodeTemplate.getProperties().get(ToscaConstants.DHCP_ENABLED_PROPERTY_NAME)
418 mdcDataDebugMessage.debugExitMessage(null);
419 return Optional.of(true);
423 networkNodeTemplate.getProperties().get(ToscaConstants.DHCP_ENABLED_PROPERTY_NAME);
424 if (dhcp instanceof String) {
425 mdcDataDebugMessage.debugExitMessage(null);
426 return Optional.of(Boolean.valueOf((String) dhcp));
427 } else if (dhcp instanceof Boolean) {
428 mdcDataDebugMessage.debugExitMessage(null);
429 return Optional.of((Boolean) dhcp);
430 } else if (dhcp instanceof Map) {
431 String inputParameterName =
432 (String) ((Map) dhcp).get(ToscaFunctions.GET_INPUT.getDisplayName());
433 if (inputParameterName != null) {
434 ParameterDefinition inputParameterDefinition =
435 serviceTemplate.getTopology_template().getInputs().get(inputParameterName);
436 if (inputParameterDefinition != null) {
437 if (inputParameterDefinition.get_default() != null) {
438 mdcDataDebugMessage.debugExitMessage(null);
439 return Optional.of(Boolean.valueOf(inputParameterDefinition.get_default().toString()));
442 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
443 LoggerTragetServiceName.EXTRACT_COMPOSITION_DATA, ErrorLevel.ERROR.name(),
444 LoggerErrorCode.DATA_ERROR.getErrorCode(),
445 LoggerErrorDescription.EXTRACT_COMPOSITION_DATA);
446 throw new CoreException(
447 new ToscaInvalidEntryNotFoundErrorBuilder("Input Parameter", inputParameterName)
453 mdcDataDebugMessage.debugExitMessage(null);
454 return Optional.of(true);
458 public String getComponentDisplayName(String componentName) {
459 if (componentName == null) {
462 String delimiterChar = ".";
463 if (componentName.contains(delimiterChar)) {
464 return componentName.substring(componentName.lastIndexOf(delimiterChar) + 1);
466 return componentName;