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.core.utilities.yaml.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 mdcDataDebugMessage.debugExitMessage("file", parentFileName);
233 Optional<InputStream> fileContent = globalContext.getFileContent(parentFileName);
234 if (fileContent.isPresent()) {
235 parentHeatOrchestrationTemplate =
236 new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
238 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
239 LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
240 ErrorLevel.ERROR.name(), LoggerErrorCode.DATA_ERROR.getErrorCode(),
241 LoggerErrorDescription.EMPTY_FILE);
242 throw new Exception("The file '" + parentFileName + "' has no content");
244 } catch (Exception exception) {
245 mdcDataDebugMessage.debugExitMessage("file", parentFileName);
248 Map<String, Parameter> parentParameters = parentHeatOrchestrationTemplate.getParameters();
249 Map<String, Parameter> nestedParameters = nestedHeatOrchestrationTemplate.getParameters();
250 Set<String> nestedParametersNames =
251 nestedParameters == null ? null : nestedHeatOrchestrationTemplate.getParameters().keySet();
253 checkNoMissingParameterInNested(parentFileName, nestedFileName, resourceName,
254 resourceFileProperties, nestedParametersNames, globalContext);
255 checkNestedInputValuesAlignWithType(parentFileName, nestedFileName, parentParameters,
256 nestedParameters, resourceName, resource, indexVarValue, globalContext);
258 mdcDataDebugMessage.debugExitMessage("file", parentFileName);
262 private static void checkNoMissingParameterInNested(String parentFileName, String nestedFileName,
264 Set<String> resourceFileProperties,
265 Set<String> nestedParametersNames,
266 GlobalValidationContext globalContext) {
268 mdcDataDebugMessage.debugEntryMessage("nested file", nestedFileName);
270 if (CollectionUtils.isNotEmpty(nestedParametersNames)) {
271 resourceFileProperties
273 .filter(propertyName -> !nestedParametersNames.contains(propertyName))
274 .forEach(propertyName -> globalContext
275 .addMessage(parentFileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
276 .getErrorWithParameters(Messages
277 .MISSING_PARAMETER_IN_NESTED.getErrorMessage(),
278 nestedFileName, resourceName, propertyName),
279 LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
280 LoggerErrorDescription.MISSING_PARAMETER_IN_NESTED));
283 mdcDataDebugMessage.debugExitMessage("nested file", nestedFileName);
287 private static void checkNestedInputValuesAlignWithType(String parentFileName,
288 String nestedFileName,
289 Map<String, Parameter> parentParameters,
290 Map<String, Parameter> nestedParameters,
291 String resourceName, Resource resource,
292 Optional<String> indexVarValue,
293 GlobalValidationContext globalContext) {
296 mdcDataDebugMessage.debugEntryMessage("nested file", nestedFileName);
298 Map<String, Object> properties = resource.getProperties();
299 for (Map.Entry<String, Object> propertyEntry : properties.entrySet()) {
300 String parameterName = propertyEntry.getKey();
301 Object parameterInputValue = propertyEntry.getValue();
303 if (Objects.nonNull(parameterInputValue)) {
304 if (parameterInputValue instanceof String) {
305 if (indexVarValue.isPresent() && indexVarValue.get().equals(parameterInputValue)) {
306 parameterInputValue = 3; //indexVarValue is actually number value in runtime
308 validateStaticValueForNestedInputParameter(parentFileName, nestedFileName, resourceName,
309 parameterName, parameterInputValue, nestedParameters.get(parameterName),
315 mdcDataDebugMessage.debugExitMessage("nested file", nestedFileName);
318 private static void validateStaticValueForNestedInputParameter(String parentFileName,
319 String nestedFileName,
321 String parameterName,
323 Parameter parameterInNested,
324 GlobalValidationContext
328 mdcDataDebugMessage.debugEntryMessage("nested file", nestedFileName);
330 if (parameterInNested == null) {
333 if (!DefinedHeatParameterTypes
334 .isValueIsFromGivenType(staticValue, parameterInNested.getType())) {
335 globalContext.addMessage(parentFileName, ErrorLevel.WARNING, ErrorMessagesFormatBuilder
336 .getErrorWithParameters(Messages
337 .WRONG_VALUE_TYPE_ASSIGNED_NESTED_INPUT.getErrorMessage(),
338 resourceName, parameterName, nestedFileName),
339 LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
340 LoggerErrorDescription.WRONG_VALUE_ASSIGNED_NESTED_PARAMETER);
343 mdcDataDebugMessage.debugExitMessage("nested file", nestedFileName);
348 * Is nested loop exist in file boolean.
350 * @param callingFileName the calling file name
351 * @param nestedFileName the nested file name
352 * @param filesInLoop the files in loop
353 * @param globalContext the global context
354 * @return the boolean
356 public static boolean isNestedLoopExistInFile(String callingFileName, String nestedFileName,
357 List<String> filesInLoop,
358 GlobalValidationContext globalContext) {
361 mdcDataDebugMessage.debugEntryMessage("file", callingFileName);
363 HeatOrchestrationTemplate nestedHeatOrchestrationTemplate;
365 Optional<InputStream> fileContent = globalContext.getFileContent(nestedFileName);
366 if (fileContent.isPresent()) {
367 nestedHeatOrchestrationTemplate =
368 new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
370 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
371 LoggerTragetServiceName.VALIDATE_NESTING_LOOPS, ErrorLevel.ERROR.name(),
372 LoggerErrorCode.DATA_ERROR.getErrorCode(), LoggerErrorDescription.EMPTY_FILE);
373 throw new Exception("The file '" + nestedFileName + "' has no content");
376 } catch (Exception exception) {
377 logger.warn("HEAT Validator will not be executed on file " + nestedFileName
378 + " due to illegal HEAT format");
380 mdcDataDebugMessage.debugExitMessage("file", callingFileName);
383 filesInLoop.add(nestedFileName);
384 Collection<Resource> nestedResources =
385 nestedHeatOrchestrationTemplate.getResources() == null ? null
386 : nestedHeatOrchestrationTemplate.getResources().values();
387 if (CollectionUtils.isNotEmpty(nestedResources)) {
388 for (Resource resource : nestedResources) {
389 String resourceType = resource.getType();
391 if (Objects.nonNull(resourceType) && isNestedResource(resourceType)) {
392 mdcDataDebugMessage.debugExitMessage("file", callingFileName);
393 return resourceType.equals(callingFileName) || !filesInLoop.contains(resourceType)
394 && isNestedLoopExistInFile(callingFileName, resourceType, filesInLoop, globalContext);
399 mdcDataDebugMessage.debugExitMessage("file", callingFileName);
405 * Loop over output map and validate get attr from nested.
407 * @param fileName the file name
408 * @param outputMap the output map
409 * @param heatOrchestrationTemplate the heat orchestration template
410 * @param globalContext the global context
412 @SuppressWarnings("unchecked")
413 public static void loopOverOutputMapAndValidateGetAttrFromNested(String fileName,
414 Map<String, Output> outputMap,
415 HeatOrchestrationTemplate
416 heatOrchestrationTemplate,
417 GlobalValidationContext
419 for (Output output : outputMap.values()) {
420 Object outputValue = output.getValue();
421 if (outputValue != null && outputValue instanceof Map) {
422 Map<String, Object> outputValueMap = (Map<String, Object>) outputValue;
423 List<String> getAttrValue =
424 (List<String>) outputValueMap.get(ResourceReferenceFunctions.GET_ATTR.getFunction());
425 if (!CollectionUtils.isEmpty(getAttrValue)) {
426 String resourceName = getAttrValue.get(0);
427 Object attNameObject = getAttrValue.get(1);
428 if (!(attNameObject instanceof String)) {
431 String attName = getAttrValue.get(1);
432 String resourceType =
433 getResourceTypeFromResourcesMap(resourceName, heatOrchestrationTemplate);
435 if (Objects.nonNull(resourceType)
436 && isNestedResource(resourceType)) {
437 handleGetAttrNestedResource(fileName, globalContext, resourceName, attName,
445 private static void handleGetAttrNestedResource(String fileName,
446 GlobalValidationContext globalContext,
447 String resourceName, String attName,
448 String resourceType) {
449 Map<String, Output> nestedOutputMap;
450 HeatOrchestrationTemplate nestedHeatOrchestrationTemplate;
452 Optional<InputStream> fileContent = globalContext.getFileContent(resourceType);
453 if (fileContent.isPresent()) {
454 nestedHeatOrchestrationTemplate =
455 new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
458 .createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
459 LoggerTragetServiceName.VALIDATE_GET_ATTR_FROM_NESTED,
460 ErrorLevel.ERROR.name(), LoggerErrorCode.DATA_ERROR.getErrorCode(),
461 LoggerErrorDescription.EMPTY_FILE);
462 throw new Exception("The file '" + resourceType + "' has no content");
464 } catch (Exception exception) {
467 nestedOutputMap = nestedHeatOrchestrationTemplate.getOutputs();
469 if (MapUtils.isEmpty(nestedOutputMap) || !nestedOutputMap.containsKey(attName)) {
470 globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
471 .getErrorWithParameters(Messages.GET_ATTR_NOT_FOUND.getErrorMessage(),
472 attName, resourceName),
473 LoggerTragetServiceName.VALIDATE_GET_ATTR_FROM_NESTED,
474 LoggerErrorDescription.GET_ATTR_NOT_FOUND);
478 public static boolean isNestedResource(String resourceType) {
479 return resourceType.contains(".yaml") || resourceType.contains(".yml");
482 private static String getResourceTypeFromResourcesMap(String resourceName,
483 HeatOrchestrationTemplate
484 heatOrchestrationTemplate) {
485 return heatOrchestrationTemplate.getResources().get(resourceName).getType();
489 * Validate env content environment.
491 * @param fileName the file name
492 * @param envFileName the env file name
493 * @param globalContext the global context
494 * @return the environment
496 public static Environment validateEnvContent(String fileName, String envFileName,
497 GlobalValidationContext globalContext) {
500 mdcDataDebugMessage.debugEntryMessage("env file", envFileName);
502 Environment envContent = null;
504 Optional<InputStream> fileContent = globalContext.getFileContent(envFileName);
505 if (fileContent.isPresent()) {
506 envContent = new YamlUtil().yamlToObject(fileContent.get(), Environment.class);
508 MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
509 LoggerTragetServiceName.VALIDATE_ENV_FILE, ErrorLevel.ERROR.name(),
510 LoggerErrorCode.DATA_ERROR.getErrorCode(), LoggerErrorDescription.EMPTY_FILE);
511 throw new Exception("The file '" + envFileName + "' has no content");
513 } catch (Exception exception) {
514 mdcDataDebugMessage.debugExitMessage("env file", envFileName);
521 public static String getResourceGroupResourceName(String resourceCallingToResourceGroup) {
522 return "OS::Heat::ResourceGroup in " + resourceCallingToResourceGroup;