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;
74 private String csarVersionId;
77 private Map<String, byte[]> csar;
79 private String mainTemplateName;
81 private String mainTemplateContent;
83 private Map<String, Object> mappedToscaMainTemplate;
85 private Map<String, String> createdNodesToscaResourceNames;
86 private Queue<String> cvfcToCreateQueue;
87 private boolean isUpdate;
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;
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;
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);
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);
119 return globalSubstitutesInCsar;
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;
129 CsarInfo(final NonManoConfiguration nonManoConfiguration) {
130 this.nonManoConfiguration = nonManoConfiguration;
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));
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;
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);
157 public void addNodeToQueue(String nodeName) {
158 if (!cvfcToCreateQueue.contains(nodeName)) {
159 cvfcToCreateQueue.add(nodeName);
161 log.debug("Failed to validate complex VFC {}. Loop detected, VSP {}. ", nodeName, getVfResourceName());
162 throw new ByActionStatusComponentException(ActionStatus.CFVC_LOOP_DETECTED, getVfResourceName(), nodeName);
166 public void removeNodeFromQueue() {
167 cvfcToCreateQueue.remove();
170 public boolean isUpdate() {
174 public void setUpdate(boolean isUpdate) {
175 this.isUpdate = isUpdate;
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);
184 if (CollectionUtils.isNotEmpty(globalSubstitutes)) {
185 setDerivedFrom(nodeTypesInfo);
186 addGlobalSubstitutionsToNodeTypes(nodeTypesUsedInNodeTemplates, nodeTypesInfo);
189 markNestedVfc(getMappedToscaMainTemplate(), nodeTypesInfo);
190 return nodeTypesInfo;
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));
201 datatypeDefinitions.putAll(getTypesFromTemplate(mappedToscaMainTemplate, TypeUtils.ToscaTagNamesEnum.DATA_TYPES));
203 return datatypeDefinitions;
206 public Map<String, Object> getPolicyTypes() {
207 if (policytypeDefinitions == null) {
208 policytypeDefinitions = new HashMap<>();
209 policytypeDefinitions.putAll(getTypesFromTemplate(mappedToscaMainTemplate, TypeUtils.ToscaTagNamesEnum.POLICY_TYPES));
211 return policytypeDefinitions;
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();
221 return Collections.emptyMap();
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));
240 private boolean isAServiceTemplate(final String filePath) {
241 return Pattern.compile(CsarUtils.SERVICE_TEMPLATE_PATH_PATTERN).matcher(filePath).matches();
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()));
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);
264 return ResultStatusEnum.OK;
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();
275 return Collections.emptySet();
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);
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);
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);
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));
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);
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));
354 mappedToscaTemplateforNode.put(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName(), nodeTypes);
355 return mappedToscaTemplateforNode;
359 * Gets the software information yaml path from the csar file map.
361 * @return the software information yaml path if it is present in the csar file map
363 public Optional<String> getSoftwareInformationPath() {
364 if (MapUtils.isEmpty(csar)) {
365 return Optional.empty();
367 final NonManoFolderType softwareInformationType = nonManoConfiguration.getNonManoType(NonManoArtifactType.ONAP_SW_INFORMATION);
368 return csar.keySet().stream().filter(filePath -> filePath.startsWith(softwareInformationType.getPath())).findFirst();