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=========================================================
21 package org.openecomp.sdc.validation.impl.util;
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.sdc.tosca.services.YamlUtil;
26 import org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder;
27 import org.openecomp.core.validation.types.GlobalValidationContext;
28 import org.openecomp.sdc.common.errors.Messages;
29 import org.openecomp.sdc.datatypes.error.ErrorLevel;
30 import org.openecomp.sdc.heat.datatypes.DefinedHeatParameterTypes;
31 import org.openecomp.sdc.heat.datatypes.model.Environment;
32 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
33 import org.openecomp.sdc.heat.datatypes.model.Output;
34 import org.openecomp.sdc.heat.datatypes.model.Parameter;
35 import org.openecomp.sdc.heat.datatypes.model.Resource;
36 import org.openecomp.sdc.heat.datatypes.model.ResourceReferenceFunctions;
37 import org.openecomp.sdc.heat.services.HeatStructureUtil;
38 import org.openecomp.sdc.logging.api.Logger;
39 import org.openecomp.sdc.logging.api.LoggerFactory;
40 import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage;
41 import org.openecomp.sdc.logging.context.impl.MdcDataErrorMessage;
42 import org.openecomp.sdc.logging.types.LoggerConstants;
43 import org.openecomp.sdc.logging.types.LoggerErrorCode;
44 import org.openecomp.sdc.logging.types.LoggerErrorDescription;
45 import org.openecomp.sdc.logging.types.LoggerTragetServiceName;
46 import org.openecomp.sdc.validation.impl.validators.HeatValidator;
48 import java.io.InputStream;
49 import java.util.Collection;
50 import java.util.List;
52 import java.util.Objects;
53 import java.util.Optional;
57 public class HeatValidationService {
59 private static final Logger logger = (Logger) LoggerFactory.getLogger(HeatValidator.class);
60 private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage();
63 * Check artifacts existence.
65 * @param fileName the file name
66 * @param artifactsNames the artifacts names
67 * @param globalContext the global context
69 public static void checkArtifactsExistence(String fileName, Set<String> artifactsNames,
70 GlobalValidationContext globalContext) {
73 mdcDataDebugMessage.debugEntryMessage("file", fileName);
76 .filter(artifactName -> !globalContext.getFileContextMap().containsKey(artifactName))
77 .forEach(artifactName -> {
78 globalContext.addMessage(fileName,
79 ErrorLevel.ERROR, ErrorMessagesFormatBuilder
80 .getErrorWithParameters(Messages.MISSING_ARTIFACT.getErrorMessage(),
81 artifactName), LoggerTragetServiceName.VALIDATE_ARTIFACTS_EXISTENCE,
82 LoggerErrorDescription.MISSING_FILE);
85 mdcDataDebugMessage.debugExitMessage("file", fileName);
89 * Check resource existence from resources map.
91 * @param fileName the file name
92 * @param resourcesNames the resources names
93 * @param valuesToSearchIn the values to search in
94 * @param globalContext the global context
96 public static void checkResourceExistenceFromResourcesMap(String fileName,
97 Set<String> resourcesNames,
98 Collection<?> valuesToSearchIn,
99 GlobalValidationContext globalContext) {
102 mdcDataDebugMessage.debugEntryMessage("file", fileName);
104 if (CollectionUtils.isNotEmpty(valuesToSearchIn)) {
105 for (Object value : valuesToSearchIn) {
106 if (value instanceof Resource) {
107 Resource resource = (Resource) value;
109 Collection<Object> resourcePropertiesValues =
110 resource.getProperties() == null ? null : resource.getProperties().values();
111 if (CollectionUtils.isNotEmpty(resourcePropertiesValues)) {
112 for (Object propertyValue : resourcePropertiesValues) {
113 handleReferencedResources(fileName, propertyValue, resourcesNames, globalContext);
116 } else if (value instanceof Output) {
117 Output output = (Output) value;
118 Object outputsValue = output.getValue();
119 handleReferencedResources(fileName, outputsValue, resourcesNames, globalContext);
124 mdcDataDebugMessage.debugExitMessage("file", fileName);
127 private static void handleReferencedResources(String fileName, Object valueToSearchReferencesIn,
128 Set<String> resourcesNames,
129 GlobalValidationContext globalContext) {
132 mdcDataDebugMessage.debugEntryMessage("file", fileName);
134 Set<String> referencedResourcesNames = HeatStructureUtil
135 .getReferencedValuesByFunctionName(fileName,
136 ResourceReferenceFunctions.GET_RESOURCE.getFunction(), valueToSearchReferencesIn,
138 if (CollectionUtils.isNotEmpty(referencedResourcesNames)) {
139 checkIfResourceReferenceExist(fileName, resourcesNames, referencedResourcesNames,
143 mdcDataDebugMessage.debugExitMessage("file", fileName);
146 private static void checkIfResourceReferenceExist(String fileName,
147 Set<String> referencedResourcesNames,
148 Set<String> referencedResources,
149 GlobalValidationContext globalContext) {
152 mdcDataDebugMessage.debugEntryMessage("file", fileName);
154 referencedResources.stream()
155 .filter(referencedResource -> !referencedResourcesNames.contains(referencedResource))
156 .forEach(referencedResource -> {
157 globalContext.addMessage(fileName,
158 ErrorLevel.ERROR, ErrorMessagesFormatBuilder
159 .getErrorWithParameters(Messages.REFERENCED_RESOURCE_NOT_FOUND.getErrorMessage(),
161 LoggerTragetServiceName.VALIDATE_RESOURCE_REFERENCE_EXISTENCE,
162 LoggerErrorDescription.RESOURCE_NOT_FOUND);
165 mdcDataDebugMessage.debugExitMessage("file", fileName);
169 * Draw files loop string.
171 * @param filesInPath the files in path
174 public static String drawFilesLoop(List<String> filesInPath) {
175 StringBuilder stringBuilder = new StringBuilder();
176 stringBuilder.append("[");
177 int pathSize = filesInPath.size();
179 for (int i = 0; i < pathSize; i++) {
180 stringBuilder.append(filesInPath.get(i));
181 if (i != pathSize - 1) {
182 stringBuilder.append(" -- ");
185 if (!filesInPath.get(0).equals(filesInPath.get(pathSize - 1))) {
186 stringBuilder.append(" -- ");
187 stringBuilder.append(filesInPath.get(0));
189 stringBuilder.append("]");
191 return stringBuilder.toString();
196 * Check nested parameters.
198 * @param parentFileName the calling nested file name
199 * @param nestedFileName the nested file name
200 * @param resourceName the resource name
201 * @param globalContext the global context
202 * @param resourceFileProperties the resource file properties
204 public static void checkNestedParameters(String parentFileName, String nestedFileName,
205 String resourceName, Resource resource,
206 Set<String> resourceFileProperties,
207 Optional<String> indexVarValue,
208 GlobalValidationContext globalContext) {
211 mdcDataDebugMessage.debugEntryMessage("file", parentFileName);
213 HeatOrchestrationTemplate parentHeatOrchestrationTemplate;
214 HeatOrchestrationTemplate nestedHeatOrchestrationTemplate;
216 Optional<InputStream> fileContent = globalContext.getFileContent(nestedFileName);
217 if (fileContent.isPresent()) {
218 nestedHeatOrchestrationTemplate =
219 new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
221 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
222 LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
223 ErrorLevel.ERROR.name(), LoggerErrorCode.DATA_ERROR.getErrorCode(),
224 LoggerErrorDescription.EMPTY_FILE);
225 throw new Exception("The file '" + nestedFileName + "' has no content");
227 } catch (Exception exception) {
228 logger.debug("",exception);
229 mdcDataDebugMessage.debugExitMessage("file", parentFileName);
234 Optional<InputStream> fileContent = globalContext.getFileContent(parentFileName);
235 if (fileContent.isPresent()) {
236 parentHeatOrchestrationTemplate =
237 new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
239 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
240 LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
241 ErrorLevel.ERROR.name(), LoggerErrorCode.DATA_ERROR.getErrorCode(),
242 LoggerErrorDescription.EMPTY_FILE);
243 throw new Exception("The file '" + parentFileName + "' has no content");
245 } catch (Exception exception) {
246 logger.debug("",exception);
247 mdcDataDebugMessage.debugExitMessage("file", parentFileName);
250 Map<String, Parameter> parentParameters = parentHeatOrchestrationTemplate.getParameters();
251 Map<String, Parameter> nestedParameters = nestedHeatOrchestrationTemplate.getParameters();
252 Set<String> nestedParametersNames =
253 nestedParameters == null ? null : nestedHeatOrchestrationTemplate.getParameters().keySet();
255 checkNoMissingParameterInNested(parentFileName, nestedFileName, resourceName,
256 resourceFileProperties, nestedParametersNames, globalContext);
257 checkNestedInputValuesAlignWithType(parentFileName, nestedFileName, parentParameters,
258 nestedParameters, resourceName, resource, indexVarValue, globalContext);
260 mdcDataDebugMessage.debugExitMessage("file", parentFileName);
264 private static void checkNoMissingParameterInNested(String parentFileName, String nestedFileName,
266 Set<String> resourceFileProperties,
267 Set<String> nestedParametersNames,
268 GlobalValidationContext globalContext) {
270 mdcDataDebugMessage.debugEntryMessage("nested file", nestedFileName);
272 if (CollectionUtils.isNotEmpty(nestedParametersNames)) {
273 resourceFileProperties
275 .filter(propertyName -> !nestedParametersNames.contains(propertyName))
276 .forEach(propertyName -> globalContext
277 .addMessage(parentFileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
278 .getErrorWithParameters(Messages
279 .MISSING_PARAMETER_IN_NESTED.getErrorMessage(),
280 nestedFileName, resourceName, propertyName),
281 LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
282 LoggerErrorDescription.MISSING_PARAMETER_IN_NESTED));
285 mdcDataDebugMessage.debugExitMessage("nested file", nestedFileName);
289 private static void checkNestedInputValuesAlignWithType(String parentFileName,
290 String nestedFileName,
291 Map<String, Parameter> parentParameters,
292 Map<String, Parameter> nestedParameters,
293 String resourceName, Resource resource,
294 Optional<String> indexVarValue,
295 GlobalValidationContext globalContext) {
298 mdcDataDebugMessage.debugEntryMessage("nested file", nestedFileName);
300 Map<String, Object> properties = resource.getProperties();
301 for (Map.Entry<String, Object> propertyEntry : properties.entrySet()) {
302 String parameterName = propertyEntry.getKey();
303 Object parameterInputValue = propertyEntry.getValue();
305 if (Objects.nonNull(parameterInputValue)) {
306 if (parameterInputValue instanceof String) {
307 if (indexVarValue.isPresent() && indexVarValue.get().equals(parameterInputValue)) {
308 parameterInputValue = 3; //indexVarValue is actually number value in runtime
310 validateStaticValueForNestedInputParameter(parentFileName, nestedFileName, resourceName,
311 parameterName, parameterInputValue, nestedParameters.get(parameterName),
317 mdcDataDebugMessage.debugExitMessage("nested file", nestedFileName);
320 private static void validateStaticValueForNestedInputParameter(String parentFileName,
321 String nestedFileName,
323 String parameterName,
325 Parameter parameterInNested,
326 GlobalValidationContext
330 mdcDataDebugMessage.debugEntryMessage("nested file", nestedFileName);
332 if (parameterInNested == null) {
335 if (!DefinedHeatParameterTypes
336 .isValueIsFromGivenType(staticValue, parameterInNested.getType())) {
337 globalContext.addMessage(parentFileName, ErrorLevel.WARNING, ErrorMessagesFormatBuilder
338 .getErrorWithParameters(Messages
339 .WRONG_VALUE_TYPE_ASSIGNED_NESTED_INPUT.getErrorMessage(),
340 resourceName, parameterName, nestedFileName),
341 LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
342 LoggerErrorDescription.WRONG_VALUE_ASSIGNED_NESTED_PARAMETER);
345 mdcDataDebugMessage.debugExitMessage("nested file", nestedFileName);
350 * Is nested loop exist in file boolean.
352 * @param callingFileName the calling file name
353 * @param nestedFileName the nested file name
354 * @param filesInLoop the files in loop
355 * @param globalContext the global context
356 * @return the boolean
358 public static boolean isNestedLoopExistInFile(String callingFileName, String nestedFileName,
359 List<String> filesInLoop,
360 GlobalValidationContext globalContext) {
363 mdcDataDebugMessage.debugEntryMessage("file", callingFileName);
365 HeatOrchestrationTemplate nestedHeatOrchestrationTemplate;
367 Optional<InputStream> fileContent = globalContext.getFileContent(nestedFileName);
368 if (fileContent.isPresent()) {
369 nestedHeatOrchestrationTemplate =
370 new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
372 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
373 LoggerTragetServiceName.VALIDATE_NESTING_LOOPS, ErrorLevel.ERROR.name(),
374 LoggerErrorCode.DATA_ERROR.getErrorCode(), LoggerErrorDescription.EMPTY_FILE);
375 throw new Exception("The file '" + nestedFileName + "' has no content");
378 } catch (Exception exception) {
379 logger.debug("",exception);
380 logger.warn("HEAT Validator will not be executed on file " + nestedFileName
381 + " due to illegal HEAT format");
383 mdcDataDebugMessage.debugExitMessage("file", callingFileName);
386 filesInLoop.add(nestedFileName);
387 Collection<Resource> nestedResources =
388 nestedHeatOrchestrationTemplate.getResources() == null ? null
389 : nestedHeatOrchestrationTemplate.getResources().values();
390 if (CollectionUtils.isNotEmpty(nestedResources)) {
391 for (Resource resource : nestedResources) {
392 String resourceType = resource.getType();
394 if (Objects.nonNull(resourceType) && isNestedResource(resourceType)) {
395 mdcDataDebugMessage.debugExitMessage("file", callingFileName);
396 return resourceType.equals(callingFileName) || !filesInLoop.contains(resourceType)
397 && isNestedLoopExistInFile(callingFileName, resourceType, filesInLoop, globalContext);
402 mdcDataDebugMessage.debugExitMessage("file", callingFileName);
408 * Loop over output map and validate get attr from nested.
410 * @param fileName the file name
411 * @param outputMap the output map
412 * @param heatOrchestrationTemplate the heat orchestration template
413 * @param globalContext the global context
415 @SuppressWarnings("unchecked")
416 public static void loopOverOutputMapAndValidateGetAttrFromNested(String fileName,
417 Map<String, Output> outputMap,
418 HeatOrchestrationTemplate
419 heatOrchestrationTemplate,
420 GlobalValidationContext
422 for (Output output : outputMap.values()) {
423 Object outputValue = output.getValue();
424 if (outputValue != null && outputValue instanceof Map) {
425 Map<String, Object> outputValueMap = (Map<String, Object>) outputValue;
426 List<String> getAttrValue =
427 (List<String>) outputValueMap.get(ResourceReferenceFunctions.GET_ATTR.getFunction());
428 if (!CollectionUtils.isEmpty(getAttrValue)) {
429 String resourceName = getAttrValue.get(0);
430 Object attNameObject = getAttrValue.get(1);
431 if (!(attNameObject instanceof String)) {
434 String attName = getAttrValue.get(1);
435 String resourceType =
436 getResourceTypeFromResourcesMap(resourceName, heatOrchestrationTemplate);
438 if (Objects.nonNull(resourceType)
439 && isNestedResource(resourceType)) {
440 handleGetAttrNestedResource(fileName, globalContext, resourceName, attName,
448 private static void handleGetAttrNestedResource(String fileName,
449 GlobalValidationContext globalContext,
450 String resourceName, String attName,
451 String resourceType) {
452 Map<String, Output> nestedOutputMap;
453 HeatOrchestrationTemplate nestedHeatOrchestrationTemplate;
455 Optional<InputStream> fileContent = globalContext.getFileContent(resourceType);
456 if (fileContent.isPresent()) {
457 nestedHeatOrchestrationTemplate =
458 new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
461 .createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
462 LoggerTragetServiceName.VALIDATE_GET_ATTR_FROM_NESTED,
463 ErrorLevel.ERROR.name(), LoggerErrorCode.DATA_ERROR.getErrorCode(),
464 LoggerErrorDescription.EMPTY_FILE);
465 throw new Exception("The file '" + resourceType + "' has no content");
467 } catch (Exception exception) {
468 logger.debug("",exception);
471 nestedOutputMap = nestedHeatOrchestrationTemplate.getOutputs();
473 if (MapUtils.isEmpty(nestedOutputMap) || !nestedOutputMap.containsKey(attName)) {
474 globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
475 .getErrorWithParameters(Messages.GET_ATTR_NOT_FOUND.getErrorMessage(),
476 attName, resourceName),
477 LoggerTragetServiceName.VALIDATE_GET_ATTR_FROM_NESTED,
478 LoggerErrorDescription.GET_ATTR_NOT_FOUND);
482 public static boolean isNestedResource(String resourceType) {
483 return resourceType.contains(".yaml") || resourceType.contains(".yml");
486 private static String getResourceTypeFromResourcesMap(String resourceName,
487 HeatOrchestrationTemplate
488 heatOrchestrationTemplate) {
489 return heatOrchestrationTemplate.getResources().get(resourceName).getType();
493 * Validate env content environment.
495 * @param fileName the file name
496 * @param envFileName the env file name
497 * @param globalContext the global context
498 * @return the environment
500 public static Environment validateEnvContent(String fileName, String envFileName,
501 GlobalValidationContext globalContext) {
504 mdcDataDebugMessage.debugEntryMessage("env file", envFileName);
506 Environment envContent = null;
508 Optional<InputStream> fileContent = globalContext.getFileContent(envFileName);
509 if (fileContent.isPresent()) {
510 envContent = new YamlUtil().yamlToObject(fileContent.get(), Environment.class);
512 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
513 LoggerTragetServiceName.VALIDATE_ENV_FILE, ErrorLevel.ERROR.name(),
514 LoggerErrorCode.DATA_ERROR.getErrorCode(), LoggerErrorDescription.EMPTY_FILE);
515 throw new Exception("The file '" + envFileName + "' has no content");
517 } catch (Exception exception) {
518 logger.debug("",exception);
519 mdcDataDebugMessage.debugExitMessage("env file", envFileName);
526 public static String getResourceGroupResourceName(String resourceCallingToResourceGroup) {
527 return "OS::Heat::ResourceGroup in " + resourceCallingToResourceGroup;