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