Support TOSCA functions in Node Filters
[sdc.git] / catalog-be-plugins / etsi-nfv-nsd-csar-plugin / src / main / java / org / openecomp / sdc / be / plugins / etsi / nfv / nsd / generator / NsDescriptorGeneratorImpl.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2020 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        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.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19 package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator;
20
21 import fj.data.Either;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30 import java.util.Optional;
31 import java.util.stream.Collectors;
32 import org.apache.commons.collections4.CollectionUtils;
33 import org.apache.commons.collections4.MapUtils;
34 import org.openecomp.sdc.be.config.ConfigurationManager;
35 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
36 import org.openecomp.sdc.be.model.Component;
37 import org.openecomp.sdc.be.datatypes.enums.ConstraintType;
38 import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.NsdException;
39 import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.Nsd;
40 import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.VnfDescriptor;
41 import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.tosca.yaml.ToscaTemplateYamlGenerator;
42 import org.openecomp.sdc.be.tosca.ToscaError;
43 import org.openecomp.sdc.be.tosca.ToscaExportHandler;
44 import org.openecomp.sdc.be.tosca.model.SubstitutionMapping;
45 import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
46 import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
47 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
48 import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraint;
49 import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraintValidValues;
50 import org.openecomp.sdc.be.tosca.model.ToscaRequirement;
51 import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
52 import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement;
53 import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56 import org.springframework.beans.factory.ObjectProvider;
57 import org.springframework.beans.factory.config.BeanDefinition;
58 import org.springframework.context.annotation.Scope;
59
60 @org.springframework.stereotype.Component("nsDescriptorGenerator")
61 @Scope(BeanDefinition.SCOPE_PROTOTYPE)
62 public class NsDescriptorGeneratorImpl implements NsDescriptorGenerator {
63
64     private static final Logger LOGGER = LoggerFactory.getLogger(NsDescriptorGeneratorImpl.class);
65     private static final String TOSCA_VERSION = "tosca_simple_yaml_1_1";
66     private static final String NS_TOSCA_TYPE = "tosca.nodes.nfv.NS";
67     private static final List<Map<String, Map<String, String>>> DEFAULT_IMPORTS = ConfigurationManager.getConfigurationManager().getConfiguration()
68         .getDefaultImports();
69     private static final List<String> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TYPE = Arrays
70         .asList("cds_model_name", "cds_model_version", "skip_post_instantiation_configuration", "controller_actor");
71     private static final List<String> ETSI_SOL_NSD_NS_NODE_TYPE_PROPERTIES = Arrays
72         .asList("descriptor_id", "designer", "version", "name", "invariant_id", "flavour_id", "ns_profile", "service_availability_level");
73     private static final List<String> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TEMPLATE = Arrays
74         .asList("nf_function", "nf_role", "nf_naming_code", "nf_type", "nf_naming", "availability_zone_max_count", "min_instances", "max_instances",
75             "multi_stage_design", "sdnc_model_name", "sdnc_model_version", "sdnc_artifact_name", "skip_post_instantiation_configuration",
76             "controller_actor");
77     private final ToscaExportHandler toscaExportHandler;
78     private final ObjectProvider<ToscaTemplateYamlGenerator> toscaTemplateYamlGeneratorProvider;
79
80     public NsDescriptorGeneratorImpl(final ToscaExportHandler toscaExportHandler,
81                                      final ObjectProvider<ToscaTemplateYamlGenerator> toscaTemplateYamlGeneratorProvider) {
82         this.toscaExportHandler = toscaExportHandler;
83         this.toscaTemplateYamlGeneratorProvider = toscaTemplateYamlGeneratorProvider;
84     }
85
86     public Optional<Nsd> generate(final Component component, final List<VnfDescriptor> vnfDescriptorList) throws NsdException {
87         if (!ComponentTypeEnum.SERVICE.equals(component.getComponentType())) {
88             return Optional.empty();
89         }
90         final ToscaTemplate toscaTemplate = createNetworkServiceDescriptor(component, vnfDescriptorList);
91         final ToscaNodeType nsNodeType = toscaTemplate.getNode_types().values().stream()
92             .filter(toscaNodeType -> NS_TOSCA_TYPE.equals(toscaNodeType.getDerived_from())).findFirst().orElse(null);
93         if (nsNodeType == null) {
94             return Optional.empty();
95         }
96         return Optional.of(buildNsd(toscaTemplate, nsNodeType));
97     }
98
99     private Nsd buildNsd(final ToscaTemplate toscaTemplate, final ToscaNodeType nsNodeType) {
100         final Nsd nsd = new Nsd();
101         nsd.setDesigner(getProperty(nsNodeType, Nsd.DESIGNER_PROPERTY));
102         nsd.setVersion(getProperty(nsNodeType, Nsd.VERSION_PROPERTY));
103         nsd.setName(getProperty(nsNodeType, Nsd.NAME_PROPERTY));
104         nsd.setInvariantId(getProperty(nsNodeType, Nsd.INVARIANT_ID_PROPERTY));
105         final ToscaTemplateYamlGenerator yamlParserProvider = toscaTemplateYamlGeneratorProvider.getObject(toscaTemplate);
106         final byte[] contents = yamlParserProvider.parseToYamlString().getBytes();
107         nsd.setContents(contents);
108         final List<String> interfaceImplementations = getInterfaceImplementations(toscaTemplate);
109         nsd.setArtifactReferences(interfaceImplementations);
110         return nsd;
111     }
112
113     private List<String> getInterfaceImplementations(final ToscaTemplate template) {
114         if (template.getTopology_template().getNode_templates() == null) {
115             return Collections.emptyList();
116         }
117         final List<String> interfaceImplementations = new ArrayList<>();
118         final Collection<ToscaNodeTemplate> nodeTemplates = template.getTopology_template().getNode_templates().values();
119         nodeTemplates.stream().filter(toscaNodeTemplate -> toscaNodeTemplate.getInterfaces() != null).forEach(
120             toscaNodeTemplate -> toscaNodeTemplate.getInterfaces().values()
121                 .forEach(interfaceInstance -> interfaceImplementations.addAll(getInterfaceImplementations(interfaceInstance))));
122         return interfaceImplementations;
123     }
124
125     private Collection<String> getInterfaceImplementations(final Object interfaceInstance) {
126         final Collection<String> interfaceImplementations = new ArrayList<>();
127         if (interfaceInstance instanceof Map) {
128             for (final Object value : ((Map<?, ?>) interfaceInstance).values()) {
129                 if (value instanceof Map && ((Map<?, ?>) value).get("implementation") != null) {
130                     interfaceImplementations.add(((Map<?, ?>) value).get("implementation").toString());
131                 }
132             }
133         }
134         return interfaceImplementations;
135     }
136
137     private String getProperty(final ToscaNodeType nodeType, final String propertyName) {
138         final ToscaProperty toscaProperty = nodeType.getProperties().get(propertyName);
139         final String errorMsg = String.format("Property '%s' must be defined and must have a valid values constraint", propertyName);
140         final String returnValueOnError = "unknown";
141         if (toscaProperty == null || CollectionUtils.isEmpty(toscaProperty.getConstraints())) {
142             LOGGER.error(errorMsg);
143             return returnValueOnError;
144         }
145         final ToscaPropertyConstraint toscaPropertyConstraint = toscaProperty.getConstraints().get(0);
146         if (ConstraintType.VALID_VALUES != toscaPropertyConstraint.getConstraintType()) {
147             LOGGER.error(errorMsg);
148             return returnValueOnError;
149         }
150         final ToscaPropertyConstraintValidValues validValuesConstraint = (ToscaPropertyConstraintValidValues) toscaPropertyConstraint;
151         final List<String> validValues = validValuesConstraint.getValidValues();
152         if (CollectionUtils.isEmpty(validValues)) {
153             LOGGER.error(errorMsg);
154             return returnValueOnError;
155         }
156         return validValues.get(0);
157     }
158
159     private ToscaTemplate createNetworkServiceDescriptor(final Component component, final List<VnfDescriptor> vnfDescriptorList) throws NsdException {
160         final ToscaTemplate componentToscaTemplate = parseToToscaTemplate(component);
161         final ToscaTemplate componentToscaTemplateInterface = exportComponentInterfaceAsToscaTemplate(component);
162         final Entry<String, ToscaNodeType> firstNodeTypeEntry = componentToscaTemplateInterface.getNode_types().entrySet().stream().findFirst()
163             .orElse(null);
164         if (firstNodeTypeEntry == null) {
165             throw new NsdException("Could not find abstract Service type");
166         }
167         final String nsNodeTypeName = firstNodeTypeEntry.getKey();
168         final ToscaNodeType nsNodeType = firstNodeTypeEntry.getValue();
169         final Map<String, ToscaNodeType> nodeTypeMap = new HashMap<>();
170         nodeTypeMap.put(nsNodeTypeName, createEtsiSolNsNodeType(nsNodeType, componentToscaTemplate));
171         if (componentToscaTemplate.getNode_types() == null) {
172             componentToscaTemplate.setNode_types(nodeTypeMap);
173         } else {
174             componentToscaTemplate.getNode_types().putAll(nodeTypeMap);
175         }
176         handleNodeTemplates(componentToscaTemplate);
177         removeOnapAndEtsiNsdPropertiesFromInputs(componentToscaTemplate);
178         handleSubstitutionMappings(componentToscaTemplate, nsNodeTypeName);
179         final Map<String, ToscaNodeTemplate> nodeTemplates = new HashMap<>();
180         nodeTemplates.put(nsNodeTypeName,
181             createNodeTemplateForNsNodeType(nsNodeTypeName, componentToscaTemplateInterface.getNode_types().get(nsNodeTypeName)));
182         if (componentToscaTemplate.getTopology_template().getNode_templates() == null) {
183             componentToscaTemplate.getTopology_template().setNode_templates(nodeTemplates);
184         } else {
185             setNodeTemplateTypesForVnfs(componentToscaTemplate, vnfDescriptorList);
186             componentToscaTemplate.getTopology_template().getNode_templates().putAll(nodeTemplates);
187         }
188         removeOnapMetaData(componentToscaTemplate);
189         setDefaultImportsForEtsiSolNsNsd(componentToscaTemplate, vnfDescriptorList);
190         return componentToscaTemplate;
191     }
192
193     private void handleSubstitutionMappings(final ToscaTemplate componentToscaTemplate, final String nsNodeTypeName) {
194         final SubstitutionMapping substitutionMapping = new SubstitutionMapping();
195         substitutionMapping.setNode_type(nsNodeTypeName);
196         final SubstitutionMapping onapSubstitutionMapping = componentToscaTemplate.getTopology_template().getSubstitution_mappings();
197         if (onapSubstitutionMapping != null && onapSubstitutionMapping.getRequirements() != null) {
198             substitutionMapping.setRequirements(adjustRequirementNamesToMatchVnfd(onapSubstitutionMapping.getRequirements()));
199         }
200         componentToscaTemplate.getTopology_template().setSubstitution_mappings(substitutionMapping);
201     }
202
203     private Map<String, String[]> adjustRequirementNamesToMatchVnfd(final Map<String, String[]> requirements) {
204         for (final Map.Entry<String, String[]> entry : requirements.entrySet()) {
205             try {
206                 final String[] adjustedValue = {entry.getValue()[0], entry.getValue()[1].substring(entry.getValue()[1].lastIndexOf('.') + 1)};
207                 entry.setValue(adjustedValue);
208             } catch (final ArrayIndexOutOfBoundsException exception) {
209                 LOGGER.error("Malformed requirement: {}", entry);
210             }
211         }
212         return requirements;
213     }
214
215     private void setNodeTemplateTypesForVnfs(final ToscaTemplate template, final List<VnfDescriptor> vnfDescriptorList) {
216         if (CollectionUtils.isEmpty(vnfDescriptorList)) {
217             return;
218         }
219         final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
220         if (MapUtils.isEmpty(nodeTemplateMap)) {
221             return;
222         }
223         nodeTemplateMap.forEach(
224             (key, toscaNodeTemplate) -> vnfDescriptorList.stream().filter(vnfDescriptor -> key.equals(vnfDescriptor.getName())).findFirst()
225                 .ifPresent(vnfDescriptor -> toscaNodeTemplate.setType(vnfDescriptor.getNodeType())));
226     }
227
228     private void handleNodeTemplates(final ToscaTemplate template) {
229         final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
230         if (MapUtils.isEmpty(nodeTemplateMap)) {
231             return;
232         }
233         for (final Entry<String, ToscaNodeTemplate> nodeTemplate : nodeTemplateMap.entrySet()) {
234             setPropertiesForNodeTemplate(nodeTemplate);
235             setRequirementsForNodeTemplate(nodeTemplate);
236             removeCapabilitiesFromNodeTemplate(nodeTemplate);
237         }
238     }
239
240     private void setPropertiesForNodeTemplate(final Entry<String, ToscaNodeTemplate> nodeTemplate) {
241         final Map<String, Object> propertyMap = nodeTemplate.getValue().getProperties();
242         if (MapUtils.isEmpty(propertyMap)) {
243             nodeTemplate.getValue().setProperties(null);
244             return;
245         }
246         final Map<String, Object> editedPropertyMap = new HashMap<>();
247         for (final Entry<String, Object> property : propertyMap.entrySet()) {
248             if (!PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TEMPLATE.contains(property.getKey()) && propertyIsDefinedInNodeType(
249                 property.getKey())) {
250                 editedPropertyMap.put(property.getKey(), property.getValue());
251             }
252         }
253         if (editedPropertyMap.isEmpty()) {
254             nodeTemplate.getValue().setProperties(null);
255         } else {
256             nodeTemplate.getValue().setProperties(editedPropertyMap);
257         }
258     }
259
260     private void setRequirementsForNodeTemplate(final Entry<String, ToscaNodeTemplate> nodeTemplateMap) {
261         final List<Map<String, ToscaTemplateRequirement>> requirementAssignments = nodeTemplateMap.getValue().getRequirements();
262         if (requirementAssignments != null) {
263             final List<Map<String, ToscaTemplateRequirement>> requirementAssignmentsMatchingVnfdRequirements = new ArrayList<>();
264             for (final Map<String, ToscaTemplateRequirement> requirementAssignment : requirementAssignments) {
265                 final Map<String, ToscaTemplateRequirement> requirementAssignmentMatchingVnfd =
266                     requirementAssignment.entrySet().stream()
267                         .collect(Collectors.toMap(entry -> entry.getKey().substring(entry.getKey().lastIndexOf('.') + 1), Map.Entry::getValue));
268                 requirementAssignmentsMatchingVnfdRequirements.add(requirementAssignmentMatchingVnfd);
269             }
270             nodeTemplateMap.getValue().setRequirements(requirementAssignmentsMatchingVnfdRequirements);
271         }
272     }
273
274
275     private void removeCapabilitiesFromNodeTemplate(final Entry<String, ToscaNodeTemplate> nodeTemplate) {
276         nodeTemplate.getValue().setCapabilities(null);
277     }
278
279     private void removeOnapAndEtsiNsdPropertiesFromInputs(final ToscaTemplate template) {
280         final ToscaTopolgyTemplate topologyTemplate = template.getTopology_template();
281         final Map<String, ToscaProperty> inputMap = topologyTemplate.getInputs();
282
283         if (MapUtils.isNotEmpty(inputMap)) {
284             inputMap.entrySet().removeIf(entry -> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TYPE.contains(entry.getKey())
285                 || ETSI_SOL_NSD_NS_NODE_TYPE_PROPERTIES.contains(entry.getKey()));
286         }
287         if (MapUtils.isEmpty(inputMap)) {
288             topologyTemplate.setInputs(null);
289         }
290     }
291
292     private void removeOnapMetaData(final ToscaTemplate template) {
293         template.setMetadata(null);
294         final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
295         if (MapUtils.isEmpty(nodeTemplateMap)) {
296             return;
297         }
298         nodeTemplateMap.values().forEach(toscaNodeTemplate -> toscaNodeTemplate.setMetadata(null));
299     }
300
301     private void setDefaultImportsForEtsiSolNsNsd(final ToscaTemplate template, final List<VnfDescriptor> vnfDescriptorList) {
302         final List<Map<String, Map<String, String>>> importEntryMap = new ArrayList<>();
303         final Map<String, Map<String, String>> defaultImportEntryMap = generateDefaultImportEntry();
304         if (MapUtils.isNotEmpty(defaultImportEntryMap)) {
305             importEntryMap.add(defaultImportEntryMap);
306         }
307         if (CollectionUtils.isNotEmpty(vnfDescriptorList)) {
308             for (final VnfDescriptor vnfDescriptor : vnfDescriptorList) {
309                 final Map<String, String> vnfImportChildEntry = new HashMap<>();
310                 vnfImportChildEntry.put("file", vnfDescriptor.getVnfdFileName());
311                 final Map<String, Map<String, String>> vnfdImportVnfdEntry = new HashMap<>();
312                 vnfdImportVnfdEntry.put(vnfDescriptor.getName(), vnfImportChildEntry);
313                 importEntryMap.add(vnfdImportVnfdEntry);
314             }
315         }
316         template.setImports(importEntryMap);
317     }
318
319     private Map<String, Map<String, String>> generateDefaultImportEntry() {
320         return Map.of("etsi_nfv_sol001_nsd_types", Map.of("file", "etsi_nfv_sol001_nsd_types.yaml"));
321     }
322
323     private ToscaNodeType createEtsiSolNsNodeType(final ToscaNodeType nsNodeType, final ToscaTemplate componentToscaTemplate) {
324         final ToscaNodeType toscaNodeType = new ToscaNodeType();
325         toscaNodeType.setDerived_from(NS_TOSCA_TYPE);
326         final Map<String, ToscaProperty> propertiesInNsNodeType = nsNodeType.getProperties();
327         for (final Entry<String, ToscaProperty> property : propertiesInNsNodeType.entrySet()) {
328             final ToscaProperty toscaProperty = property.getValue();
329             if (toscaProperty.getDefaultp() != null && ETSI_SOL_NSD_NS_NODE_TYPE_PROPERTIES.contains(property.getKey())) {
330                 final ToscaPropertyConstraintValidValues constraint = new ToscaPropertyConstraintValidValues(
331                     Collections.singletonList(toscaProperty.getDefaultp().toString()));
332                 toscaProperty.setConstraints(Collections.singletonList(constraint));
333             }
334         }
335         propertiesInNsNodeType.entrySet().removeIf(entry -> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TYPE.contains(entry.getKey()));
336         toscaNodeType.setProperties(propertiesInNsNodeType);
337
338         final List<Map<String, ToscaRequirement>> requirementsInNsNodeType = getRequirementsForNsNodeType(nsNodeType.getRequirements(),
339             componentToscaTemplate);
340         if (!requirementsInNsNodeType.isEmpty()) {
341             toscaNodeType.setRequirements(requirementsInNsNodeType);
342         }
343
344         return toscaNodeType;
345     }
346
347     private List<Map<String, ToscaRequirement>> getRequirementsForNsNodeType(final List<Map<String, ToscaRequirement>> requirements,
348                                                                              final ToscaTemplate componentToscaTemplate) {
349         final Map<String, String[]> requirementsInSubstitutionMapping = componentToscaTemplate.getTopology_template().getSubstitution_mappings()
350             .getRequirements();
351         if (requirements == null || MapUtils.isEmpty(requirementsInSubstitutionMapping)) {
352             return Collections.emptyList();
353         }
354         final List<Map<String, ToscaRequirement>> requirementsToAdd = new ArrayList<>();
355         for (final Map<String, ToscaRequirement> requirementMap : requirements) {
356             final Map<String, ToscaRequirement> neededRequirements = requirementMap.entrySet().stream()
357                 .filter(entry -> requirementsInSubstitutionMapping.containsKey(entry.getKey()))
358                 .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
359             if (!neededRequirements.isEmpty()) {
360                 requirementsToAdd.add(neededRequirements);
361             }
362         }
363         return requirementsToAdd;
364
365     }
366
367     private boolean propertyIsDefinedInNodeType(final String propertyName) {
368         // This will achieve what we want for now, but will look into a more generic solution which would involve
369
370         // checking the node_type definition in the VNFD
371         return !propertyName.equals("additional_parameters");
372     }
373
374     private ToscaNodeTemplate createNodeTemplateForNsNodeType(final String nodeType, final ToscaNodeType toscaNodeType) {
375         final ToscaNodeTemplate nodeTemplate = new ToscaNodeTemplate();
376         nodeTemplate.setType(nodeType);
377         final Map<String, ToscaProperty> properties = toscaNodeType.getProperties();
378         final Map<String, Object> nodeTemplateProperties = new HashMap<>();
379         for (final Entry<String, ToscaProperty> property : properties.entrySet()) {
380             if (property.getValue().getDefaultp() != null) {
381                 nodeTemplateProperties.put(property.getKey(), property.getValue().getDefaultp());
382             }
383         }
384         if (!nodeTemplateProperties.isEmpty()) {
385             nodeTemplate.setProperties(nodeTemplateProperties);
386         }
387         final Map<String, Object> interfaces = toscaNodeType.getInterfaces();
388         if (interfaces != null) {
389             for (final Entry<String, Object> nodeInterface : interfaces.entrySet()) {
390                 if ("Nslcm".equals(nodeInterface.getKey()) && nodeInterface.getValue() instanceof Map) {
391                     ((Map<?, ?>) nodeInterface.getValue()).remove("type");
392                 }
393             }
394             nodeTemplate.setInterfaces(interfaces);
395         }
396         return nodeTemplate;
397     }
398
399     private ToscaTemplate parseToToscaTemplate(final Component component) throws NsdException {
400         final Either<ToscaTemplate, ToscaError> toscaTemplateRes = toscaExportHandler.convertToToscaTemplate(component);
401         if (toscaTemplateRes.isRight()) {
402             String errorMsg = String
403                 .format("Could not parse component '%s' to tosca template. Error '%s'", component.getName(), toscaTemplateRes.right().value().name());
404             throw new NsdException(errorMsg);
405         }
406         return toscaTemplateRes.left().value();
407     }
408
409     private ToscaTemplate exportComponentInterfaceAsToscaTemplate(final Component component) throws NsdException {
410         if (null == DEFAULT_IMPORTS) {
411             throw new NsdException("Could not load default CSAR imports from configuration");
412         }
413         final ToscaTemplate toscaTemplate = new ToscaTemplate(TOSCA_VERSION);
414         toscaTemplate.setImports(new ArrayList<>(DEFAULT_IMPORTS));
415         final Either<ToscaTemplate, ToscaError> toscaTemplateRes = toscaExportHandler
416             .convertInterfaceNodeType(new HashMap<>(), component, toscaTemplate, new HashMap<>(), false);
417         if (toscaTemplateRes.isRight()) {
418             throw new NsdException(String.format("Could not create abstract service from component '%s'", component.getName()));
419         }
420         return toscaTemplateRes.left().value();
421     }
422 }