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