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