de4dc79207c3398a67e3d03b396799ef0c4a59ab
[sdc.git] /
1 package org.openecomp.sdc.validation.impl.validators.namingconvention;
2
3 import org.openecomp.core.validation.ErrorMessageCode;
4 import org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder;
5 import org.openecomp.core.validation.types.GlobalValidationContext;
6 import org.openecomp.sdc.datatypes.error.ErrorLevel;
7 import org.openecomp.sdc.heat.datatypes.DefinedHeatParameterTypes;
8 import org.openecomp.sdc.heat.datatypes.model.Resource;
9 import org.openecomp.sdc.heat.services.HeatConstants;
10 import org.openecomp.sdc.heat.services.HeatStructureUtil;
11 import org.openecomp.sdc.validation.ResourceValidator;
12 import org.openecomp.sdc.validation.ValidationContext;
13 import org.openecomp.sdc.validation.type.NamingConventionValidationContext;
14
15 import java.util.Arrays;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Objects;
19 import java.util.Optional;
20 import java.util.Set;
21 import java.util.stream.Collectors;
22 import java.util.stream.Stream;
23
24 import static org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes.CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE;
25 import static org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes.NEUTRON_PORT_RESOURCE_TYPE;
26 import static org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes.NOVA_SERVER_RESOURCE_TYPE;
27
28 /**
29  * @author KATYR
30  * @since February 05, 2018
31  */
32
33 public class VirtualMachineInterfaceGuidelineValidator implements ResourceValidator {
34   private static final ErrorMessageCode ERROR_CODE_VLAN_GUIDELINE1 = new ErrorMessageCode
35       ("VlANG1");
36   private static final ErrorMessageCode ERROR_CODE_VLAN_GUIDELINE2 = new ErrorMessageCode
37       ("VlANG2");
38   private static final ErrorMessageCode ERROR_CODE_VLAN_GUIDELINE3 = new ErrorMessageCode
39       ("VlANG3");
40   private static final String UNDERSCORE = "_";
41   private static final String VMI = "vmi";
42
43
44   @Override
45   public void validate(String fileName, Map.Entry<String, Resource> resourceEntry,
46                        GlobalValidationContext globalContext, ValidationContext validationContext) {
47       NamingConventionValidationContext namingConventionValidationContext =
48           (NamingConventionValidationContext) validationContext;
49       Optional<Object> tagPropertyValue = getVlanTagPropertyValue(resourceEntry.getValue());
50
51       if (tagPropertyValue.isPresent()) {
52         validateModeledByResourceGroup(fileName, resourceEntry, globalContext,
53             namingConventionValidationContext);
54         validateSingleVirtualMachineInterfaceInFile(fileName, globalContext,
55             namingConventionValidationContext);
56         validateNamingConvention(fileName, resourceEntry, globalContext
57         );
58       }
59   }
60
61   private void validateModeledByResourceGroup(String fileName,
62                                               Map.Entry<String, Resource> resourceEntry,
63                                               GlobalValidationContext globalContext,
64                                               NamingConventionValidationContext namingConventionValidationContext) {
65
66     Object refsPropertyValue = resourceEntry.getValue().getProperties()
67         .get(HeatConstants.VMI_REFS_PROPERTY_NAME);
68     if (Objects.isNull(refsPropertyValue)) {
69       addViolationToContext(fileName, globalContext, ErrorLevel.WARNING, ERROR_CODE_VLAN_GUIDELINE1,
70           Messages.VLAN_GUIDELINE_VALIDATION_NOT_MODELED_THROUGH_RESOURCE_GROUP,
71           resourceEntry.getKey());
72       return;
73     }
74     final boolean modeledThroughResourceGroup =
75         isModeledThroughResourceGroup(fileName, globalContext,
76             namingConventionValidationContext,
77             refsPropertyValue);
78     if (!modeledThroughResourceGroup) {
79       addViolationToContext(fileName, globalContext, ErrorLevel.WARNING, ERROR_CODE_VLAN_GUIDELINE1,
80           Messages.VLAN_GUIDELINE_VALIDATION_NOT_MODELED_THROUGH_RESOURCE_GROUP,
81           resourceEntry.getKey());
82     }
83
84   }
85
86
87   private void validateNamingConvention(String fileName, Map.Entry<String, Resource>
88       resourceEntry, GlobalValidationContext globalContext) {
89     final String resourceId = resourceEntry.getKey();
90     final String networkRole = extractNetworkRoleFromResourceId(resourceId);
91     if (Objects.isNull(networkRole)) {
92       addViolationToContext(fileName, globalContext, ErrorLevel.WARNING, ERROR_CODE_VLAN_GUIDELINE3,
93           Messages.VLAN_GUIDELINE_VALIDATION_NAMING_CONVENTION, resourceId);
94     }
95   }
96
97   private void validateSingleVirtualMachineInterfaceInFile(String fileName,
98                                                            GlobalValidationContext globalContext,
99                                                            NamingConventionValidationContext
100                                                                namingConventionValidationContext) {
101     Set<String> forbiddenTypes = Stream.of(NOVA_SERVER_RESOURCE_TYPE.getHeatResource(),
102         NEUTRON_PORT_RESOURCE_TYPE.getHeatResource()).collect(Collectors.toSet());
103
104     final Map<String, Resource> resources =
105         namingConventionValidationContext.getHeatOrchestrationTemplate().getResources();
106
107     if ((countVlanResources(resources) > 1) || fileContainsNonVlanResources(resources,
108         forbiddenTypes)) {
109       addViolationToContext(fileName, globalContext, ErrorLevel.ERROR, ERROR_CODE_VLAN_GUIDELINE2,
110           Messages.VLAN_GUIDELINE_VALIDATION_SINGLE_VLAN, fileName);
111     }
112
113
114   }
115
116   private boolean fileContainsNonVlanResources(Map<String, Resource> resources,
117                                                Set<String> forbiddenTypes) {
118     for (String resourceName : resources.keySet()) {
119       if (forbiddenTypes.contains(resources.get(resourceName).getType())) {
120         return true;
121       }
122     }
123     return false;
124   }
125
126   private int countVlanResources(Map<String, Resource> resources) {
127     int numVlanResources = 0;
128     for (String resourceName : resources.keySet()) {
129       final String resourceType = resources.get(resourceName).getType();
130       if (resourceType.equals
131           (CONTRAIL_V2_VIRTUAL_MACHINE_INTERFACE_RESOURCE_TYPE.getHeatResource())) {
132         numVlanResources++;
133       }
134     }
135
136     return numVlanResources;
137   }
138
139
140   private void addViolationToContext(String fileName, GlobalValidationContext globalContext,
141                                      ErrorLevel error, ErrorMessageCode errorCodeVlanGuideline1,
142                                      Messages vlanGuidelineValidationNotModeledThroughResourceGroup,
143                                      String key) {
144     globalContext.addMessage(fileName, error, ErrorMessagesFormatBuilder
145         .getErrorWithParameters(errorCodeVlanGuideline1,
146             vlanGuidelineValidationNotModeledThroughResourceGroup.getErrorMessage(),
147             key));
148   }
149
150
151   private Optional<Object> getVlanTagPropertyValue(Resource resource) {
152     Object vmiProperties = resource.getProperties()
153         .get(HeatConstants.VMI_PROPERTIES_PROPERTY_NAME);
154     if (Objects.nonNull(vmiProperties) && vmiProperties instanceof Map) {
155       return Optional.ofNullable(((Map) vmiProperties)
156           .get(HeatConstants.VMI_SUB_INTERFACE_VLAN_TAG_PROPERTY_NAME));
157     }
158     return Optional.empty();
159   }
160
161
162   /**
163    * This method verifies whether the propertyValue is a list containing a single get_param
164    * whose value is string
165    *
166    * @param fileName                          on which the validation is currently run
167    * @param globalContext                     global validation context
168    * @param namingConventionValidationContext heat resource validation context
169    * @param propertyValue                     the value which is examined
170    * @return whether  the propertyValue is a list containing a single get_param
171    * whose value is string
172    */
173   private static boolean isModeledThroughResourceGroup(String fileName, GlobalValidationContext
174       globalContext, NamingConventionValidationContext namingConventionValidationContext,
175                                                        Object propertyValue) {
176     final boolean isList = propertyValue instanceof List;
177     if (!isList || ((List) propertyValue).size() != 1) {
178       return false;
179     }
180
181     final Object listValue = ((List) propertyValue).get(0);
182
183     final Set<String> getParamValues =
184         HeatStructureUtil.getReferencedValuesByFunctionName(fileName, "get_param",
185             listValue, globalContext);
186     if (getParamValues.isEmpty()) {
187       return false; //this is not a get_param
188     }
189
190     //validating get_param value
191     return (getParamValues.size() == 1) &&
192         validateGetParamValueOfType(getParamValues, namingConventionValidationContext,
193             DefinedHeatParameterTypes.STRING.getType());
194
195   }
196
197   private static boolean validateGetParamValueOfType(Set<String> values,
198                                                      NamingConventionValidationContext
199                                                          namingConventionValidationContext,
200                                                      String type) {
201
202     return values.stream().anyMatch(e -> Objects.equals(
203         namingConventionValidationContext.getHeatOrchestrationTemplate().getParameters().get(e)
204             .getType(), type));
205   }
206
207
208   private static String extractNetworkRoleFromResourceId(String resourceId) {
209
210     List<String> splitSubInterfaceResourceId =
211         Arrays.asList(resourceId.toLowerCase().split(UNDERSCORE));
212
213     int vmiIndex = splitSubInterfaceResourceId.indexOf(VMI);
214     if (vmiIndex > 0) {
215       return splitSubInterfaceResourceId.get(vmiIndex - 1);
216     }
217
218     return null;
219   }
220
221
222   private enum Messages {
223     VLAN_GUIDELINE_VALIDATION_NOT_MODELED_THROUGH_RESOURCE_GROUP("VLAN Resource will not be " +
224         "translated as the VLAN Sub-interface [%s] is not modeled as resource group"),
225     VLAN_GUIDELINE_VALIDATION_SINGLE_VLAN("There should not be any Compute Server Node, Port, " +
226         "Parent Port in nested file [%s]"),
227     VLAN_GUIDELINE_VALIDATION_NAMING_CONVENTION(
228         "Network role associated with VLAN Sub-interface " +
229             "id" +
230             "[%s] is not following the naming convention");
231
232     private final String errorMessage;
233
234     Messages(String errorMessage) {
235       this.errorMessage = errorMessage;
236     }
237
238     String getErrorMessage() {
239       return errorMessage;
240     }
241   }
242
243
244 }