push addional code
[sdc.git] / openecomp-be / lib / openecomp-sdc-validation-lib / openecomp-sdc-validation-impl / src / main / java / org / openecomp / sdc / validation / impl / validators / HeatValidator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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  */
20
21 package org.openecomp.sdc.validation.impl.validators;
22
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.apache.commons.collections4.MapUtils;
25 import org.openecomp.core.utilities.json.JsonUtil;
26 import org.openecomp.core.utilities.yaml.YamlUtil;
27 import org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder;
28 import org.openecomp.core.validation.errors.Messages;
29 import org.openecomp.core.validation.interfaces.Validator;
30 import org.openecomp.core.validation.types.GlobalValidationContext;
31 import org.openecomp.sdc.common.utils.AsdcCommon;
32 import org.openecomp.sdc.datatypes.error.ErrorLevel;
33 import org.openecomp.sdc.heat.datatypes.DefinedHeatParameterTypes;
34 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
35 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
36 import org.openecomp.sdc.heat.datatypes.model.Environment;
37 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
38 import org.openecomp.sdc.heat.datatypes.model.HeatPseudoParameters;
39 import org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes;
40 import org.openecomp.sdc.heat.datatypes.model.Output;
41 import org.openecomp.sdc.heat.datatypes.model.Parameter;
42 import org.openecomp.sdc.heat.datatypes.model.Resource;
43 import org.openecomp.sdc.heat.datatypes.model.ResourceReferenceFunctions;
44 import org.openecomp.sdc.heat.services.HeatStructureUtil;
45 import org.openecomp.sdc.heat.services.manifest.ManifestUtil;
46 import org.openecomp.sdc.validation.impl.util.HeatValidationService;
47 import org.openecomp.sdc.validation.impl.util.ResourceValidationHeatValidator;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 import java.io.InputStream;
52 import java.util.Collection;
53 import java.util.HashSet;
54 import java.util.Map;
55 import java.util.Objects;
56 import java.util.Set;
57
58 public class HeatValidator implements Validator {
59
60   protected static Logger logger = LoggerFactory.getLogger(HeatValidator.class);
61
62   /* validation 9*/
63   private static void validateAllRequiredArtifactsExist(String fileName,
64                                      HeatOrchestrationTemplate heatOrchestrationTemplate,
65                                      Set<String> artifacts,
66                                      GlobalValidationContext globalContext) {
67     Collection<Resource> resourcesValues = heatOrchestrationTemplate.getResources() == null ? null
68         : heatOrchestrationTemplate.getResources().values();
69
70     if (CollectionUtils.isNotEmpty(resourcesValues)) {
71       for (Resource resource : resourcesValues) {
72         Collection<Object> properties =
73             resource.getProperties() == null ? null : resource.getProperties().values();
74         if (CollectionUtils.isNotEmpty(properties)) {
75           for (Object property : properties) {
76             if (property instanceof Map) {
77               Set<String> artifactNames = HeatStructureUtil
78                   .getReferencedValuesByFunctionName(fileName,
79                       ResourceReferenceFunctions.GET_FILE.getFunction(), property, globalContext);
80               artifacts.addAll(artifactNames);
81               HeatValidationService.checkArtifactsExistence(fileName, artifactNames, globalContext);
82             }
83           }
84         }
85       }
86     }
87
88
89   }
90
91   /* validation 14 */
92   private static void validateAllResourceReferencesExist(String fileName,
93                                      HeatOrchestrationTemplate heatOrchestrationTemplate,
94                                      GlobalValidationContext globalContext) {
95
96     Set<String> resourcesNames = heatOrchestrationTemplate.getResources() == null ? null
97         : heatOrchestrationTemplate.getResources().keySet();
98     Collection<Resource> resourcesValues = heatOrchestrationTemplate.getResources() == null ? null
99         : heatOrchestrationTemplate.getResources().values();
100     Collection<Output> outputsValues = heatOrchestrationTemplate.getOutputs() == null ? null
101         : heatOrchestrationTemplate.getOutputs().values();
102
103     HeatValidationService
104         .checkResourceExistenceFromResourcesMap(fileName, resourcesNames, resourcesValues,
105             globalContext);
106     HeatValidationService
107         .checkResourceExistenceFromResourcesMap(fileName, resourcesNames, outputsValues,
108             globalContext);
109
110   }
111
112   /* validation 16 */
113   private static void validateGetParamPointToParameter(String fileName,
114                                     HeatOrchestrationTemplate heatOrchestrationTemplate,
115                                     GlobalValidationContext globalContext) {
116     Set<String> parametersNames = heatOrchestrationTemplate.getParameters() == null ? null
117         : heatOrchestrationTemplate.getParameters().keySet();
118     Map<String, Resource> resourcesMap = heatOrchestrationTemplate.getResources();
119
120     if (CollectionUtils.isNotEmpty(parametersNames) && MapUtils.isNotEmpty(resourcesMap)) {
121       for (Map.Entry<String, Resource> resourceEntry : resourcesMap.entrySet()) {
122         Resource resource = resourceEntry.getValue();
123         Map<String, Object> properties = resource.getProperties();
124         if (MapUtils.isNotEmpty(properties)) {
125           Collection<Object> propertiesValues = properties.values();
126           if (CollectionUtils.isNotEmpty(propertiesValues)) {
127             for (Object propertyObject : propertiesValues) {
128               //Set<String> referencedParameterNames = HeatValidationService
129               // .getParameterNameFromGetParamMap(propertyObject);
130               Set<String> referencedParameterNames = HeatStructureUtil
131                   .getReferencedValuesByFunctionName(fileName, "get_param", propertyObject,
132                       globalContext);
133
134               validateReferenceParams(fileName, resourceEntry.getKey(), parametersNames,
135                   referencedParameterNames, globalContext);
136             }
137           }
138         }
139       }
140     }
141   }
142
143   private static void validateReferenceParams(String fileName, String resourceName,
144                                               Set<String> parametersNamesFromFile,
145                                               Set<String> referencedParametersNames,
146                                               GlobalValidationContext globalContext) {
147
148     for (String parameterName : referencedParametersNames) {
149       if (!isHeatPseudoParameter(parameterName)
150           && !parametersNamesFromFile.contains(parameterName)) {
151         globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
152             .getErrorWithParameters(Messages.REFERENCED_PARAMETER_NOT_FOUND.getErrorMessage(),
153                 parameterName, resourceName));
154       }
155     }
156   }
157
158   private static boolean isHeatPseudoParameter(String parameterName) {
159     return HeatPseudoParameters.getPseudoParameterNames().contains(parameterName);
160   }
161
162   /* validation 18*/
163   private static void validateGetAttr(String fileName,
164                                       HeatOrchestrationTemplate heatOrchestrationTemplate,
165                                       GlobalValidationContext globalContext) {
166     Map<String, Output> outputMap;
167     outputMap = heatOrchestrationTemplate.getOutputs();
168
169     if (MapUtils.isNotEmpty(outputMap)) {
170       HeatValidationService.loopOverOutputMapAndValidateGetAttrFromNested(fileName, outputMap,
171           heatOrchestrationTemplate, globalContext);
172     }
173   }
174
175   /* validation 17 + */
176   private static void validateEnvFile(String fileName, String envFileName,
177                                       HeatOrchestrationTemplate heatOrchestrationTemplate,
178                                       GlobalValidationContext globalContext) {
179
180     Environment envContent;
181
182     if (!envFileName.contains(".env")) {
183       globalContext.addMessage(envFileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
184           .getErrorWithParameters(Messages.WRONG_ENV_FILE_EXTENSION.getErrorMessage(),
185               envFileName));
186     }
187
188     envContent = HeatValidationService.validateEnvContent(fileName, envFileName, globalContext);
189     if (envContent != null) {
190       validateEnvContentIsSubSetOfHeatParameters(envFileName, envContent, globalContext,
191           heatOrchestrationTemplate);
192       validateEnvParametersMatchDefinedHeatParameterTypes(envFileName, envContent, globalContext,
193           heatOrchestrationTemplate);
194     }
195
196   }
197
198   private static void validateEnvContentIsSubSetOfHeatParameters(String envFile,
199                                             Environment envContent,
200                                             GlobalValidationContext globalContext,
201                                             HeatOrchestrationTemplate heatOrchestrationTemplate) {
202     Set<String> parametersNames = heatOrchestrationTemplate.getParameters() == null ? null
203         : heatOrchestrationTemplate.getParameters().keySet();
204
205     if (MapUtils.isNotEmpty(envContent.getParameters())) {
206       if (CollectionUtils.isNotEmpty(parametersNames)) {
207         for (Map.Entry<String, Object> envEntry : envContent.getParameters().entrySet()) {
208           String envParameter = envEntry.getKey();
209           if (!parametersNames.contains(envParameter)) {
210             globalContext.addMessage(envFile, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
211                 .getErrorWithParameters(
212                     Messages.ENV_INCLUDES_PARAMETER_NOT_IN_HEAT.getErrorMessage(), envFile,
213                     envParameter));
214           }
215         }
216       } else {
217         for (Map.Entry<String, Object> envEntry : envContent.getParameters().entrySet()) {
218           globalContext.addMessage(envFile, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
219               .getErrorWithParameters(Messages.ENV_INCLUDES_PARAMETER_NOT_IN_HEAT.getErrorMessage(),
220                   envFile, envEntry.getKey()));
221         }
222       }
223     }
224   }
225
226   private static void validateParameterDefaultTypeAlignWithType(String fileName,
227                                        HeatOrchestrationTemplate heatOrchestrationTemplate,
228                                        GlobalValidationContext globalContext) {
229     Map<String, Parameter> parametersMap = heatOrchestrationTemplate.getParameters() == null ? null
230         : heatOrchestrationTemplate.getParameters();
231
232     if (MapUtils.isNotEmpty(parametersMap)) {
233       for (Map.Entry<String, Parameter> parameterEntry : parametersMap.entrySet()) {
234         Parameter parameter = parameterEntry.getValue();
235         String parameterType = parameter.getType();
236         Object parameterDefault = parameter.get_default();
237         if (parameterDefault != null && parameterType != null) {
238           boolean isValueMatchDefault =
239               DefinedHeatParameterTypes.isValueIsFromGivenType(parameterDefault, parameterType);
240           if (!isValueMatchDefault) {
241             globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
242                 .getErrorWithParameters(
243                     Messages.PARAMETER_DEFAULT_VALUE_NOT_ALIGN_WITH_TYPE.getErrorMessage(),
244                     parameterEntry.getKey(), parameterType));
245           }
246         }
247       }
248     }
249   }
250
251   private static void validateEnvParametersMatchDefinedHeatParameterTypes(String envFile,
252                                          Environment envContent,
253                                          GlobalValidationContext globalContext,
254                                          HeatOrchestrationTemplate heatOrchestrationTemplate) {
255     Map<String, Parameter> heatParameters = heatOrchestrationTemplate.getParameters();
256
257     if (MapUtils.isNotEmpty(heatParameters) && MapUtils.isNotEmpty(envContent.getParameters())) {
258       for (Map.Entry<String, Object> envEntry : envContent.getParameters().entrySet()) {
259         String parameterName = envEntry.getKey();
260         Object parameterEnvValue = envEntry.getValue();
261         Parameter parameterFromHeatFile = heatParameters.get(parameterName);
262         if (parameterFromHeatFile != null) {
263           String parameterType = parameterFromHeatFile.getType();
264           if (!DefinedHeatParameterTypes.isEmptyValueInEnv(parameterEnvValue)
265               && !DefinedHeatParameterTypes.isValueIsFromGivenType(parameterEnvValue,
266               parameterType)) {
267             globalContext.addMessage(envFile, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
268                 .getErrorWithParameters(
269                     Messages.PARAMETER_ENV_VALUE_NOT_ALIGN_WITH_TYPE.getErrorMessage(),
270                     parameterName));
271           }
272         }
273       }
274     }
275   }
276
277   @Override
278   public void validate(GlobalValidationContext globalContext) {
279
280     ManifestContent manifestContent;
281     try {
282       manifestContent = checkValidationPreCondition(globalContext);
283     } catch (Exception e0) {
284       return;
285     }
286     String baseFileName;
287     Map<String, FileData.Type> fileTypeMap = ManifestUtil.getFileTypeMap(manifestContent);
288     Map<String, FileData> fileEnvMap = ManifestUtil.getFileAndItsEnv(manifestContent);
289     Set<String> baseFiles = ManifestUtil.getBaseFiles(manifestContent);
290     Set<String> securityGroupsNamesFromBaseFileOutputs;
291     Set<String> artifacts = new HashSet<>();
292
293
294     baseFileName = CollectionUtils.isEmpty(baseFiles) ? null : baseFiles.iterator().next();
295     securityGroupsNamesFromBaseFileOutputs = baseFileName == null ? null
296         : checkForBaseFilePortsExistenceAndReturnSecurityGroupNamesFromOutputsIfNot(baseFileName,
297             globalContext);
298
299
300     globalContext.getFiles().stream()
301         .filter(fileName -> FileData.isHeatFile(fileTypeMap.get(fileName))).forEach(
302           fileName -> validate(fileName,
303             fileEnvMap.get(fileName) == null ? null : fileEnvMap.get(fileName).getFile(),
304             baseFileName == null ? null : baseFileName, artifacts,
305             securityGroupsNamesFromBaseFileOutputs, globalContext));
306
307
308     Set<String> manifestArtifacts = ManifestUtil.getArtifacts(manifestContent);
309
310     globalContext.getFiles().stream()
311         .filter(fileName -> manifestArtifacts.contains(fileName) && !artifacts.contains(fileName))
312         .forEach(fileName -> globalContext.addMessage(fileName, ErrorLevel.WARNING,
313             Messages.ARTIFACT_FILE_NOT_REFERENCED.getErrorMessage()));
314
315     ResourceValidationHeatValidator
316         .handleNotEmptyResourceNamesList(baseFileName, securityGroupsNamesFromBaseFileOutputs,
317             "SecurityGroup", globalContext);
318
319   }
320
321   private void validate(String fileName, String envFileName, String baseFileName,
322                         Set<String> artifacts, Set<String> securityGroupsNamesFromBaseFileOutputs,
323                         GlobalValidationContext globalContext) {
324     HeatOrchestrationTemplate heatOrchestrationTemplate =
325         checkHeatOrchestrationPreCondition(fileName, globalContext);
326
327
328     if (heatOrchestrationTemplate != null) {
329       if (!(fileName.contains(".yaml") || fileName.contains(".yml"))) {
330         globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
331             .getErrorWithParameters(Messages.WRONG_HEAT_FILE_EXTENSION.getErrorMessage(),
332                 fileName));
333       }
334
335       validateHeatBaseStructure(fileName, heatOrchestrationTemplate, globalContext);
336
337       ResourceValidationHeatValidator
338           .validateResourceType(fileName, baseFileName, securityGroupsNamesFromBaseFileOutputs,
339               heatOrchestrationTemplate, globalContext);
340       validateParameterDefaultTypeAlignWithType(fileName, heatOrchestrationTemplate, globalContext);
341       validateAllResourceReferencesExist(fileName, heatOrchestrationTemplate, globalContext);
342       validateGetParamPointToParameter(fileName, heatOrchestrationTemplate, globalContext);
343       validateGetAttr(fileName, heatOrchestrationTemplate, globalContext);
344       validateAllRequiredArtifactsExist(fileName, heatOrchestrationTemplate, artifacts,
345           globalContext);
346
347       if (envFileName != null) {
348         validateEnvFile(fileName, envFileName, heatOrchestrationTemplate, globalContext);
349       }
350     }
351   }
352
353   private void validateHeatBaseStructure(String fileName,
354                                          HeatOrchestrationTemplate heatOrchestrationTemplate,
355                                          GlobalValidationContext globalContext) {
356     if (heatOrchestrationTemplate.getHeat_template_version() == null) {
357       globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
358           .getErrorWithParameters(Messages.INVALID_HEAT_FORMAT_REASON.getErrorMessage(),
359               "missing template version"));
360     }
361     if (heatOrchestrationTemplate.getResources() == null
362         || heatOrchestrationTemplate.getResources().size() == 0) {
363       globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
364           .getErrorWithParameters(Messages.INVALID_HEAT_FORMAT_REASON.getErrorMessage(),
365               "heat file must have minimum one resource"));
366     }
367   }
368
369   protected ManifestContent checkValidationPreCondition(GlobalValidationContext globalContext) {
370     InputStream manifest = globalContext.getFileContent(AsdcCommon.MANIFEST_NAME);
371     if (manifest == null) {
372       throw new RuntimeException("Can't load manifest file for Heat Validator");
373     }
374     ManifestContent manifestContent;
375     try {
376       manifestContent = JsonUtil.json2Object(manifest, ManifestContent.class);
377     } catch (Exception e0) {
378       throw new RuntimeException("Can't load manifest file for Heat Validator");
379     }
380
381     return manifestContent;
382   }
383
384
385   private HeatOrchestrationTemplate checkHeatOrchestrationPreCondition(String fileName,
386                                             GlobalValidationContext globalContext) {
387     HeatOrchestrationTemplate heatOrchestrationTemplate;
388     try {
389       heatOrchestrationTemplate = new YamlUtil()
390           .yamlToObject(globalContext.getFileContent(fileName), HeatOrchestrationTemplate.class);
391     } catch (Exception e0) {
392       globalContext.addMessage(fileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
393           .getErrorWithParameters(Messages.INVALID_HEAT_FORMAT_REASON.getErrorMessage(),
394               getParserExceptionReason(e0)));
395       return null;
396     }
397
398     return heatOrchestrationTemplate;
399   }
400
401
402   private Set<String> checkForBaseFilePortsExistenceAndReturnSecurityGroupNamesFromOutputsIfNot(
403       String baseFileName, GlobalValidationContext globalContext) {
404     Set<String> securityGroupsNamesFromOutputsMap = new HashSet<>();
405     HeatOrchestrationTemplate heatOrchestrationTemplate =
406         checkHeatOrchestrationPreCondition(baseFileName, globalContext);
407
408     if (heatOrchestrationTemplate != null) {
409       Map<String, Resource> resourceMap = heatOrchestrationTemplate.getResources();
410       if (!isPortResourceExistInBaseFile(resourceMap)) {
411         getSecurityGroupsReferencedResourcesFromOutputs(securityGroupsNamesFromOutputsMap,
412             heatOrchestrationTemplate.getOutputs(), resourceMap);
413       }
414     }
415
416     return securityGroupsNamesFromOutputsMap;
417   }
418
419
420   @SuppressWarnings("unchecked")
421   private void getSecurityGroupsReferencedResourcesFromOutputs(
422       Set<String> securityGroupsNamesFromOutputsMap, Map<String, Output> outputMap,
423       Map<String, Resource> resourceMap) {
424     if (MapUtils.isNotEmpty(outputMap)) {
425       for (Map.Entry<String, Output> outputEntry : outputMap.entrySet()) {
426         Object outputValue = outputEntry.getValue().getValue();
427         if (Objects.nonNull(outputValue) && outputValue instanceof Map) {
428           String resourceName = (String) ((Map) outputValue)
429               .get(ResourceReferenceFunctions.GET_RESOURCE.getFunction());
430           if (Objects.nonNull(resourceName)) {
431             Resource resource = resourceMap.get(resourceName);
432             if (Objects.nonNull(resource) && resource.getType().equals(
433                 HeatResourcesTypes.NEUTRON_SECURITY_GROUP_RESOURCE_TYPE.getHeatResource())) {
434               securityGroupsNamesFromOutputsMap.add(outputEntry.getKey());
435             }
436           }
437         }
438       }
439     }
440   }
441
442
443   private boolean isPortResourceExistInBaseFile(Map<String, Resource> resourceMap) {
444     for (Map.Entry<String, Resource> resourceEntry : resourceMap.entrySet()) {
445       if (resourceEntry.getValue().getType()
446           .equals(HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE.getHeatResource())) {
447         return true;
448       }
449     }
450
451     return false;
452   }
453
454
455   private String getParserExceptionReason(Exception e0) {
456     String reason;
457
458     if (e0.getCause() != null && e0.getCause().getCause() != null) {
459       reason = e0.getCause().getCause().getMessage();
460     } else if (e0.getCause() != null) {
461       reason = e0.getCause().getMessage();
462     } else {
463       reason = Messages.GENERAL_HEAT_PARSER_ERROR.getErrorMessage();
464     }
465     return reason;
466   }
467
468
469 }