Onboard Package Handling
[sdc.git] / openecomp-be / lib / openecomp-tosca-converter-lib / openecomp-tosca-converter-core / src / main / java / org / openecomp / core / impl / ToscaSolConverterPnf.java
1 /*
2  * -
3  *  * ============LICENSE_START=======================================================
4  *  *  Copyright (C) 2019 Nordix Foundation.
5  *  * ================================================================================
6  *  * Licensed under the Apache License, Version 2.0 (the "License");
7  *  * you may not use this file except in compliance with the License.
8  *  * You may obtain a copy of the License at
9  *  *
10  *  *      http://www.apache.org/licenses/LICENSE-2.0
11  *  *
12  *  * Unless required by applicable law or agreed to in writing, software
13  *  * distributed under the License is distributed on an "AS IS" BASIS,
14  *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  * See the License for the specific language governing permissions and
16  *  * limitations under the License.
17  *  *
18  *  * SPDX-License-Identifier: Apache-2.0
19  *  * ============LICENSE_END=========================================================
20  *
21  */
22
23 package org.openecomp.core.impl;
24
25 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.CONSTRAINTS;
26 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE;
27 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DESCRIPTION;
28 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.ENTRY_SCHEMA;
29 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.GET_INPUT;
30 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.PROPERTIES;
31 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.REQUIRED;
32 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.TYPE;
33
34 import java.util.AbstractMap;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Objects;
39 import java.util.stream.Collectors;
40 import org.apache.commons.collections.MapUtils;
41 import org.onap.sdc.tosca.datatypes.model.Constraint;
42 import org.onap.sdc.tosca.datatypes.model.EntrySchema;
43 import org.onap.sdc.tosca.datatypes.model.NodeTemplate;
44 import org.onap.sdc.tosca.datatypes.model.ParameterDefinition;
45 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
46 import org.onap.sdc.tosca.datatypes.model.TopologyTemplate;
47 import org.openecomp.core.converter.ServiceTemplateReaderService;
48 import org.openecomp.sdc.tosca.services.DataModelUtil;
49
50 public class ToscaSolConverterPnf extends AbstractToscaSolConverter {
51
52     private static final String PNF_EXT_CP_TYPE = "tosca.nodes.nfv.PnfExtCp";
53     private static final String EXT_CP_TYPE = "org.openecomp.resource.cp.v2.extCP";
54     private static final String LAYER_PROTOCOLS = "layer_protocols";
55     private static final String ASSIGNMENT_METHOD = "assingment_method";
56     private static final String DHCP = "dhcp";
57     private static final String IP_V4 = "ipv4";
58     private static final String IP_V6 = "ipv6";
59     private static final String IP_VERSION = "ip_version";
60     private static final String IP_REQUIREMENTS = "ip_requirements";
61     private static final String IP_REQUIREMENTS_TYPE = "org.openecomp.datatypes.network.IpRequirements";
62     private ServiceTemplate serviceTemplate;
63     private ServiceTemplateReaderService readerService;
64
65     /**
66      * For PNF the node templates are converted ETSI node types to ecomp node types. All other data i.e. inputs,
67      * substitution mappings and outputs are simply dropped at this stage. The equivalent ecomp data will be added when
68      * the vsp is imported into the catalog.
69      *
70      * @param serviceTemplate - the service template
71      * @param readerService - the reader service
72      */
73     @Override
74     public void convertTopologyTemplate(final ServiceTemplate serviceTemplate,
75             final ServiceTemplateReaderService readerService) {
76         this.serviceTemplate = serviceTemplate;
77         this.readerService = readerService;
78         convertNodeTemplatesToEcompTypes();
79         addEmptyNodeTemplatesIfNoneDefined();
80     }
81
82     /**
83      * Copies a input from the reader (input) to the service template (output)
84      * @param inputName     the name of the input to copy
85      */
86     private void copyTopologyTemplateInput(final String inputName) {
87         final Map<String, Object> inputMap = readerService.getInputs();
88         if (MapUtils.isEmpty(inputMap)) {
89             return;
90         }
91         final Map propertyMap = (Map) inputMap.get(inputName);
92         final Object requiredObj = propertyMap.get(REQUIRED.getElementName());
93         final Object constraintsObj = propertyMap.get(CONSTRAINTS.getElementName());
94         final Object entrySchemaObj = propertyMap.get(ENTRY_SCHEMA.getElementName());
95
96         EntrySchema entrySchema = null;
97         if (entrySchemaObj instanceof Map) {
98             final Map entrySchemaMap = ((Map) entrySchemaObj);
99             entrySchema = parseEntrySchema(entrySchemaMap);
100         }
101         final ParameterDefinition parameterDefinition =
102             DataModelUtil.createParameterDefinition(
103                 (String) propertyMap.get(TYPE.getElementName()),
104                 (String) propertyMap.get(DESCRIPTION.getElementName()),
105                 requiredObj instanceof Boolean ? (Boolean) requiredObj : null,
106                 constraintsObj instanceof List ? (List<Constraint>) constraintsObj : null,
107                 entrySchema,
108                 propertyMap.get(DEFAULT_VALUE.getElementName()));
109
110         DataModelUtil
111             .addInputParameterToTopologyTemplate(serviceTemplate, inputName, parameterDefinition);
112     }
113
114     /**
115      * PNF only has nfv.PNF and nfv.PnfExtCp types defined in ETSI SOL001 v2.5.1. - The PNF is mapped to the outer
116      * Abstract PNF container in ecomp model and hence nfv.PNF is dropped here. - nfv.PnfExtCp is mapped to ecomp
117      * v2.extCp type.
118      */
119     private void convertNodeTemplatesToEcompTypes() {
120         final Map<String, Object> nodeTemplates = readerService.getNodeTemplates();
121         if (MapUtils.isEmpty(nodeTemplates)) {
122             return;
123         }
124
125         nodeTemplates.entrySet().stream()
126             .filter(nodeTemplateEntry ->
127                 PNF_EXT_CP_TYPE.equals(((Map<String, Object>) nodeTemplateEntry.getValue()).get(TYPE.getElementName())))
128             .forEach(nodeTemplateEntry ->
129                 DataModelUtil.addNodeTemplate(serviceTemplate, nodeTemplateEntry.getKey(),
130                     convertToEcompConnectionPointNodeType((Map<String, Object>) nodeTemplateEntry.getValue())));
131     }
132
133     /**
134      * Converts from the ETSI PnfExtCp node type to ecomp v2.extCP node type The following properties are mapped -
135      * layer_protocols is mapped to ip_requirements if it contains the values ipv4 and/or ipv6. All other data e.g.
136      * remaining properties, requirements, capabilities are not mapped over to ecomp equivalent
137      *
138      * @param pnfExtCp - the ETSI PnfExtCp map
139      * @return ecomp v2.extCP node type
140      */
141     private NodeTemplate convertToEcompConnectionPointNodeType(final Map<String, Object> pnfExtCp) {
142         final NodeTemplate nodeTemplate = new NodeTemplate();
143         nodeTemplate.setType(EXT_CP_TYPE);
144         final Map<String, Object> properties = (Map<String, Object>) pnfExtCp.get(PROPERTIES.getElementName());
145
146         properties.entrySet().stream()
147             .filter(propertyMap -> LAYER_PROTOCOLS.equals(propertyMap.getKey()))
148             .forEach(propertyMap -> {
149                 final Object propertyValue = propertyMap.getValue();
150                 if (propertyValue instanceof List) {
151                     // layer_protocols: [ ipv4, ipv6, ... ]
152                     final List<Map<String, Object>> ipRequirements =
153                         convertToIpRequirementsProperty((List<String>) propertyValue);
154                     if (!ipRequirements.isEmpty()) {
155                         final Map<String, Object> convertedProperties = new HashMap<>();
156                         convertedProperties.put(IP_REQUIREMENTS, ipRequirements);
157                         nodeTemplate.setProperties(convertedProperties);
158                     }
159                 } else if (propertyValue instanceof AbstractMap) {
160                     final Map propertyValueMap = (Map) propertyValue;
161                     if (propertyValueMap.containsKey(GET_INPUT.getElementName())) {
162                         // layer_protocols: {get_input: anInputName}
163                         final Map<String, Object> convertedProperties = new HashMap<>();
164                         convertedProperties.put(IP_REQUIREMENTS, propertyValueMap);
165                         nodeTemplate.setProperties(convertedProperties);
166                         final String getInputValue = (String) propertyValueMap.get(GET_INPUT.getElementName());
167                         if (!isInputAlreadyAdded(getInputValue)) {
168                             copyTopologyTemplateInput(getInputValue);
169                             parseLayerProtocolsInputToIpRequirements(getInputValue);
170                         }
171                     }
172                 }
173             });
174         return nodeTemplate;
175     }
176
177     /**
178      * Checks if a topology template input was already added
179      *
180      * @param inputName     The name of the input to check
181      * @return
182      *  {@code true} if the input was found in the topology template structure
183      */
184     private boolean isInputAlreadyAdded(final String inputName) {
185         final TopologyTemplate topologyTemplate = serviceTemplate.getTopology_template();
186         if (topologyTemplate == null) {
187             return false;
188         }
189
190         final Map<String, ParameterDefinition> inputMap = topologyTemplate.getInputs();
191         if (MapUtils.isNotEmpty(inputMap)) {
192             return inputMap.keySet().contains(inputName);
193         }
194
195         return false;
196     }
197
198     /**
199      * Parses a layer_protocol input to org.openecomp.datatypes.network.IpRequirements ecomp type.
200      *
201      * @param inputName     The name of the input to parse
202      *
203      */
204     private void parseLayerProtocolsInputToIpRequirements(final String inputName) {
205         final TopologyTemplate topologyTemplate = serviceTemplate.getTopology_template();
206         final ParameterDefinition layerProtocolsInput = topologyTemplate.getInputs().get(inputName);
207         final EntrySchema entrySchema = layerProtocolsInput.getEntry_schema();
208         entrySchema.setType(IP_REQUIREMENTS_TYPE);
209         final List<String> defaultLayerProtocolList = (List<String>) layerProtocolsInput.get_default();
210         layerProtocolsInput.set_default(convertToIpRequirementsProperty(defaultLayerProtocolList));
211     }
212
213     /**
214      * Converts each layer_protocols entry that is either {@link #IP_V4} or {@link #IP_V6} to the ecomp
215      * {@link #IP_REQUIREMENTS_TYPE}, ignoring other entry types.
216      *
217      * @param layerProtocols    the PnfExtCp layer_protocols list
218      * @return
219      *  A list of map representing a {@link #IP_REQUIREMENTS_TYPE} ecomp type
220      */
221     private List<Map<String, Object>> convertToIpRequirementsProperty(final List<String> layerProtocols) {
222         return layerProtocols.stream()
223             .filter(layerProtocol -> IP_V4.equals(layerProtocol) || IP_V6.equals(layerProtocol))
224             .map(this::createIpRequirementsEntry)
225             .collect(Collectors.toList());
226     }
227
228     /**
229      * Creates a {@link #IP_REQUIREMENTS_TYPE} based on the ip version
230      * @param ipVersion  the provided ip version, either {@link #IP_V4} or {@link #IP_V6}
231      * @return
232      *  A map representing an {@link #IP_REQUIREMENTS_TYPE} ecomp type
233      */
234     private Map<String, Object> createIpRequirementsEntry(final String ipVersion) {
235         final int version = IP_V4.equals(ipVersion) ? 4 : 6;
236         final Map<String, Object> result = new HashMap<>();
237         result.put(IP_VERSION, version);
238         result.put(ASSIGNMENT_METHOD, DHCP);
239         return result;
240     }
241
242     /**
243      * Fills missing required entries in the service template. Checks for topology_template entry and
244      * topology_template->node_templates entry.
245      */
246     private void addEmptyNodeTemplatesIfNoneDefined() {
247         TopologyTemplate topologyTemplate = serviceTemplate.getTopology_template();
248         if (Objects.isNull(topologyTemplate)) {
249             topologyTemplate = new TopologyTemplate();
250             serviceTemplate.setTopology_template(topologyTemplate);
251         }
252         if (topologyTemplate.getNode_templates() == null) {
253             topologyTemplate.setNode_templates(new HashMap<>());
254         }
255     }
256
257     /**
258      * Parses an input entry schema
259      *
260      * @param entrySchemaMap    the descriptor input entry schema map
261      * @return
262      *  A parsed entry schema based on the provided map
263      */
264     private EntrySchema parseEntrySchema(Map entrySchemaMap) {
265         return DataModelUtil.createEntrySchema((String) entrySchemaMap.get(TYPE.getElementName())
266             , (String) entrySchemaMap.get(DESCRIPTION.getElementName())
267             , (List<Constraint>) entrySchemaMap.get(CONSTRAINTS.getElementName())
268         );
269     }
270
271 }