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.validators;
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.sdc.validation.Validator;
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.manifest.FileData;
32 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
33 import org.openecomp.sdc.heat.datatypes.model.Environment;
34 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
35 import org.openecomp.sdc.heat.datatypes.model.HeatPseudoParameters;
36 import org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes;
37 import org.openecomp.sdc.heat.datatypes.model.Output;
38 import org.openecomp.sdc.heat.datatypes.model.Parameter;
39 import org.openecomp.sdc.heat.datatypes.model.Resource;
40 import org.openecomp.sdc.heat.datatypes.model.ResourceReferenceFunctions;
41 import org.openecomp.sdc.heat.services.HeatStructureUtil;
42 import org.openecomp.sdc.heat.services.manifest.ManifestUtil;
43 import org.openecomp.sdc.logging.api.Logger;
44 import org.openecomp.sdc.logging.api.LoggerFactory;
45 import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage;
46 import org.openecomp.sdc.logging.types.LoggerErrorDescription;
47 import org.openecomp.sdc.logging.types.LoggerTragetServiceName;
48 import org.openecomp.sdc.validation.impl.util.HeatValidationService;
49 import org.openecomp.sdc.validation.util.ValidationUtil;
51 import java.util.Collection;
52 import java.util.HashSet;
54 import java.util.Objects;
57 public class HeatValidator implements Validator {
58 public static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage();
59 protected static Logger logger = (Logger) LoggerFactory.getLogger(HeatValidator.class);
61 private static void validateAllRequiredArtifactsExist(String fileName,
62 HeatOrchestrationTemplate
63 heatOrchestrationTemplate,
64 Set<String> artifacts,
65 GlobalValidationContext globalContext) {
67 mdcDataDebugMessage.debugEntryMessage("file", fileName);
69 Collection<Resource> resourcesValues = heatOrchestrationTemplate.getResources() == null ? null
70 : heatOrchestrationTemplate.getResources().values();
72 if (CollectionUtils.isNotEmpty(resourcesValues)) {
73 for (Resource resource : resourcesValues) {
74 Collection<Object> properties =
75 resource.getProperties() == null ? null : resource.getProperties().values();
76 if (CollectionUtils.isNotEmpty(properties)) {
77 for (Object property : properties) {
78 if (property instanceof Map) {
79 Set<String> artifactNames = HeatStructureUtil
80 .getReferencedValuesByFunctionName(fileName,
81 ResourceReferenceFunctions.GET_FILE.getFunction(), property, globalContext);
82 artifacts.addAll(artifactNames);
83 HeatValidationService.checkArtifactsExistence(fileName, artifactNames, globalContext);
90 mdcDataDebugMessage.debugExitMessage("file", fileName);
95 private static void validateAllResourceReferencesExist(String fileName,
96 HeatOrchestrationTemplate
97 heatOrchestrationTemplate,
98 GlobalValidationContext globalContext) {
100 mdcDataDebugMessage.debugEntryMessage("file", fileName);
102 Set<String> resourcesNames = heatOrchestrationTemplate.getResources() == null ? null
103 : heatOrchestrationTemplate.getResources().keySet();
104 Collection<Resource> resourcesValues = heatOrchestrationTemplate.getResources() == null ? null
105 : heatOrchestrationTemplate.getResources().values();
106 Collection<Output> outputsValues = heatOrchestrationTemplate.getOutputs() == null ? null
107 : heatOrchestrationTemplate.getOutputs().values();
109 HeatValidationService
110 .checkResourceExistenceFromResourcesMap(fileName, resourcesNames, resourcesValues,
112 HeatValidationService
113 .checkResourceExistenceFromResourcesMap(fileName, resourcesNames, outputsValues,
116 mdcDataDebugMessage.debugExitMessage("file", fileName);
122 private static void validateGetParamPointToParameter(String fileName,
123 HeatOrchestrationTemplate
124 heatOrchestrationTemplate,
125 GlobalValidationContext globalContext) {
127 mdcDataDebugMessage.debugEntryMessage("file", fileName);
129 Set<String> parametersNames = heatOrchestrationTemplate.getParameters() == null ? null
130 : heatOrchestrationTemplate.getParameters().keySet();
131 Map<String, Resource> resourcesMap = heatOrchestrationTemplate.getResources();
133 if (CollectionUtils.isNotEmpty(parametersNames) && MapUtils.isNotEmpty(resourcesMap)) {
134 for (Map.Entry<String, Resource> resourceEntry : resourcesMap.entrySet()) {
135 Resource resource = resourceEntry.getValue();
136 Map<String, Object> properties = resource.getProperties();
137 if (MapUtils.isNotEmpty(properties)) {
138 Collection<Object> propertiesValues = properties.values();
139 if (CollectionUtils.isNotEmpty(propertiesValues)) {
140 for (Object propertyObject : propertiesValues) {
141 Set<String> referencedParameterNames = HeatStructureUtil
142 .getReferencedValuesByFunctionName(fileName, "get_param", propertyObject,
145 validateReferenceParams(fileName, resourceEntry.getKey(), parametersNames,
146 referencedParameterNames, globalContext);
153 mdcDataDebugMessage.debugExitMessage("file", fileName);
157 private static void validateReferenceParams(String fileName, String resourceName,
158 Set<String> parametersNamesFromFile,
159 Set<String> referencedParametersNames,
160 GlobalValidationContext globalContext) {
163 mdcDataDebugMessage.debugEntryMessage("file", fileName);
165 for (String parameterName : referencedParametersNames) {
166 if (!isHeatPseudoParameter(parameterName)
167 && !parametersNamesFromFile.contains(parameterName)) {
168 globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
169 .getErrorWithParameters(Messages.REFERENCED_PARAMETER_NOT_FOUND.getErrorMessage(),
170 parameterName, resourceName),
171 LoggerTragetServiceName.VALIDATE_PARAMETER_REFERENCE_EXITENCE,
172 LoggerErrorDescription.PARAMETER_NOT_FOUND);
176 mdcDataDebugMessage.debugExitMessage("file", fileName);
179 private static boolean isHeatPseudoParameter(String parameterName) {
180 return HeatPseudoParameters.getPseudoParameterNames().contains(parameterName);
185 private static void validateGetAttr(String fileName,
186 HeatOrchestrationTemplate heatOrchestrationTemplate,
187 GlobalValidationContext globalContext) {
189 mdcDataDebugMessage.debugEntryMessage("file", fileName);
191 Map<String, Output> outputMap;
192 outputMap = heatOrchestrationTemplate.getOutputs();
194 if (MapUtils.isNotEmpty(outputMap)) {
195 HeatValidationService.loopOverOutputMapAndValidateGetAttrFromNested(fileName, outputMap,
196 heatOrchestrationTemplate, globalContext);
199 mdcDataDebugMessage.debugExitMessage("file", fileName);
202 /* validation 17 + */
203 private static void validateEnvFile(String fileName, String envFileName,
204 HeatOrchestrationTemplate heatOrchestrationTemplate,
205 GlobalValidationContext globalContext) {
208 mdcDataDebugMessage.debugEntryMessage("file", fileName);
210 Environment envContent;
212 if (!envFileName.contains(".env")) {
213 globalContext.addMessage(envFileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
214 .getErrorWithParameters(Messages
215 .WRONG_ENV_FILE_EXTENSION.getErrorMessage(), envFileName),
216 LoggerTragetServiceName.VALIDATE_ENV_FILE, LoggerErrorDescription.WRONG_FILE_EXTENSION);
219 envContent = HeatValidationService.validateEnvContent(fileName, envFileName, globalContext);
220 if (envContent != null) {
221 validateEnvContentIsSubSetOfHeatParameters(envFileName, envContent, globalContext,
222 heatOrchestrationTemplate);
223 validateEnvParametersMatchDefinedHeatParameterTypes(envFileName, envContent, globalContext,
224 heatOrchestrationTemplate);
227 mdcDataDebugMessage.debugExitMessage("file", fileName);
231 private static void validateEnvContentIsSubSetOfHeatParameters(String envFile,
232 Environment envContent,
233 GlobalValidationContext
235 HeatOrchestrationTemplate
236 heatOrchestrationTemplate) {
238 mdcDataDebugMessage.debugEntryMessage("file", envFile);
240 Set<String> parametersNames = heatOrchestrationTemplate.getParameters() == null ? null
241 : heatOrchestrationTemplate.getParameters().keySet();
243 if (MapUtils.isNotEmpty(envContent.getParameters())) {
244 if (CollectionUtils.isNotEmpty(parametersNames)) {
245 for (Map.Entry<String, Object> envEntry : envContent.getParameters().entrySet()) {
246 String envParameter = envEntry.getKey();
247 if (!parametersNames.contains(envParameter)) {
248 globalContext.addMessage(envFile, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
249 .getErrorWithParameters(
250 Messages.ENV_INCLUDES_PARAMETER_NOT_IN_HEAT.getErrorMessage(), envFile,
251 envParameter), LoggerTragetServiceName.VALIDATE_ENV_FILE,
252 LoggerErrorDescription.ENV_PARAMETER_NOT_IN_HEAT);
256 for (Map.Entry<String, Object> envEntry : envContent.getParameters().entrySet()) {
257 globalContext.addMessage(envFile, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
258 .getErrorWithParameters(Messages
259 .ENV_INCLUDES_PARAMETER_NOT_IN_HEAT.getErrorMessage(),
260 envFile, envEntry.getKey()), LoggerTragetServiceName.VALIDATE_ENV_FILE,
261 LoggerErrorDescription.ENV_PARAMETER_NOT_IN_HEAT);
266 mdcDataDebugMessage.debugExitMessage("file", envFile);
270 private static void validateParameterDefaultTypeAlignWithType(String fileName,
271 HeatOrchestrationTemplate
272 heatOrchestrationTemplate,
273 GlobalValidationContext
276 mdcDataDebugMessage.debugEntryMessage("file", fileName);
278 Map<String, Parameter> parametersMap = heatOrchestrationTemplate.getParameters() == null ? null
279 : heatOrchestrationTemplate.getParameters();
281 if (MapUtils.isNotEmpty(parametersMap)) {
282 for (Map.Entry<String, Parameter> parameterEntry : parametersMap.entrySet()) {
283 Parameter parameter = parameterEntry.getValue();
284 String parameterType = parameter.getType();
285 Object parameterDefault = parameter.get_default();
286 if (parameterDefault != null && parameterType != null) {
287 boolean isValueMatchDefault =
288 DefinedHeatParameterTypes.isValueIsFromGivenType(parameterDefault, parameterType);
289 if (!isValueMatchDefault) {
290 globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
291 .getErrorWithParameters(
292 Messages.PARAMETER_DEFAULT_VALUE_NOT_ALIGN_WITH_TYPE.getErrorMessage(),
293 parameterEntry.getKey(), parameterType),
294 LoggerTragetServiceName.VALIDATE_PARAMTER_DEFAULT_MATCH_TYPE,
295 LoggerErrorDescription.PARAMETER_DEFAULT_VALUE_NOT_ALIGNED_WITH_TYPE);
301 mdcDataDebugMessage.debugExitMessage("file", fileName);
305 private static void validateEnvParametersMatchDefinedHeatParameterTypes(String envFile,
306 Environment envContent,
307 GlobalValidationContext globalContext,
308 HeatOrchestrationTemplate heatOrchestrationTemplate) {
311 mdcDataDebugMessage.debugEntryMessage("file", envFile);
313 Map<String, Parameter> heatParameters = heatOrchestrationTemplate.getParameters();
315 if (MapUtils.isNotEmpty(heatParameters) && MapUtils.isNotEmpty(envContent.getParameters())) {
316 for (Map.Entry<String, Object> envEntry : envContent.getParameters().entrySet()) {
317 String parameterName = envEntry.getKey();
318 Object parameterEnvValue = envEntry.getValue();
319 Parameter parameterFromHeatFile = heatParameters.get(parameterName);
320 if (parameterFromHeatFile != null) {
321 String parameterType = parameterFromHeatFile.getType();
322 if (!DefinedHeatParameterTypes.isEmptyValueInEnv(parameterEnvValue)
323 && !DefinedHeatParameterTypes
324 .isValueIsFromGivenType(parameterEnvValue, parameterType)) {
325 globalContext.addMessage(envFile, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
326 .getErrorWithParameters(
327 Messages.PARAMETER_ENV_VALUE_NOT_ALIGN_WITH_TYPE.getErrorMessage(),
328 parameterName), LoggerTragetServiceName.VALIDATE_ENV_PARAMETER_MATCH_TYPE,
329 LoggerErrorDescription.PARAMETER_DEFAULT_VALUE_NOT_ALIGNED_WITH_TYPE);
335 mdcDataDebugMessage.debugExitMessage("file", envFile);
340 public void validate(GlobalValidationContext globalContext) {
341 mdcDataDebugMessage.debugEntryMessage(null, null);
342 ManifestContent manifestContent;
344 manifestContent = ValidationUtil.checkValidationPreCondition(globalContext);
345 } catch (Exception exception) {
349 Map<String, FileData.Type> fileTypeMap = ManifestUtil.getFileTypeMap(manifestContent);
350 Map<String, FileData> fileEnvMap = ManifestUtil.getFileAndItsEnv(manifestContent);
351 Set<String> baseFiles = ManifestUtil.getBaseFiles(manifestContent);
352 Set<String> securityGroupsNamesFromBaseFileOutputs;
353 Set<String> artifacts = new HashSet<>();
356 baseFileName = CollectionUtils.isEmpty(baseFiles) ? null : baseFiles.iterator().next();
357 securityGroupsNamesFromBaseFileOutputs = baseFileName == null ? null
358 : checkForBaseFilePortsExistenceAndReturnSecurityGroupNamesFromOutputsIfNot(baseFileName,
362 globalContext.getFiles().stream()
363 .filter(fileName -> FileData.isHeatFile(fileTypeMap.get(fileName))).forEach(
364 fileName -> validate(fileName, fileEnvMap.get(fileName) == null ? null : fileEnvMap.get(
366 baseFileName == null ? null : baseFileName, artifacts,
367 securityGroupsNamesFromBaseFileOutputs, globalContext));
370 Set<String> manifestArtifacts = ManifestUtil.getArtifacts(manifestContent);
372 globalContext.getFiles().stream()
373 .filter(fileName -> manifestArtifacts.contains(fileName) && !artifacts.contains(fileName))
374 .forEach(fileName -> globalContext.addMessage(fileName, ErrorLevel.WARNING,
375 Messages.ARTIFACT_FILE_NOT_REFERENCED.getErrorMessage(),
376 LoggerTragetServiceName.CHECK_FOR_ORPHAN_ARTIFACTS,
377 LoggerErrorDescription.ARTIFACT_NOT_REFERENCED));
379 mdcDataDebugMessage.debugExitMessage(null, null);
383 private void validate(String fileName, String envFileName, String baseFileName,
384 Set<String> artifacts, Set<String> securityGroupsNamesFromBaseFileOutputs,
385 GlobalValidationContext globalContext) {
386 HeatOrchestrationTemplate
387 heatOrchestrationTemplate = ValidationUtil.checkHeatOrchestrationPreCondition(fileName, globalContext);
390 if (heatOrchestrationTemplate != null) {
391 if (!(fileName.contains(".yaml") || fileName.contains(".yml"))) {
392 globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
393 .getErrorWithParameters(Messages
394 .WRONG_HEAT_FILE_EXTENSION.getErrorMessage(), fileName),
395 LoggerTragetServiceName.CHECK_FOR_VALID_FILE_EXTENTION,
396 LoggerErrorDescription.WRONG_FILE_EXTENSION);
399 validateHeatBaseStructure(fileName, heatOrchestrationTemplate, globalContext);
400 validateParameterDefaultTypeAlignWithType(fileName, heatOrchestrationTemplate, globalContext);
401 validateAllResourceReferencesExist(fileName, heatOrchestrationTemplate, globalContext);
402 validateResourceDependsOn(fileName, heatOrchestrationTemplate, globalContext);
403 validateGetParamPointToParameter(fileName, heatOrchestrationTemplate, globalContext);
404 validateGetAttr(fileName, heatOrchestrationTemplate, globalContext);
405 validateAllRequiredArtifactsExist(fileName, heatOrchestrationTemplate, artifacts,
408 if (envFileName != null) {
409 validateEnvFile(fileName, envFileName, heatOrchestrationTemplate, globalContext);
414 private void validateResourceDependsOn(String fileName,
415 HeatOrchestrationTemplate heatOrchestrationTemplate,
416 GlobalValidationContext globalContext) {
417 Map<String, Resource> resourcesMap = heatOrchestrationTemplate.getResources();
418 if(MapUtils.isEmpty(resourcesMap)){
422 Set<String> resourcesNames = resourcesMap.keySet();
424 resourcesMap.entrySet().stream()
425 .forEach(entry -> checkResourceDependsOn(fileName, entry.getValue(), resourcesNames, globalContext));
428 @SuppressWarnings("unchecked")
429 private static void checkResourceDependsOn(String fileName, Resource resource,
430 Set<String> resourcesNames,
431 GlobalValidationContext globalContext) {
434 mdcDataDebugMessage.debugEntryMessage("file", fileName);
436 Object dependencies = resource.getDepends_on();
437 if (dependencies instanceof Collection) {
438 ((Collection<String>) dependencies)
440 .filter(resource_id -> !resourcesNames.contains(resource_id))
441 .forEach(resource_id -> globalContext.addMessage(fileName, ErrorLevel.ERROR,
442 ErrorMessagesFormatBuilder
443 .getErrorWithParameters(Messages.MISSING_RESOURCE_IN_DEPENDS_ON.getErrorMessage(),
444 (String) resource_id), LoggerTragetServiceName.CHECK_RESOURCE_DEPENDS_ON,
445 LoggerErrorDescription.MISSING_RESOURCE_DEPENDS_ON));
446 } else if (dependencies instanceof String) {
447 if (!resourcesNames.contains(dependencies)) {
448 globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
449 .getErrorWithParameters(Messages.MISSING_RESOURCE_IN_DEPENDS_ON.getErrorMessage(),
450 (String) dependencies), LoggerTragetServiceName.CHECK_RESOURCE_DEPENDS_ON,
451 LoggerErrorDescription.MISSING_RESOURCE_DEPENDS_ON);
455 mdcDataDebugMessage.debugExitMessage("file", fileName);
459 private void validateHeatBaseStructure(String fileName,
460 HeatOrchestrationTemplate heatOrchestrationTemplate,
461 GlobalValidationContext globalContext) {
464 mdcDataDebugMessage.debugEntryMessage("file", fileName);
466 if (heatOrchestrationTemplate.getHeat_template_version() == null) {
467 globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
468 .getErrorWithParameters(Messages.INVALID_HEAT_FORMAT_REASON.getErrorMessage(),
469 "missing template version"), LoggerTragetServiceName.VALIDATE_HEAT_FORMAT,
470 LoggerErrorDescription.INVALID_HEAT_FORMAT);
472 if (heatOrchestrationTemplate.getResources() == null
473 || heatOrchestrationTemplate.getResources().size() == 0) {
474 globalContext.addMessage(fileName, ErrorLevel.WARNING, ErrorMessagesFormatBuilder
475 .getErrorWithParameters(Messages.INVALID_HEAT_FORMAT_REASON.getErrorMessage(),
476 "The heat file does not contain any resources"),
477 LoggerTragetServiceName.VALIDATE_HEAT_FORMAT, LoggerErrorDescription.INVALID_HEAT_FORMAT);
480 mdcDataDebugMessage.debugExitMessage("file", fileName);
483 private Set<String> checkForBaseFilePortsExistenceAndReturnSecurityGroupNamesFromOutputsIfNot(
484 String baseFileName, GlobalValidationContext globalContext) {
485 Set<String> securityGroupsNamesFromOutputsMap = new HashSet<>();
486 HeatOrchestrationTemplate heatOrchestrationTemplate =
487 ValidationUtil.checkHeatOrchestrationPreCondition(baseFileName, globalContext);
489 if (heatOrchestrationTemplate != null) {
490 Map<String, Resource> resourceMap = heatOrchestrationTemplate.getResources();
491 if (!isPortResourceExistInBaseFile(resourceMap)) {
492 getSecurityGroupsReferencedResourcesFromOutputs(securityGroupsNamesFromOutputsMap,
493 heatOrchestrationTemplate.getOutputs(), resourceMap);
496 return securityGroupsNamesFromOutputsMap;
500 @SuppressWarnings("unchecked")
501 private void getSecurityGroupsReferencedResourcesFromOutputs(
502 Set<String> securityGroupsNamesFromOutputsMap, Map<String, Output> outputMap,
503 Map<String, Resource> resourceMap) {
504 if (MapUtils.isNotEmpty(outputMap)) {
505 for (Map.Entry<String, Output> outputEntry : outputMap.entrySet()) {
506 Object outputValue = outputEntry.getValue().getValue();
507 if (Objects.nonNull(outputValue) && outputValue instanceof Map) {
508 String resourceName = (String) ((Map) outputValue)
509 .get(ResourceReferenceFunctions.GET_RESOURCE.getFunction());
510 if (Objects.nonNull(resourceName)) {
511 Resource resource = resourceMap.get(resourceName);
512 if (Objects.nonNull(resource) && resource.getType().equals(
513 HeatResourcesTypes.NEUTRON_SECURITY_GROUP_RESOURCE_TYPE.getHeatResource())) {
514 securityGroupsNamesFromOutputsMap.add(outputEntry.getKey());
523 private boolean isPortResourceExistInBaseFile(Map<String, Resource> resourceMap) {
524 for (Map.Entry<String, Resource> resourceEntry : resourceMap.entrySet()) {
525 if (resourceEntry.getValue().getType()
526 .equals(HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource())) {