dc6f7c4416eaa5f254c66d9e8e151b9808393a52
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / csar / CsarInfo.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  * Modifications copyright (c) 2019 Nokia
20  * ================================================================================
21  */
22 package org.openecomp.sdc.be.components.csar;
23
24 import static org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
25 import static org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum;
26 import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement;
27
28 import com.google.common.annotations.VisibleForTesting;
29 import fj.data.Either;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Optional;
37 import java.util.PriorityQueue;
38 import java.util.Queue;
39 import java.util.Set;
40 import java.util.regex.Pattern;
41 import lombok.Getter;
42 import lombok.Setter;
43 import org.apache.commons.collections.CollectionUtils;
44 import org.apache.commons.collections.MapUtils;
45 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
46 import org.openecomp.sdc.be.config.NonManoArtifactType;
47 import org.openecomp.sdc.be.config.NonManoConfiguration;
48 import org.openecomp.sdc.be.config.NonManoConfigurationManager;
49 import org.openecomp.sdc.be.config.NonManoFolderType;
50 import org.openecomp.sdc.be.dao.api.ActionStatus;
51 import org.openecomp.sdc.be.model.NodeTypeInfo;
52 import org.openecomp.sdc.be.model.Resource;
53 import org.openecomp.sdc.be.model.User;
54 import org.openecomp.sdc.be.tosca.CsarUtils;
55 import org.openecomp.sdc.be.utils.TypeUtils;
56 import org.openecomp.sdc.common.api.Constants;
57 import org.openecomp.sdc.common.log.wrappers.Logger;
58 import org.yaml.snakeyaml.Yaml;
59
60 public class CsarInfo {
61
62     private static final Logger log = Logger.getLogger(CsarInfo.class);
63     private final NonManoConfiguration nonManoConfiguration;
64     @Getter
65     @Setter
66     private String vfResourceName;
67     @Getter
68     @Setter
69     private User modifier;
70     @Getter
71     @Setter
72     private String csarUUID;
73     @Getter
74     private String csarVersionId;
75     @Getter
76     @Setter
77     private Map<String, byte[]> csar;
78     @Getter
79     private String mainTemplateName;
80     @Getter
81     private String mainTemplateContent;
82     @Getter
83     private Map<String, Object> mappedToscaMainTemplate;
84     @Getter
85     private Map<String, String> createdNodesToscaResourceNames;
86     private Queue<String> cvfcToCreateQueue;
87     private boolean isUpdate;
88     @Getter
89     private Map<String, Resource> createdNodes;
90     private Map<String, Object> datatypeDefinitions;
91     private Map<String, Object> policytypeDefinitions;
92     private List<Map.Entry<String, byte[]>> globalSubstitutes;
93
94
95     public CsarInfo(User modifier, String csarUUID, Map<String, byte[]> csar, String vfResourceName, String mainTemplateName,
96                     String mainTemplateContent, boolean isUpdate) {
97         this.vfResourceName = vfResourceName;
98         this.modifier = modifier;
99         this.csarUUID = csarUUID;
100         this.csar = csar;
101         this.mainTemplateName = mainTemplateName;
102         this.mainTemplateContent = mainTemplateContent;
103         this.mappedToscaMainTemplate = new Yaml().load(mainTemplateContent);
104         this.createdNodesToscaResourceNames = new HashMap<>();
105         this.cvfcToCreateQueue = new PriorityQueue<>();
106         this.isUpdate = isUpdate;
107         this.createdNodes = new HashMap<>();
108         this.nonManoConfiguration = NonManoConfigurationManager.getInstance().getNonManoConfiguration();
109         this.globalSubstitutes = getGlobalSubstitutes(csar);
110     }
111     
112     private List<Map.Entry<String, byte[]>> getGlobalSubstitutes(final Map<String, byte[]> csar){
113         final List<Map.Entry<String, byte[]>> globalSubstitutesInCsar = new ArrayList<>();
114         for (Map.Entry<String, byte[]> entry : csar.entrySet()) {
115             if (isAServiceTemplate(entry.getKey()) && isGlobalSubstitute(entry.getKey())) {
116                 globalSubstitutesInCsar.add(entry);
117             }
118         }
119         return globalSubstitutesInCsar;
120     }    
121
122     public CsarInfo(final User modifier, final String csarUUID, final String csarVersionId, final Map<String, byte[]> csarContent,
123                     final String vfResourceName, final String mainTemplateName, final String mainTemplateContent, final boolean isUpdate) {
124         this(modifier, csarUUID, csarContent, vfResourceName, mainTemplateName, mainTemplateContent, isUpdate);
125         this.csarVersionId = csarVersionId;
126     }
127
128     @VisibleForTesting
129     CsarInfo(final NonManoConfiguration nonManoConfiguration) {
130         this.nonManoConfiguration = nonManoConfiguration;
131     }
132
133     @SuppressWarnings("unchecked")
134     public static void markNestedVfc(Map<String, Object> mappedToscaTemplate, Map<String, NodeTypeInfo> nodeTypesInfo) {
135         findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES, ToscaElementTypeEnum.MAP).right()
136             .on(nts -> processNodeTemplates((Map<String, Object>) nts, nodeTypesInfo));
137     }
138
139     @SuppressWarnings("unchecked")
140     private static ResultStatusEnum processNodeTemplates(Map<String, Object> nodeTemplates, Map<String, NodeTypeInfo> nodeTypesInfo) {
141         nodeTemplates.values().forEach(nt -> processNodeTemplate(nodeTypesInfo, (Map<String, Object>) nt));
142         return ResultStatusEnum.OK;
143     }
144
145     private static void processNodeTemplate(Map<String, NodeTypeInfo> nodeTypesInfo, Map<String, Object> nodeTemplate) {
146         if (nodeTemplate.containsKey(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName())) {
147             String type = (String) nodeTemplate.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName());
148             if (nodeTypesInfo.containsKey(type)) {
149                 NodeTypeInfo nodeTypeInfo = nodeTypesInfo.get(type);
150                 if (nodeTypeInfo.isSubstitutionMapping() && type.contains(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX)) {
151                     nodeTypeInfo.setNested(true);
152                 }
153             }
154         }
155     }
156
157     public void addNodeToQueue(String nodeName) {
158         if (!cvfcToCreateQueue.contains(nodeName)) {
159             cvfcToCreateQueue.add(nodeName);
160         } else {
161             log.debug("Failed to validate complex VFC {}. Loop detected, VSP {}. ", nodeName, getVfResourceName());
162             throw new ByActionStatusComponentException(ActionStatus.CFVC_LOOP_DETECTED, getVfResourceName(), nodeName);
163         }
164     }
165
166     public void removeNodeFromQueue() {
167         cvfcToCreateQueue.remove();
168     }
169
170     public boolean isUpdate() {
171         return isUpdate;
172     }
173
174     public void setUpdate(boolean isUpdate) {
175         this.isUpdate = isUpdate;
176     }
177
178     public Map<String, NodeTypeInfo> extractTypesInfo() {
179         Map<String, NodeTypeInfo> nodeTypesInfo = new HashMap<>();
180         final Set<String> nodeTypesUsedInNodeTemplates = new HashSet<>();
181         for (Map.Entry<String, byte[]> entry : getCsar().entrySet()) {
182             extractNodeTypeInfo(nodeTypesInfo,  nodeTypesUsedInNodeTemplates, entry);
183         }
184         if (CollectionUtils.isNotEmpty(globalSubstitutes)) {
185             setDerivedFrom(nodeTypesInfo);
186             addGlobalSubstitutionsToNodeTypes(nodeTypesUsedInNodeTemplates, nodeTypesInfo);
187         }
188         
189         markNestedVfc(getMappedToscaMainTemplate(), nodeTypesInfo);
190         return nodeTypesInfo;
191     }
192     
193     public Map<String, Object> getDataTypes() {
194         if (datatypeDefinitions == null) {
195             datatypeDefinitions = new HashMap<>();
196             for (Map.Entry<String, byte[]> entry : globalSubstitutes) {
197                 final String yamlFileContents = new String(entry.getValue());
198                 final Map<String, Object> mappedToscaTemplate = new Yaml().load(yamlFileContents);
199                 datatypeDefinitions.putAll(getTypesFromTemplate(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.DATA_TYPES));
200             }
201             datatypeDefinitions.putAll(getTypesFromTemplate(mappedToscaMainTemplate, TypeUtils.ToscaTagNamesEnum.DATA_TYPES));
202         }
203         return datatypeDefinitions;
204     }
205
206     public Map<String, Object> getPolicyTypes() {
207         if (policytypeDefinitions == null) {
208             policytypeDefinitions = new HashMap<>();
209             policytypeDefinitions.putAll(getTypesFromTemplate(mappedToscaMainTemplate, TypeUtils.ToscaTagNamesEnum.POLICY_TYPES));
210         }
211         return policytypeDefinitions;
212     }
213     
214     @SuppressWarnings("unchecked")    
215     private Map<String, Object> getTypesFromTemplate(final Map<String, Object> mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum type) {
216         final Either<Object, ResultStatusEnum> dataTypesEither = findToscaElement(mappedToscaTemplate, type,
217                         ToscaElementTypeEnum.MAP);
218         if (dataTypesEither != null && dataTypesEither.isLeft()) {
219             return (Map<String, Object>) dataTypesEither.left().value();
220         }
221         return Collections.emptyMap();
222     }
223
224     @SuppressWarnings("unchecked")
225     private void extractNodeTypeInfo(Map<String, NodeTypeInfo> nodeTypesInfo,
226                                      final Set<String> nodeTypesUsedInNodeTemplates, Map.Entry<String, byte[]> entry) {
227         if (isAServiceTemplate(entry.getKey()) && !isGlobalSubstitute(entry.getKey())) {
228             Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(new String(entry.getValue()));
229             findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.SUBSTITUTION_MAPPINGS, ToscaElementTypeEnum.MAP).right()
230                 .on(sub -> handleSubstitutionMappings(nodeTypesInfo, entry, mappedToscaTemplate, (Map<String, Object>) sub));
231             final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate,
232                 TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES, ToscaElementTypeEnum.MAP);
233             if (nodeTypesEither.isLeft()) {
234                 final Map<String, Map<String, Object>> nodeTemplates = (Map<String, Map<String, Object>>) nodeTypesEither.left().value();
235                 nodeTypesUsedInNodeTemplates.addAll(findNodeTypesUsedInNodeTemplates(nodeTemplates));
236             }
237         }
238     }
239
240     private boolean isAServiceTemplate(final String filePath) {
241         return Pattern.compile(CsarUtils.SERVICE_TEMPLATE_PATH_PATTERN).matcher(filePath).matches();
242     }
243
244     private Set<String> findNodeTypesUsedInNodeTemplates(final Map<String, Map<String, Object>> nodeTemplates) {
245         final Set<String> nodeTypes = new HashSet<>();
246         for (final Map<String, Object> nodeTemplate : nodeTemplates.values()) {
247             nodeTypes.add((String) nodeTemplate.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName()));
248         }
249         return nodeTypes;
250     }
251
252     private ResultStatusEnum handleSubstitutionMappings(Map<String, NodeTypeInfo> nodeTypesInfo, Map.Entry<String, byte[]> entry,
253                                                         Map<String, Object> mappedToscaTemplate, Map<String, Object> substitutionMappings) {
254         final Set<String> nodeTypesDefinedInTemplate = findNodeTypesDefinedInTemplate(mappedToscaTemplate);
255         if (substitutionMappings.containsKey(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()) && !nodeTypesDefinedInTemplate
256             .contains(substitutionMappings.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()))) {
257             NodeTypeInfo nodeTypeInfo = new NodeTypeInfo();
258             nodeTypeInfo.setSubstitutionMapping(true);
259             nodeTypeInfo.setType((String) substitutionMappings.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()));
260             nodeTypeInfo.setTemplateFileName(entry.getKey());
261             nodeTypeInfo.setMappedToscaTemplate(mappedToscaTemplate);
262             nodeTypesInfo.put(nodeTypeInfo.getType(), nodeTypeInfo);
263         }
264         return ResultStatusEnum.OK;
265     }
266
267     @SuppressWarnings("unchecked")
268     private Set<String> findNodeTypesDefinedInTemplate(final Map<String, Object> mappedToscaTemplate) {
269         final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
270             ToscaElementTypeEnum.MAP);
271         if (nodeTypesEither.isLeft()) {
272             final Map<String, Object> nodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
273             return nodeTypes.keySet();
274         }
275         return Collections.emptySet();
276     }
277
278     private boolean isGlobalSubstitute(String fileName) {
279         return fileName.equalsIgnoreCase(Constants.GLOBAL_SUBSTITUTION_TYPES_SERVICE_TEMPLATE) || fileName
280             .equalsIgnoreCase(Constants.ABSTRACT_SUBSTITUTE_GLOBAL_TYPES_SERVICE_TEMPLATE);
281     }
282
283     @SuppressWarnings("unchecked")
284     private void setDerivedFrom(Map<String, NodeTypeInfo> nodeTypesInfo) {
285         for (Map.Entry<String, byte[]> entry : globalSubstitutes) {
286             String yamlFileContents = new String(entry.getValue());
287             Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(yamlFileContents);
288             Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
289                 ToscaElementTypeEnum.MAP);
290             if (nodeTypesEither.isLeft()) {
291                 Map<String, Object> nodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
292                 for (Map.Entry<String, Object> nodeType : nodeTypes.entrySet()) {
293                     processNodeType(nodeTypesInfo, nodeType);
294                 }
295             }
296         }
297     }
298
299     @SuppressWarnings("unchecked")
300     private void processNodeType(Map<String, NodeTypeInfo> nodeTypesInfo, Map.Entry<String, Object> nodeType) {
301         Map<String, Object> nodeTypeMap = (Map<String, Object>) nodeType.getValue();
302         if (nodeTypeMap.containsKey(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()) && nodeTypesInfo.containsKey(nodeType.getKey())) {
303             NodeTypeInfo nodeTypeInfo = nodeTypesInfo.get(nodeType.getKey());
304             List<String> derivedFrom = new ArrayList<>();
305             derivedFrom.add((String) nodeTypeMap.get(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()));
306             nodeTypeInfo.setDerivedFrom(derivedFrom);
307         }
308     }
309
310     @SuppressWarnings("unchecked")
311     private void addGlobalSubstitutionsToNodeTypes(final Set<String> nodeTypesUsedInNodeTemplates, final Map<String, NodeTypeInfo> nodeTypesInfo) {
312         for (Map.Entry<String, byte[]> entry : globalSubstitutes) {
313             final String yamlFileContents = new String(entry.getValue());
314             final Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(yamlFileContents);
315             final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
316                 ToscaElementTypeEnum.MAP);
317             if (nodeTypesEither.isLeft()) {
318                 final Map<String, Object> nodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
319                 for (final Map.Entry<String, Object> nodeType : nodeTypes.entrySet()) {
320                     if (!nodeTypesInfo.containsKey(nodeType.getKey()) && nodeTypesUsedInNodeTemplates.contains(nodeType.getKey())) {
321                         nodeTypesInfo.put(nodeType.getKey(), buildNodeTypeInfo(nodeType, entry.getKey(), mappedToscaTemplate));
322                     }
323                 }
324             }
325         }
326     }
327
328     @SuppressWarnings("unchecked")
329     private NodeTypeInfo buildNodeTypeInfo(final Map.Entry<String, Object> nodeType, final String templateFileName,
330                                            final Map<String, Object> mappedToscaTemplate) {
331         final NodeTypeInfo nodeTypeInfo = new NodeTypeInfo();
332         nodeTypeInfo.setSubstitutionMapping(false);
333         nodeTypeInfo.setNested(true);
334         nodeTypeInfo.setType(nodeType.getKey());
335         nodeTypeInfo.setTemplateFileName(templateFileName);
336         nodeTypeInfo.setMappedToscaTemplate(buildToscaTemplateForNode(nodeType.getKey(), mappedToscaTemplate));
337         final Map<String, Object> nodeTypeMap = (Map<String, Object>) nodeType.getValue();
338         final List<String> derivedFrom = new ArrayList<>();
339         derivedFrom.add((String) nodeTypeMap.get(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()));
340         nodeTypeInfo.setDerivedFrom(derivedFrom);
341         return nodeTypeInfo;
342     }
343
344     @SuppressWarnings("unchecked")
345     private Map<String, Object> buildToscaTemplateForNode(final String nodeTypeName, final Map<String, Object> mappedToscaTemplate) {
346         final Map<String, Object> mappedToscaTemplateforNode = new HashMap<>(mappedToscaTemplate);
347         final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
348             ToscaElementTypeEnum.MAP);
349         final Map<String, Object> nodeTypes = new HashMap<>();
350         if (nodeTypesEither.isLeft()) {
351             final Map<String, Object> allNodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
352             nodeTypes.put(nodeTypeName, allNodeTypes.get(nodeTypeName));
353         }
354         mappedToscaTemplateforNode.put(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName(), nodeTypes);
355         return mappedToscaTemplateforNode;
356     }
357
358     /**
359      * Gets the software information yaml path from the csar file map.
360      *
361      * @return the software information yaml path if it is present in the csar file map
362      */
363     public Optional<String> getSoftwareInformationPath() {
364         if (MapUtils.isEmpty(csar)) {
365             return Optional.empty();
366         }
367         final NonManoFolderType softwareInformationType = nonManoConfiguration.getNonManoType(NonManoArtifactType.ONAP_SW_INFORMATION);
368         return csar.keySet().stream().filter(filePath -> filePath.startsWith(softwareInformationType.getPath())).findFirst();
369     }
370 }