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