Support unknown data types in service import
[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.findToscaElement;
25
26 import com.google.common.annotations.VisibleForTesting;
27 import fj.data.Either;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Optional;
35 import java.util.PriorityQueue;
36 import java.util.Queue;
37 import java.util.Set;
38 import lombok.Getter;
39 import lombok.Setter;
40 import org.apache.commons.collections.MapUtils;
41 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
42 import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum;
43 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
44 import org.openecomp.sdc.be.config.NonManoArtifactType;
45 import org.openecomp.sdc.be.config.NonManoConfiguration;
46 import org.openecomp.sdc.be.config.NonManoConfigurationManager;
47 import org.openecomp.sdc.be.config.NonManoFolderType;
48 import org.openecomp.sdc.be.dao.api.ActionStatus;
49 import org.openecomp.sdc.be.model.NodeTypeInfo;
50 import org.openecomp.sdc.be.model.Resource;
51 import org.openecomp.sdc.be.model.User;
52 import org.openecomp.sdc.be.utils.TypeUtils;
53 import org.openecomp.sdc.common.api.Constants;
54 import org.openecomp.sdc.common.log.wrappers.Logger;
55 import org.yaml.snakeyaml.Yaml;
56
57 /**
58  * Provides access to the contents of a CSAR
59  */
60 public abstract 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     protected Map<String, byte[]> csar;
78     @Getter
79     private String mainTemplateName;
80     @Getter
81     private String mainTemplateContent;
82     @Getter
83     protected 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     protected Map<String, Object> datatypeDefinitions;
91     private Map<String, Object> policytypeDefinitions;
92
93
94     public CsarInfo(User modifier, String csarUUID, Map<String, byte[]> csar, String vfResourceName, String mainTemplateName,
95                     String mainTemplateContent, boolean isUpdate) {
96         this.vfResourceName = vfResourceName;
97         this.modifier = modifier;
98         this.csarUUID = csarUUID;
99         this.csar = csar;
100         this.mainTemplateName = mainTemplateName;
101         this.mainTemplateContent = mainTemplateContent;
102         this.mappedToscaMainTemplate = new Yaml().load(mainTemplateContent);
103         this.createdNodesToscaResourceNames = new HashMap<>();
104         this.cvfcToCreateQueue = new PriorityQueue<>();
105         this.isUpdate = isUpdate;
106         this.createdNodes = new HashMap<>();
107         this.nonManoConfiguration = NonManoConfigurationManager.getInstance().getNonManoConfiguration();
108     }
109     
110     public String getVfResourceName() {
111         return vfResourceName;
112     }
113
114     public CsarInfo(final User modifier, final String csarUUID, final String csarVersionId, final Map<String, byte[]> csarContent,
115                     final String vfResourceName, final String mainTemplateName, final String mainTemplateContent, final boolean isUpdate) {
116         this(modifier, csarUUID, csarContent, vfResourceName, mainTemplateName, mainTemplateContent, isUpdate);
117         this.csarVersionId = csarVersionId;
118     }
119
120     @VisibleForTesting
121     CsarInfo(final NonManoConfiguration nonManoConfiguration) {
122         this.nonManoConfiguration = nonManoConfiguration;
123     }
124
125     @SuppressWarnings("unchecked")
126     public static void markNestedVfc(Map<String, Object> mappedToscaTemplate, Map<String, NodeTypeInfo> nodeTypesInfo) {
127         findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES, ToscaElementTypeEnum.MAP).right()
128             .on(nts -> processNodeTemplates((Map<String, Object>) nts, nodeTypesInfo));
129     }
130
131     @SuppressWarnings("unchecked")
132     private static ResultStatusEnum processNodeTemplates(Map<String, Object> nodeTemplates, Map<String, NodeTypeInfo> nodeTypesInfo) {
133         nodeTemplates.values().forEach(nt -> processNodeTemplate(nodeTypesInfo, (Map<String, Object>) nt));
134         return ResultStatusEnum.OK;
135     }
136
137     private static void processNodeTemplate(Map<String, NodeTypeInfo> nodeTypesInfo, Map<String, Object> nodeTemplate) {
138         if (nodeTemplate.containsKey(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName())) {
139             String type = (String) nodeTemplate.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName());
140             if (nodeTypesInfo.containsKey(type)) {
141                 NodeTypeInfo nodeTypeInfo = nodeTypesInfo.get(type);
142                 if (nodeTypeInfo.isSubstitutionMapping() && type.contains(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX)) {
143                     nodeTypeInfo.setNested(true);
144                 }
145             }
146         }
147     }
148
149     public void addNodeToQueue(String nodeName) {
150         if (!cvfcToCreateQueue.contains(nodeName)) {
151             cvfcToCreateQueue.add(nodeName);
152         } else {
153             log.debug("Failed to validate complex VFC {}. Loop detected, VSP {}. ", nodeName, getVfResourceName());
154             throw new ByActionStatusComponentException(ActionStatus.CFVC_LOOP_DETECTED, getVfResourceName(), nodeName);
155         }
156     }
157
158     public void removeNodeFromQueue() {
159         cvfcToCreateQueue.remove();
160     }
161
162     public boolean isUpdate() {
163         return isUpdate;
164     }
165
166     public void setUpdate(boolean isUpdate) {
167         this.isUpdate = isUpdate;
168     }
169     
170     public abstract Map<String, NodeTypeInfo> extractTypesInfo();
171     
172     /**
173      * Get the data types defined in the CSAR
174      * 
175      * @return map with the data type name as key and representaion of the data type defintion as value
176      */
177     public abstract Map<String, Object> getDataTypes();
178
179     public Map<String, Object> getPolicyTypes() {
180         if (policytypeDefinitions == null) {
181             policytypeDefinitions = new HashMap<>();
182             policytypeDefinitions.putAll(getTypesFromTemplate(mappedToscaMainTemplate, TypeUtils.ToscaTagNamesEnum.POLICY_TYPES));
183         }
184         return policytypeDefinitions;
185     }
186     
187     @SuppressWarnings("unchecked")
188     protected Map<String, Object> getTypesFromTemplate(final Map<String, Object> mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum type) {
189         final Either<Object, ResultStatusEnum> dataTypesEither = findToscaElement(mappedToscaTemplate, type,
190                         ToscaElementTypeEnum.MAP);
191         if (dataTypesEither != null && dataTypesEither.isLeft()) {
192             return (Map<String, Object>) dataTypesEither.left().value();
193         }
194         return Collections.emptyMap();
195     }
196
197     protected Set<String> findNodeTypesUsedInNodeTemplates(final Map<String, Map<String, Object>> nodeTemplates) {
198         final Set<String> nodeTypes = new HashSet<>();
199         for (final Map<String, Object> nodeTemplate : nodeTemplates.values()) {
200             nodeTypes.add((String) nodeTemplate.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName()));
201         }
202         return nodeTypes;
203     }
204
205     @SuppressWarnings("unchecked")
206     protected NodeTypeInfo buildNodeTypeInfo(final Map.Entry<String, Object> nodeType, final String templateFileName,
207                                            final Map<String, Object> mappedToscaTemplate) {
208         final NodeTypeInfo nodeTypeInfo = new NodeTypeInfo();
209         nodeTypeInfo.setSubstitutionMapping(false);
210         nodeTypeInfo.setNested(true);
211         nodeTypeInfo.setType(nodeType.getKey());
212         nodeTypeInfo.setTemplateFileName(templateFileName);
213         nodeTypeInfo.setMappedToscaTemplate(buildToscaTemplateForNode(nodeType.getKey(), mappedToscaTemplate));
214         final Map<String, Object> nodeTypeMap = (Map<String, Object>) nodeType.getValue();
215         final List<String> derivedFrom = new ArrayList<>();
216         derivedFrom.add((String) nodeTypeMap.get(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()));
217         nodeTypeInfo.setDerivedFrom(derivedFrom);
218         return nodeTypeInfo;
219     }
220
221     @SuppressWarnings("unchecked")
222     private Map<String, Object> buildToscaTemplateForNode(final String nodeTypeName, final Map<String, Object> mappedToscaTemplate) {
223         final Map<String, Object> mappedToscaTemplateforNode = new HashMap<>(mappedToscaTemplate);
224         final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
225             ToscaElementTypeEnum.MAP);
226         final Map<String, Object> nodeTypes = new HashMap<>();
227         if (nodeTypesEither.isLeft()) {
228             final Map<String, Object> allNodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
229             nodeTypes.put(nodeTypeName, allNodeTypes.get(nodeTypeName));
230         }
231         mappedToscaTemplateforNode.put(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName(), nodeTypes);
232         return mappedToscaTemplateforNode;
233     }
234
235     /**
236      * Gets the software information yaml path from the csar file map.
237      *
238      * @return the software information yaml path if it is present in the csar file map
239      */
240     public Optional<String> getSoftwareInformationPath() {
241         if (MapUtils.isEmpty(csar)) {
242             return Optional.empty();
243         }
244         final NonManoFolderType softwareInformationType = nonManoConfiguration.getNonManoType(NonManoArtifactType.ONAP_SW_INFORMATION);
245         return csar.keySet().stream().filter(filePath -> filePath.startsWith(softwareInformationType.getPath())).findFirst();
246     }
247 }