Merge "Revert "Add validation for performance tuning""
[ta/cm-plugins.git] / validators / src / PerformanceProfilesValidation.py
1 #!/usr/bin/python
2 # Copyright 2019 Nokia
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 import json
17
18 from cmdatahandlers.api import validation
19 from cmframework.apis import cmvalidator
20
21
22 class PerformanceProfilesValidation(cmvalidator.CMValidator):
23     SUBSCRIPTION = r'^cloud\.performance_profiles$'
24
25     HUGEPAGESZ = 'hugepagesz'
26     DEFAULT_HUGEPAGESZ = 'default_hugepagesz'
27     HUGEPAGES = 'hugepages'
28     PLATFORM_CPUS = 'platform_cpus'
29     DPDK_CPUS = 'ovs_dpdk_cpus'
30     CAAS_CPU_POOLS = 'caas_cpu_pools'
31     CAAS_CPU_POOL_ATTRIBUTES = ['exclusive_pool_percentage', 'shared_pool_percentage']
32     CAAS_CPU_POOL_SHARE = 'caas_cpu_pool_share'
33
34     NUMA0 = 'numa0'
35     NUMA1 = 'numa1'
36     NUMA_VALUES = [NUMA0, NUMA1]
37
38     HUGEPAGESZ_VALUES = ['2M', '1G']
39
40     INFO_HUGEPAGESZ = 'Valid values: %s' % HUGEPAGESZ_VALUES
41     INFO_HUGEPAGES = 'Must be positive integer'
42     INFO_CPUS = 'Must be zero or positive integer'
43     INFO_PLATFORM_CPUS = 'Platform requires at least one core from NUMA0'
44
45     ERR_MISSING_DATA = 'Performance profiles validation input does not contain {} data'
46     ERR_INVALID_VALUE = 'Invalid %s value in performance profile {}: %s'
47
48     ERR_HUGEPAGESZ = ERR_INVALID_VALUE % (HUGEPAGESZ, INFO_HUGEPAGESZ)
49     ERR_DEFAULT_HUGEPAGESZ = ERR_INVALID_VALUE % (DEFAULT_HUGEPAGESZ, INFO_HUGEPAGESZ)
50     ERR_HUGEPAGES = ERR_INVALID_VALUE % (HUGEPAGES, INFO_HUGEPAGES)
51
52     ERR_NUMA = "Invalid NUMA value in performance profile {}"
53     ERR_CPUS = ERR_INVALID_VALUE % ("platform/ovs_dpdk cpu", INFO_CPUS)
54     ERR_PLATFORM_CPUS = ERR_INVALID_VALUE % ("platform_cpus", INFO_PLATFORM_CPUS)
55     ERR_CPU_POOL_RATIO = 'caas_cpu_pools total cpu percentage exceeded'
56     ERR_CAAS_CPU_POOL_TYPE = 'caas_cpu_pools percentage values should be integer'
57     ERR_CAAS_DEFAULT_POOL = 'caas_cpu_pool_share value should be integer between 0 and 100'
58
59     @staticmethod
60     def raise_error(context, err_type):
61         raise validation.ValidationError(err_type.format(context))
62
63     def get_subscription_info(self):
64         return self.SUBSCRIPTION
65
66     def validate_set(self, props):
67         conf = self.get_conf(props)
68         if isinstance(conf, dict):
69             self.validate(conf)
70
71     def get_conf(self, props):
72         domain = 'cloud.performance_profiles'
73         if not isinstance(props, dict) or domain not in props:
74             self.raise_error(domain, self.ERR_MISSING_DATA)
75         return json.loads(props[domain])
76
77     def validate(self, conf):
78         for profile, entries in conf.iteritems():
79             if isinstance(entries, dict):
80                 self.validate_profile(profile, entries)
81
82     def validate_profile(self, profile, entries):
83         for key, value in entries.iteritems():
84             self.validate_value(profile, key, value)
85
86     def validate_value(self, profile, key, value):
87         if key == self.HUGEPAGESZ:
88             self.validate_hugepagesz(profile, value)
89         elif key == self.DEFAULT_HUGEPAGESZ:
90             self.validate_default_hugepagesz(profile, value)
91         elif key == self.HUGEPAGES:
92             self.validate_hugepages(profile, value)
93         elif key == self.PLATFORM_CPUS:
94             self.validate_platform_cpus(profile, value)
95         elif key == self.DPDK_CPUS:
96             self.validate_ovs_dpdk_cpus(profile, value)
97         elif key == self.CAAS_CPU_POOLS:
98             self.validate_caas_cpu_pools(profile, value)
99         elif key == self.CAAS_CPU_POOL_SHARE:
100             self.validate_caas_cpu_pool_share(value)
101
102     def validate_hugepagesz(self, profile, value):
103         if value not in self.HUGEPAGESZ_VALUES:
104             self.raise_error(profile, self.ERR_HUGEPAGESZ)
105
106     def validate_default_hugepagesz(self, profile, value):
107         if value not in self.HUGEPAGESZ_VALUES:
108             self.raise_error(profile, self.ERR_DEFAULT_HUGEPAGESZ)
109
110     def validate_hugepages(self, profile, value):
111         if not (isinstance(value, (int, long)) and value > 0):
112             self.raise_error(profile, self.ERR_HUGEPAGES)
113
114     def validate_numa_names(self, profile, cpus):
115         if isinstance(cpus, dict):
116             for key in cpus.keys():
117                 if key not in self.NUMA_VALUES:
118                     self.raise_error(profile, self.ERR_NUMA)
119
120     def validate_cpu_values(self, profile, cpus):
121         if isinstance(cpus, dict):
122             for value in cpus.values():
123                 if not (isinstance(value, (int, long)) and value >= 0):
124                     self.raise_error(profile, self.ERR_CPUS)
125
126     def validate_platform_cpus(self, profile, cpus):
127         self.validate_numa_names(profile, cpus)
128         if cpus.get(self.NUMA1, None) is not None and cpus.get(self.NUMA0, None) is None:
129             self.raise_error(profile, self.ERR_PLATFORM_CPUS)
130         if cpus.get(self.NUMA1, None) is not None and cpus.get(self.NUMA0, None) == 0:
131             self.raise_error(profile, self.ERR_PLATFORM_CPUS)
132         self.validate_cpu_values(profile, cpus)
133
134     def validate_ovs_dpdk_cpus(self, profile, cpus):
135         self.validate_numa_names(profile, cpus)
136         self.validate_cpu_values(profile, cpus)
137
138     def validate_caas_cpu_pools(self, profile, pools):
139         sum_ratio = 0
140         self.allowed_attributes(profile, pools, self.CAAS_CPU_POOL_ATTRIBUTES)
141         self.is_attribute_present(profile, pools, self.CAAS_CPU_POOL_ATTRIBUTES)
142         for value in pools.values():
143             if not isinstance(value, int) or (value > 100) or (value < 0):
144                 self.raise_error(profile, self.ERR_CAAS_CPU_POOL_TYPE)
145             sum_ratio += value
146         if sum_ratio > 100:
147             self.raise_error(profile, self.ERR_CPU_POOL_RATIO)
148
149     def allowed_attributes(self, profile, entries, allowed_attributes):
150         for key in entries.keys():
151             if key not in allowed_attributes:
152                 self.raise_error(profile, 'Attribute %s is not allowed in profile %s, '
153                                  'allowed attributes: \"%s\"' %
154                                  (key, profile, str(",".join(allowed_attributes))))
155
156     def is_attribute_present(self, profile, entries, attributes):
157         is_present = False
158         for key in entries.keys():
159             if key in attributes:
160                 is_present = True
161         if not is_present:
162             self.raise_error(profile, 'Profile: %s should contain at least one of the following '
163                              'attributes: \"%s\"' % (profile, str(",".join(attributes))))
164
165     def validate_caas_cpu_pool_share(self, value):
166         if not isinstance(value, (int)) or (value > 100) or (value < 0):
167             self.raise_error(value, self.ERR_CAAS_DEFAULT_POOL)