d59d0a8def2ddc596bfbf3a17d5e3de637b30887
[sdc.git] /
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.util;
22
23 import org.apache.commons.collections4.CollectionUtils;
24 import org.openecomp.sdc.tosca.services.YamlUtil;
25 import org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder;
26 import org.openecomp.core.validation.types.GlobalValidationContext;
27 import org.openecomp.sdc.common.errors.Messages;
28 import org.openecomp.sdc.datatypes.error.ErrorLevel;
29 import org.openecomp.sdc.heat.datatypes.DefinedHeatParameterTypes;
30 import org.openecomp.sdc.heat.datatypes.model.Environment;
31 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
32 import org.openecomp.sdc.heat.datatypes.model.Parameter;
33 import org.openecomp.sdc.heat.datatypes.model.Resource;
34 import org.openecomp.sdc.logging.api.Logger;
35 import org.openecomp.sdc.logging.api.LoggerFactory;
36 import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage;
37 import org.openecomp.sdc.logging.context.impl.MdcDataErrorMessage;
38 import org.openecomp.sdc.logging.types.LoggerConstants;
39 import org.openecomp.sdc.logging.types.LoggerErrorCode;
40 import org.openecomp.sdc.logging.types.LoggerErrorDescription;
41 import org.openecomp.sdc.logging.types.LoggerTragetServiceName;
42 import org.openecomp.sdc.validation.impl.validators.HeatValidator;
43
44 import java.io.InputStream;
45 import java.util.Collection;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Objects;
49 import java.util.Optional;
50 import java.util.Set;
51
52
53 public class HeatValidationService {
54
55   private static final Logger logger = (Logger) LoggerFactory.getLogger(HeatValidator.class);
56   private static final String NESTED_FILE = "nested file";
57   private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage();
58
59   /**
60    * Check artifacts existence.
61    *
62    * @param fileName       the file name
63    * @param artifactsNames the artifacts names
64    * @param globalContext  the global context
65    */
66   public static void checkArtifactsExistence(String fileName, Set<String> artifactsNames,
67                                              GlobalValidationContext globalContext) {
68
69
70     mdcDataDebugMessage.debugEntryMessage("file", fileName);
71     artifactsNames
72         .stream()
73         .filter(artifactName -> !globalContext.getFileContextMap().containsKey(artifactName))
74         .forEach(artifactName -> {
75           globalContext.addMessage(fileName,
76               ErrorLevel.ERROR, ErrorMessagesFormatBuilder
77                   .getErrorWithParameters(globalContext.getMessageCode(),Messages.MISSING_ARTIFACT.getErrorMessage()
78                       ,artifactName),
79                   LoggerTragetServiceName.VALIDATE_ARTIFACTS_EXISTENCE,
80               LoggerErrorDescription.MISSING_FILE);
81         });
82
83     mdcDataDebugMessage.debugExitMessage("file", fileName);
84   }
85
86   /**
87    * Draw files loop string.
88    *
89    * @param filesInPath the files in path
90    * @return the string
91    */
92   public static String drawFilesLoop(List<String> filesInPath) {
93     StringBuilder stringBuilder = new StringBuilder();
94     stringBuilder.append("[");
95     int pathSize = filesInPath.size();
96
97     for (int i = 0; i < pathSize; i++) {
98       stringBuilder.append(filesInPath.get(i));
99       if (i != pathSize - 1) {
100         stringBuilder.append(" -- ");
101       }
102     }
103     if (!filesInPath.get(0).equals(filesInPath.get(pathSize - 1))) {
104       stringBuilder.append(" -- ");
105       stringBuilder.append(filesInPath.get(0));
106     }
107     stringBuilder.append("]");
108
109     return stringBuilder.toString();
110   }
111
112
113   /**
114    * Check nested parameters.
115    *
116    * @param parentFileName         the calling nested file name
117    * @param nestedFileName         the nested file name
118    * @param resourceName           the resource name
119    * @param globalContext          the global context
120    * @param resourceFileProperties the resource file properties
121    */
122   public static void checkNestedParameters(String parentFileName, String nestedFileName,
123                                            String resourceName, Resource resource,
124                                            Set<String> resourceFileProperties,
125                                            Optional<String> indexVarValue,
126                                            GlobalValidationContext globalContext) {
127
128
129     mdcDataDebugMessage.debugEntryMessage("file", parentFileName);
130
131     HeatOrchestrationTemplate parentHeatOrchestrationTemplate;
132     HeatOrchestrationTemplate nestedHeatOrchestrationTemplate;
133     try {
134       Optional<InputStream> fileContent = globalContext.getFileContent(nestedFileName);
135       if (fileContent.isPresent()) {
136         nestedHeatOrchestrationTemplate =
137             new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
138       } else {
139         MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
140             LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
141             ErrorLevel.ERROR.name(), LoggerErrorCode.DATA_ERROR.getErrorCode(),
142             LoggerErrorDescription.EMPTY_FILE);
143         throw new Exception("The file '" + nestedFileName + "' has no content");
144       }
145     } catch (Exception exception) {
146       logger.debug("",exception);
147       mdcDataDebugMessage.debugExitMessage("file", parentFileName);
148       return;
149     }
150
151     try {
152       Optional<InputStream> fileContent = globalContext.getFileContent(parentFileName);
153       if (fileContent.isPresent()) {
154         parentHeatOrchestrationTemplate =
155             new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
156       } else {
157         MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
158             LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
159             ErrorLevel.ERROR.name(), LoggerErrorCode.DATA_ERROR.getErrorCode(),
160             LoggerErrorDescription.EMPTY_FILE);
161         throw new Exception("The file '" + parentFileName + "' has no content");
162       }
163     } catch (Exception exception) {
164       logger.debug("",exception);
165       mdcDataDebugMessage.debugExitMessage("file", parentFileName);
166       return;
167     }
168     Map<String, Parameter> parentParameters = parentHeatOrchestrationTemplate.getParameters();
169     Map<String, Parameter> nestedParameters = nestedHeatOrchestrationTemplate.getParameters();
170     Set<String> nestedParametersNames =
171         nestedParameters == null ? null : nestedHeatOrchestrationTemplate.getParameters().keySet();
172
173     checkNoMissingParameterInNested(parentFileName, nestedFileName, resourceName,
174         resourceFileProperties, nestedParametersNames, globalContext);
175     checkNestedInputValuesAlignWithType(parentFileName, nestedFileName, parentParameters,
176         nestedParameters, resourceName, resource, indexVarValue, globalContext);
177
178     mdcDataDebugMessage.debugExitMessage("file", parentFileName);
179
180   }
181
182   private static void checkNoMissingParameterInNested(String parentFileName, String nestedFileName,
183                                                       String resourceName,
184                                                       Set<String> resourceFileProperties,
185                                                       Set<String> nestedParametersNames,
186                                                       GlobalValidationContext globalContext) {
187
188     mdcDataDebugMessage.debugEntryMessage(NESTED_FILE, nestedFileName);
189
190     if (CollectionUtils.isNotEmpty(nestedParametersNames)) {
191       resourceFileProperties
192           .stream()
193           .filter(propertyName -> !nestedParametersNames.contains(propertyName))
194           .forEach(propertyName -> globalContext
195               .addMessage(parentFileName, ErrorLevel.ERROR, ErrorMessagesFormatBuilder
196                       .getErrorWithParameters(Messages
197                               .MISSING_PARAMETER_IN_NESTED.getErrorMessage(),
198                           nestedFileName, resourceName, propertyName),
199                   LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
200                   LoggerErrorDescription.MISSING_PARAMETER_IN_NESTED));
201     }
202
203     mdcDataDebugMessage.debugExitMessage(NESTED_FILE, nestedFileName);
204   }
205
206
207   private static void checkNestedInputValuesAlignWithType(String parentFileName,
208                                                           String nestedFileName,
209                                                           Map<String, Parameter> parentParameters,
210                                                           Map<String, Parameter> nestedParameters,
211                                                           String resourceName, Resource resource,
212                                                           Optional<String> indexVarValue,
213                                                           GlobalValidationContext globalContext) {
214
215
216     mdcDataDebugMessage.debugEntryMessage(NESTED_FILE, nestedFileName);
217
218     Map<String, Object> properties = resource.getProperties();
219     for (Map.Entry<String, Object> propertyEntry : properties.entrySet()) {
220       String parameterName = propertyEntry.getKey();
221       Object parameterInputValue = propertyEntry.getValue();
222
223       if (Objects.nonNull(parameterInputValue)) {
224         if (parameterInputValue instanceof String) {
225           if (indexVarValue.isPresent() && indexVarValue.get().equals(parameterInputValue)) {
226             parameterInputValue = 3; //indexVarValue is actually number value in runtime
227           }
228           validateStaticValueForNestedInputParameter(parentFileName, nestedFileName, resourceName,
229               parameterName, parameterInputValue, nestedParameters.get(parameterName),
230               globalContext);
231         }
232       }
233     }
234
235     mdcDataDebugMessage.debugExitMessage(NESTED_FILE, nestedFileName);
236   }
237
238   private static void validateStaticValueForNestedInputParameter(String parentFileName,
239                                                                  String nestedFileName,
240                                                                  String resourceName,
241                                                                  String parameterName,
242                                                                  Object staticValue,
243                                                                  Parameter parameterInNested,
244                                                                  GlobalValidationContext
245                                                                      globalContext) {
246
247
248     mdcDataDebugMessage.debugEntryMessage(NESTED_FILE, nestedFileName);
249
250     if (parameterInNested == null) {
251       return;
252     }
253     if (!DefinedHeatParameterTypes
254         .isValueIsFromGivenType(staticValue, parameterInNested.getType())) {
255       globalContext.addMessage(parentFileName, ErrorLevel.WARNING, ErrorMessagesFormatBuilder
256               .getErrorWithParameters(Messages
257                       .WRONG_VALUE_TYPE_ASSIGNED_NESTED_INPUT.getErrorMessage(),
258                   resourceName, parameterName, nestedFileName),
259           LoggerTragetServiceName.VALIDATE_PROPERTIES_MATCH_NESTED_PARAMETERS,
260           LoggerErrorDescription.WRONG_VALUE_ASSIGNED_NESTED_PARAMETER);
261     }
262
263     mdcDataDebugMessage.debugExitMessage(NESTED_FILE, nestedFileName);
264   }
265
266
267   /**
268    * Is nested loop exist in file boolean.
269    *
270    * @param callingFileName the calling file name
271    * @param nestedFileName  the nested file name
272    * @param filesInLoop     the files in loop
273    * @param globalContext   the global context
274    * @return the boolean
275    */
276   public static boolean isNestedLoopExistInFile(String callingFileName, String nestedFileName,
277                                                 List<String> filesInLoop,
278                                                 GlobalValidationContext globalContext) {
279
280
281     mdcDataDebugMessage.debugEntryMessage("file", callingFileName);
282
283     HeatOrchestrationTemplate nestedHeatOrchestrationTemplate;
284     try {
285       Optional<InputStream> fileContent = globalContext.getFileContent(nestedFileName);
286       if (fileContent.isPresent()) {
287         nestedHeatOrchestrationTemplate =
288             new YamlUtil().yamlToObject(fileContent.get(), HeatOrchestrationTemplate.class);
289       } else {
290         MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
291             LoggerTragetServiceName.VALIDATE_NESTING_LOOPS, ErrorLevel.ERROR.name(),
292             LoggerErrorCode.DATA_ERROR.getErrorCode(), LoggerErrorDescription.EMPTY_FILE);
293         throw new Exception("The file '" + nestedFileName + "' has no content");
294       }
295
296     } catch (Exception exception) {
297       logger.debug("",exception);
298       logger.warn("HEAT Validator will not be executed on file " + nestedFileName
299           + " due to illegal HEAT format");
300
301       mdcDataDebugMessage.debugExitMessage("file", callingFileName);
302       return false;
303     }
304     filesInLoop.add(nestedFileName);
305     Collection<Resource> nestedResources =
306         nestedHeatOrchestrationTemplate.getResources() == null ? null
307             : nestedHeatOrchestrationTemplate.getResources().values();
308     if (CollectionUtils.isNotEmpty(nestedResources)) {
309       for (Resource resource : nestedResources) {
310         String resourceType = resource.getType();
311
312         if (Objects.nonNull(resourceType) && isNestedResource(resourceType)) {
313           mdcDataDebugMessage.debugExitMessage("file", callingFileName);
314           return resourceType.equals(callingFileName) || !filesInLoop.contains(resourceType)
315               && isNestedLoopExistInFile(callingFileName, resourceType, filesInLoop, globalContext);
316         }
317       }
318     }
319
320     mdcDataDebugMessage.debugExitMessage("file", callingFileName);
321     return false;
322   }
323
324   public static boolean isNestedResource(String resourceType) {
325     return resourceType.contains(".yaml") || resourceType.contains(".yml");
326   }
327
328   /**
329    * Validate env content environment.
330    *
331    * @param fileName      the file name
332    * @param envFileName   the env file name
333    * @param globalContext the global context
334    * @return the environment
335    */
336   public static Environment validateEnvContent(String fileName, String envFileName,
337                                                GlobalValidationContext globalContext) {
338
339
340     mdcDataDebugMessage.debugEntryMessage("env file", envFileName);
341
342     Environment envContent = null;
343     try {
344       Optional<InputStream> fileContent = globalContext.getFileContent(envFileName);
345       if (fileContent.isPresent()) {
346         envContent = new YamlUtil().yamlToObject(fileContent.get(), Environment.class);
347       } else {
348         MdcDataErrorMessage.createErrorMessageAndUpdateMdc(LoggerConstants.TARGET_ENTITY_API,
349             LoggerTragetServiceName.VALIDATE_ENV_FILE, ErrorLevel.ERROR.name(),
350             LoggerErrorCode.DATA_ERROR.getErrorCode(), LoggerErrorDescription.EMPTY_FILE);
351         throw new Exception("The file '" + envFileName + "' has no content");
352       }
353     } catch (Exception exception) {
354       logger.debug("",exception);
355       mdcDataDebugMessage.debugExitMessage("env file", envFileName);
356       return null;
357     }
358     return envContent;
359   }
360
361
362   public static String getResourceGroupResourceName(String resourceCallingToResourceGroup) {
363     return "OS::Heat::ResourceGroup in " + resourceCallingToResourceGroup;
364   }
365
366 }