2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ================================================================================
22 package org.openecomp.sdc.be.components.csar;
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;
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;
36 import java.util.Optional;
37 import java.util.PriorityQueue;
38 import java.util.Queue;
40 import java.util.regex.Pattern;
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;
60 public class CsarInfo {
62 private static final Logger log = Logger.getLogger(CsarInfo.class);
63 private final NonManoConfiguration nonManoConfiguration;
66 private String vfResourceName;
69 private User modifier;
72 private String csarUUID;
75 private Map<String, byte[]> csar;
77 private String mainTemplateName;
79 private String mainTemplateContent;
81 private Map<String, Object> mappedToscaMainTemplate;
83 private Map<String, String> createdNodesToscaResourceNames;
84 private Queue<String> cvfcToCreateQueue;
85 private boolean isUpdate;
87 private Map<String, Resource> createdNodes;
88 private Map<String, Object> datatypeDefinitions;
89 private List<Map.Entry<String, byte[]>> globalSubstitutes;
92 @SuppressWarnings("unchecked")
93 public CsarInfo(User modifier, String csarUUID, Map<String, byte[]> csar, String vfResourceName, String mainTemplateName,
94 String mainTemplateContent, boolean isUpdate) {
95 this.vfResourceName = vfResourceName;
96 this.modifier = modifier;
97 this.csarUUID = csarUUID;
99 this.mainTemplateName = mainTemplateName;
100 this.mainTemplateContent = mainTemplateContent;
101 this.mappedToscaMainTemplate = (Map<String, Object>) new Yaml().load(mainTemplateContent);
102 this.createdNodesToscaResourceNames = new HashMap<>();
103 this.cvfcToCreateQueue = new PriorityQueue<>();
104 this.isUpdate = isUpdate;
105 this.createdNodes = new HashMap<>();
106 this.nonManoConfiguration = NonManoConfigurationManager.getInstance().getNonManoConfiguration();
107 this.globalSubstitutes = getGlobalSubstitutes(csar);
110 private List<Map.Entry<String, byte[]>> getGlobalSubstitutes(final Map<String, byte[]> csar){
111 final List<Map.Entry<String, byte[]>> globalSubstitutesInCsar = new ArrayList<>();
112 for (Map.Entry<String, byte[]> entry : csar.entrySet()) {
113 if (isAServiceTemplate(entry.getKey()) && isGlobalSubstitute(entry.getKey())) {
114 globalSubstitutesInCsar.add(entry);
117 return globalSubstitutesInCsar;
121 CsarInfo(final NonManoConfiguration nonManoConfiguration) {
122 this.nonManoConfiguration = nonManoConfiguration;
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));
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;
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);
149 public void addNodeToQueue(String nodeName) {
150 if (!cvfcToCreateQueue.contains(nodeName)) {
151 cvfcToCreateQueue.add(nodeName);
153 log.debug("Failed to validate complex VFC {}. Loop detected, VSP {}. ", nodeName, getVfResourceName());
154 throw new ByActionStatusComponentException(ActionStatus.CFVC_LOOP_DETECTED, getVfResourceName(), nodeName);
158 public void removeNodeFromQueue() {
159 cvfcToCreateQueue.remove();
162 public boolean isUpdate() {
166 public void setUpdate(boolean isUpdate) {
167 this.isUpdate = isUpdate;
170 public Map<String, NodeTypeInfo> extractTypesInfo() {
171 Map<String, NodeTypeInfo> nodeTypesInfo = new HashMap<>();
172 final Set<String> nodeTypesUsedInNodeTemplates = new HashSet<>();
173 for (Map.Entry<String, byte[]> entry : getCsar().entrySet()) {
174 extractNodeTypeInfo(nodeTypesInfo, nodeTypesUsedInNodeTemplates, entry);
176 if (CollectionUtils.isNotEmpty(globalSubstitutes)) {
177 setDerivedFrom(nodeTypesInfo);
178 addGlobalSubstitutionsToNodeTypes(nodeTypesUsedInNodeTemplates, nodeTypesInfo);
181 markNestedVfc(getMappedToscaMainTemplate(), nodeTypesInfo);
182 return nodeTypesInfo;
185 public Map<String, Object> getDataTypes() {
186 if (datatypeDefinitions == null) {
187 datatypeDefinitions = new HashMap<>();
188 for (Map.Entry<String, byte[]> entry : globalSubstitutes) {
189 final String yamlFileContents = new String(entry.getValue());
190 final Map<String, Object> mappedToscaTemplate = new Yaml().load(yamlFileContents);
191 datatypeDefinitions.putAll(getDataTypesFromTemplate(mappedToscaTemplate));
193 datatypeDefinitions.putAll(getDataTypesFromTemplate(mappedToscaMainTemplate));
195 return datatypeDefinitions;
198 @SuppressWarnings("unchecked")
199 private Map<String, Object> getDataTypesFromTemplate(final Map<String, Object> mappedToscaTemplate) {
200 final Either<Object, ResultStatusEnum> dataTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.DATA_TYPES,
201 ToscaElementTypeEnum.MAP);
202 if (dataTypesEither != null && dataTypesEither.isLeft()) {
203 return (Map<String, Object>) dataTypesEither.left().value();
205 return Collections.emptyMap();
208 @SuppressWarnings("unchecked")
209 private void extractNodeTypeInfo(Map<String, NodeTypeInfo> nodeTypesInfo,
210 final Set<String> nodeTypesUsedInNodeTemplates, Map.Entry<String, byte[]> entry) {
211 if (isAServiceTemplate(entry.getKey()) && !isGlobalSubstitute(entry.getKey())) {
212 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(new String(entry.getValue()));
213 findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.SUBSTITUTION_MAPPINGS, ToscaElementTypeEnum.MAP).right()
214 .on(sub -> handleSubstitutionMappings(nodeTypesInfo, entry, mappedToscaTemplate, (Map<String, Object>) sub));
215 final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate,
216 TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES, ToscaElementTypeEnum.MAP);
217 if (nodeTypesEither.isLeft()) {
218 final Map<String, Map<String, Object>> nodeTemplates = (Map<String, Map<String, Object>>) nodeTypesEither.left().value();
219 nodeTypesUsedInNodeTemplates.addAll(findNodeTypesUsedInNodeTemplates(nodeTemplates));
224 private boolean isAServiceTemplate(final String filePath) {
225 return Pattern.compile(CsarUtils.SERVICE_TEMPLATE_PATH_PATTERN).matcher(filePath).matches();
228 private Set<String> findNodeTypesUsedInNodeTemplates(final Map<String, Map<String, Object>> nodeTemplates) {
229 final Set<String> nodeTypes = new HashSet<>();
230 for (final Map<String, Object> nodeTemplate : nodeTemplates.values()) {
231 nodeTypes.add((String) nodeTemplate.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName()));
236 private ResultStatusEnum handleSubstitutionMappings(Map<String, NodeTypeInfo> nodeTypesInfo, Map.Entry<String, byte[]> entry,
237 Map<String, Object> mappedToscaTemplate, Map<String, Object> substitutionMappings) {
238 final Set<String> nodeTypesDefinedInTemplate = findNodeTypesDefinedInTemplate(mappedToscaTemplate);
239 if (substitutionMappings.containsKey(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()) && !nodeTypesDefinedInTemplate
240 .contains(substitutionMappings.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()))) {
241 NodeTypeInfo nodeTypeInfo = new NodeTypeInfo();
242 nodeTypeInfo.setSubstitutionMapping(true);
243 nodeTypeInfo.setType((String) substitutionMappings.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPE.getElementName()));
244 nodeTypeInfo.setTemplateFileName(entry.getKey());
245 nodeTypeInfo.setMappedToscaTemplate(mappedToscaTemplate);
246 nodeTypesInfo.put(nodeTypeInfo.getType(), nodeTypeInfo);
248 return ResultStatusEnum.OK;
251 @SuppressWarnings("unchecked")
252 private Set<String> findNodeTypesDefinedInTemplate(final Map<String, Object> mappedToscaTemplate) {
253 final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
254 ToscaElementTypeEnum.MAP);
255 if (nodeTypesEither.isLeft()) {
256 final Map<String, Object> nodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
257 return nodeTypes.keySet();
259 return Collections.emptySet();
262 private boolean isGlobalSubstitute(String fileName) {
263 return fileName.equalsIgnoreCase(Constants.GLOBAL_SUBSTITUTION_TYPES_SERVICE_TEMPLATE) || fileName
264 .equalsIgnoreCase(Constants.ABSTRACT_SUBSTITUTE_GLOBAL_TYPES_SERVICE_TEMPLATE);
267 @SuppressWarnings("unchecked")
268 private void setDerivedFrom(Map<String, NodeTypeInfo> nodeTypesInfo) {
269 for (Map.Entry<String, byte[]> entry : globalSubstitutes) {
270 String yamlFileContents = new String(entry.getValue());
271 Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(yamlFileContents);
272 Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
273 ToscaElementTypeEnum.MAP);
274 if (nodeTypesEither.isLeft()) {
275 Map<String, Object> nodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
276 for (Map.Entry<String, Object> nodeType : nodeTypes.entrySet()) {
277 processNodeType(nodeTypesInfo, nodeType);
283 @SuppressWarnings("unchecked")
284 private void processNodeType(Map<String, NodeTypeInfo> nodeTypesInfo, Map.Entry<String, Object> nodeType) {
285 Map<String, Object> nodeTypeMap = (Map<String, Object>) nodeType.getValue();
286 if (nodeTypeMap.containsKey(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()) && nodeTypesInfo.containsKey(nodeType.getKey())) {
287 NodeTypeInfo nodeTypeInfo = nodeTypesInfo.get(nodeType.getKey());
288 List<String> derivedFrom = new ArrayList<>();
289 derivedFrom.add((String) nodeTypeMap.get(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()));
290 nodeTypeInfo.setDerivedFrom(derivedFrom);
294 @SuppressWarnings("unchecked")
295 private void addGlobalSubstitutionsToNodeTypes(final Set<String> nodeTypesUsedInNodeTemplates, final Map<String, NodeTypeInfo> nodeTypesInfo) {
296 for (Map.Entry<String, byte[]> entry : globalSubstitutes) {
297 final String yamlFileContents = new String(entry.getValue());
298 final Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(yamlFileContents);
299 final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
300 ToscaElementTypeEnum.MAP);
301 if (nodeTypesEither.isLeft()) {
302 final Map<String, Object> nodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
303 for (final Map.Entry<String, Object> nodeType : nodeTypes.entrySet()) {
304 if (!nodeTypesInfo.containsKey(nodeType.getKey()) && nodeTypesUsedInNodeTemplates.contains(nodeType.getKey())) {
305 nodeTypesInfo.put(nodeType.getKey(), buildNodeTypeInfo(nodeType, entry.getKey(), mappedToscaTemplate));
312 @SuppressWarnings("unchecked")
313 private NodeTypeInfo buildNodeTypeInfo(final Map.Entry<String, Object> nodeType, final String templateFileName,
314 final Map<String, Object> mappedToscaTemplate) {
315 final NodeTypeInfo nodeTypeInfo = new NodeTypeInfo();
316 nodeTypeInfo.setSubstitutionMapping(false);
317 nodeTypeInfo.setNested(true);
318 nodeTypeInfo.setType(nodeType.getKey());
319 nodeTypeInfo.setTemplateFileName(templateFileName);
320 nodeTypeInfo.setMappedToscaTemplate(buildToscaTemplateForNode(nodeType.getKey(), mappedToscaTemplate));
321 final Map<String, Object> nodeTypeMap = (Map<String, Object>) nodeType.getValue();
322 final List<String> derivedFrom = new ArrayList<>();
323 derivedFrom.add((String) nodeTypeMap.get(TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName()));
324 nodeTypeInfo.setDerivedFrom(derivedFrom);
328 @SuppressWarnings("unchecked")
329 private Map<String, Object> buildToscaTemplateForNode(final String nodeTypeName, final Map<String, Object> mappedToscaTemplate) {
330 final Map<String, Object> mappedToscaTemplateforNode = new HashMap<>(mappedToscaTemplate);
331 final Either<Object, ResultStatusEnum> nodeTypesEither = findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES,
332 ToscaElementTypeEnum.MAP);
333 final Map<String, Object> nodeTypes = new HashMap<>();
334 if (nodeTypesEither.isLeft()) {
335 final Map<String, Object> allNodeTypes = (Map<String, Object>) nodeTypesEither.left().value();
336 nodeTypes.put(nodeTypeName, allNodeTypes.get(nodeTypeName));
338 mappedToscaTemplateforNode.put(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName(), nodeTypes);
339 return mappedToscaTemplateforNode;
343 * Gets the software information yaml path from the csar file map.
345 * @return the software information yaml path if it is present in the csar file map
347 public Optional<String> getSoftwareInformationPath() {
348 if (MapUtils.isEmpty(csar)) {
349 return Optional.empty();
351 final NonManoFolderType softwareInformationType = nonManoConfiguration.getNonManoType(NonManoArtifactType.ONAP_SW_INFORMATION);
352 return csar.keySet().stream().filter(filePath -> filePath.startsWith(softwareInformationType.getPath())).findFirst();