Catalog alignment
[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 com.google.common.annotations.VisibleForTesting;
25 import fj.data.Either;
26 import lombok.Getter;
27 import lombok.Setter;
28 import org.apache.commons.collections.CollectionUtils;
29 import org.apache.commons.collections.MapUtils;
30 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
31 import org.openecomp.sdc.be.config.NonManoArtifactType;
32 import org.openecomp.sdc.be.config.NonManoConfiguration;
33 import org.openecomp.sdc.be.config.NonManoConfigurationManager;
34 import org.openecomp.sdc.be.config.NonManoFolderType;
35 import org.openecomp.sdc.be.dao.api.ActionStatus;
36 import org.openecomp.sdc.be.model.NodeTypeInfo;
37 import org.openecomp.sdc.be.model.Resource;
38 import org.openecomp.sdc.be.model.User;
39 import org.openecomp.sdc.be.tosca.CsarUtils;
40 import org.openecomp.sdc.be.utils.TypeUtils;
41 import org.openecomp.sdc.common.api.Constants;
42 import org.openecomp.sdc.common.log.wrappers.Logger;
43 import org.yaml.snakeyaml.Yaml;
44
45 import java.util.ArrayList;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Optional;
50 import java.util.PriorityQueue;
51 import java.util.Queue;
52 import java.util.regex.Pattern;
53
54 import static org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
55 import static org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum;
56 import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement;
57
58 public class CsarInfo {
59     private static final Logger log = Logger.getLogger(CsarInfo.class);
60
61     @Getter
62     @Setter
63     private String vfResourceName;
64     @Getter
65     @Setter
66     private User modifier;
67     @Getter
68     @Setter
69     private String csarUUID;
70     @Getter
71     @Setter
72     private Map<String, byte[]> csar;
73     @Getter
74     private String mainTemplateName;
75     @Getter
76     private String mainTemplateContent;
77     @Getter
78     private Map<String, Object> mappedToscaMainTemplate;
79     @Getter
80     private Map<String, String> createdNodesToscaResourceNames;
81     private Queue<String> cvfcToCreateQueue;
82     private boolean isUpdate;
83     @Getter
84     private Map<String, Resource> createdNodes;
85     private final NonManoConfiguration nonManoConfiguration;
86
87     @SuppressWarnings("unchecked")
88     public CsarInfo(User modifier, String csarUUID, Map<String, byte[]> csar, String vfResourceName, String mainTemplateName, String mainTemplateContent, boolean isUpdate){
89         this.vfResourceName = vfResourceName;
90         this.modifier = modifier;
91         this.csarUUID = csarUUID;
92         this.csar = csar;
93         this.mainTemplateName = mainTemplateName;
94         this.mainTemplateContent = mainTemplateContent;
95         this.mappedToscaMainTemplate = (Map<String, Object>) new Yaml().load(mainTemplateContent);
96         this.createdNodesToscaResourceNames = new HashMap<>();
97         this.cvfcToCreateQueue = new PriorityQueue<>();
98         this.isUpdate = isUpdate;
99         this.createdNodes  = new HashMap<>();
100         this.nonManoConfiguration = NonManoConfigurationManager.getInstance().getNonManoConfiguration();
101     }
102
103     @VisibleForTesting
104     CsarInfo(final NonManoConfiguration nonManoConfiguration) {
105         this.nonManoConfiguration = nonManoConfiguration;
106     }
107
108     public void addNodeToQueue(String nodeName) {
109         if(!cvfcToCreateQueue.contains(nodeName)) {
110             cvfcToCreateQueue.add(nodeName);
111         } else {
112             log.debug("Failed to validate complex VFC {}. Loop detected, VSP {}. ", nodeName,
113                     getVfResourceName());
114             throw new ByActionStatusComponentException(ActionStatus.CFVC_LOOP_DETECTED,
115                     getVfResourceName(), nodeName);
116         }
117     }
118
119     public void removeNodeFromQueue() {
120         cvfcToCreateQueue.remove();
121     }
122
123     public boolean isUpdate() {
124         return isUpdate;
125     }
126
127     public void setUpdate(boolean isUpdate) {
128         this.isUpdate = isUpdate;
129     }
130
131     public Map<String,NodeTypeInfo> extractNodeTypesInfo() {
132         Map<String, NodeTypeInfo> nodeTypesInfo = new HashMap<>();
133         List<Map.Entry<String, byte[]>> globalSubstitutes = new ArrayList<>();
134         for (Map.Entry<String, byte[]> entry : getCsar().entrySet()) {
135             extractNodeTypeInfo(nodeTypesInfo, globalSubstitutes, entry);
136         }
137         if (CollectionUtils.isNotEmpty(globalSubstitutes)) {
138             setDerivedFrom(nodeTypesInfo, globalSubstitutes);
139         }
140         markNestedVfc(getMappedToscaMainTemplate(), nodeTypesInfo);
141         return nodeTypesInfo;
142     }
143
144     @SuppressWarnings("unchecked")
145     private void extractNodeTypeInfo(Map<String, NodeTypeInfo> nodeTypesInfo,
146                                      List<Map.Entry<String, byte[]>> globalSubstitutes, Map.Entry<String, byte[]> entry) {
147         if (Pattern.compile(CsarUtils.SERVICE_TEMPLATE_PATH_PATTERN).matcher(entry.getKey()).matches()) {
148             if (!isGlobalSubstitute(entry.getKey())) {
149                 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(new String(entry.getValue()));
150                 findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.SUBSTITUTION_MAPPINGS, ToscaElementTypeEnum.MAP)
151                     .right()
152                     .on(sub->handleSubstitutionMappings(nodeTypesInfo, entry, mappedToscaTemplate, (Map<String, Object>)sub));
153             }else {
154                 globalSubstitutes.add(entry);
155             }
156         }
157     }
158
159     private ResultStatusEnum handleSubstitutionMappings(Map<String, NodeTypeInfo> nodeTypesInfo, Map.Entry<String, byte[]> entry, Map<String, Object> mappedToscaTemplate, Map<String, Object> substitutionMappings) {
160         if (substitutionMappings.containsKey(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName())) {
161             NodeTypeInfo nodeTypeInfo = new NodeTypeInfo();
162             nodeTypeInfo.setSubstitutionMapping(true);
163             nodeTypeInfo.setType(
164                     (String) substitutionMappings.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()));
165             nodeTypeInfo.setTemplateFileName(entry.getKey());
166             nodeTypeInfo.setMappedToscaTemplate(mappedToscaTemplate);
167             nodeTypesInfo.put(nodeTypeInfo.getType(), nodeTypeInfo);
168         }
169         return ResultStatusEnum.OK;
170     }
171
172     private boolean isGlobalSubstitute(String fileName) {
173         return fileName.equalsIgnoreCase(Constants.GLOBAL_SUBSTITUTION_TYPES_SERVICE_TEMPLATE)
174                 || fileName.equalsIgnoreCase(Constants.ABSTRACT_SUBSTITUTE_GLOBAL_TYPES_SERVICE_TEMPLATE);
175     }
176
177     @SuppressWarnings("unchecked")
178     private void setDerivedFrom(Map<String, NodeTypeInfo> nodeTypesInfo,
179                                 List<Map.Entry<String, byte[]>> globalSubstitutes) {
180         for (Map.Entry<String, byte[]> entry : globalSubstitutes) {
181             String yamlFileContents = new String(entry.getValue());
182             Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(yamlFileContents);
183             Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate,
184                     TypeUtils.ToscaTagNamesEnum.NODE_TYPES, ToscaElementTypeEnum.MAP);
185             if (nodeTypesEither.isLeft()) {
186                 Map<String, Object> nodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
187                 for (Map.Entry<String, Object> nodeType : nodeTypes.entrySet()) {
188                     processNodeType(nodeTypesInfo, nodeType);
189                 }
190             }
191         }
192     }
193
194     @SuppressWarnings("unchecked")
195     private void processNodeType(Map<String, NodeTypeInfo> nodeTypesInfo, Map.Entry<String, Object> nodeType) {
196         Map<String, Object> nodeTypeMap = (Map<String, Object>) nodeType.getValue();
197         if (nodeTypeMap.containsKey(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()) && nodeTypesInfo.containsKey(nodeType.getKey())) {
198             NodeTypeInfo nodeTypeInfo = nodeTypesInfo.get(nodeType.getKey());
199             List<String> derivedFrom = new ArrayList<>();
200             derivedFrom.add((String) nodeTypeMap.get(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()));
201             nodeTypeInfo.setDerivedFrom(derivedFrom);
202         }
203     }
204
205     @SuppressWarnings("unchecked")
206     public static void markNestedVfc(Map<String, Object> mappedToscaTemplate, Map<String, NodeTypeInfo> nodeTypesInfo) {
207         findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES,
208                 ToscaElementTypeEnum.MAP)
209                 .right()
210                 .on(nts-> processNodeTemplates((Map<String, Object>)nts, nodeTypesInfo));
211     }
212
213     @SuppressWarnings("unchecked")
214     private static ResultStatusEnum processNodeTemplates( Map<String, Object> nodeTemplates, Map<String, NodeTypeInfo> nodeTypesInfo) {
215         nodeTemplates.values().forEach(nt->processNodeTemplate(nodeTypesInfo, (Map<String, Object>) nt));
216         return ResultStatusEnum.OK;
217     }
218
219     private static void processNodeTemplate(Map<String, NodeTypeInfo> nodeTypesInfo, Map<String, Object> nodeTemplate) {
220         if (nodeTemplate.containsKey(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName())) {
221             String type = (String) nodeTemplate.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName());
222             if (nodeTypesInfo.containsKey(type)) {
223                 NodeTypeInfo nodeTypeInfo = nodeTypesInfo.get(type);
224                 if (nodeTypeInfo.isSubstitutionMapping() && type.contains(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX)) {
225                     nodeTypeInfo.setNested(true);
226                 }
227             }
228         }
229     }
230
231     /**
232      * Gets the software information yaml path from the csar file map.
233      *
234      * @return the software information yaml path if it is present in the csar file map
235      */
236     public Optional<String> getSoftwareInformationPath() {
237         if (MapUtils.isEmpty(csar)) {
238             return Optional.empty();
239         }
240         final NonManoFolderType softwareInformationType =
241             nonManoConfiguration.getNonManoType(NonManoArtifactType.ONAP_SW_INFORMATION);
242         return csar.keySet().stream()
243             .filter(filePath -> filePath.startsWith(softwareInformationType.getPath()))
244             .findFirst();
245     }
246 }