--- /dev/null
+#!/usr/bin/python
+# Copyright 2019 Nokia
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+
+from cmdatahandlers.api import validation
+from cmframework.apis import cmvalidator
+
+
+class PerformanceProfilesValidation(cmvalidator.CMValidator):
+ SUBSCRIPTION = r'^cloud\.performance_profiles$'
+
+ HUGEPAGESZ = 'hugepagesz'
+ DEFAULT_HUGEPAGESZ = 'default_hugepagesz'
+ HUGEPAGES = 'hugepages'
+ PLATFORM_CPUS = 'platform_cpus'
+ DPDK_CPUS = 'ovs_dpdk_cpus'
+ CAAS_CPU_POOLS = 'caas_cpu_pools'
+ CAAS_CPU_POOL_ATTRIBUTES = ['exclusive_pool_percentage', 'shared_pool_percentage']
+ CAAS_CPU_POOL_SHARE = 'caas_cpu_pool_share'
+
+ NUMA0 = 'numa0'
+ NUMA1 = 'numa1'
+ NUMA_VALUES = [NUMA0, NUMA1]
+
+ HUGEPAGESZ_VALUES = ['2M', '1G']
+
+ INFO_HUGEPAGESZ = 'Valid values: %s' % HUGEPAGESZ_VALUES
+ INFO_HUGEPAGES = 'Must be positive integer'
+ INFO_CPUS = 'Must be zero or positive integer'
+ INFO_PLATFORM_CPUS = 'Platform requires at least one core from NUMA0'
+
+ ERR_MISSING_DATA = 'Performance profiles validation input does not contain {} data'
+ ERR_INVALID_VALUE = 'Invalid %s value in performance profile {}: %s'
+
+ ERR_HUGEPAGESZ = ERR_INVALID_VALUE % (HUGEPAGESZ, INFO_HUGEPAGESZ)
+ ERR_DEFAULT_HUGEPAGESZ = ERR_INVALID_VALUE % (DEFAULT_HUGEPAGESZ, INFO_HUGEPAGESZ)
+ ERR_HUGEPAGES = ERR_INVALID_VALUE % (HUGEPAGES, INFO_HUGEPAGES)
+
+ ERR_NUMA = "Invalid NUMA value in performance profile {}"
+ ERR_CPUS = ERR_INVALID_VALUE % ("platform/ovs_dpdk cpu", INFO_CPUS)
+ ERR_PLATFORM_CPUS = ERR_INVALID_VALUE % ("platform_cpus", INFO_PLATFORM_CPUS)
+ ERR_CPU_POOL_RATIO = 'caas_cpu_pools total cpu percentage exceeded'
+ ERR_CAAS_CPU_POOL_TYPE = 'caas_cpu_pools percentage values should be integer'
+ ERR_CAAS_DEFAULT_POOL = 'caas_cpu_pool_share value should be integer between 0 and 100'
+
+ @staticmethod
+ def raise_error(context, err_type):
+ raise validation.ValidationError(err_type.format(context))
+
+ def get_subscription_info(self):
+ return self.SUBSCRIPTION
+
+ def validate_set(self, props):
+ conf = self.get_conf(props)
+ if isinstance(conf, dict):
+ self.validate(conf)
+
+ def get_conf(self, props):
+ domain = 'cloud.performance_profiles'
+ if not isinstance(props, dict) or domain not in props:
+ self.raise_error(domain, self.ERR_MISSING_DATA)
+ return json.loads(props[domain])
+
+ def validate(self, conf):
+ for profile, entries in conf.iteritems():
+ if isinstance(entries, dict):
+ self.validate_profile(profile, entries)
+
+ def validate_profile(self, profile, entries):
+ for key, value in entries.iteritems():
+ self.validate_value(profile, key, value)
+
+ def validate_value(self, profile, key, value):
+ if key == self.HUGEPAGESZ:
+ self.validate_hugepagesz(profile, value)
+ elif key == self.DEFAULT_HUGEPAGESZ:
+ self.validate_default_hugepagesz(profile, value)
+ elif key == self.HUGEPAGES:
+ self.validate_hugepages(profile, value)
+ elif key == self.PLATFORM_CPUS:
+ self.validate_platform_cpus(profile, value)
+ elif key == self.DPDK_CPUS:
+ self.validate_ovs_dpdk_cpus(profile, value)
+ elif key == self.CAAS_CPU_POOLS:
+ self.validate_caas_cpu_pools(profile, value)
+ elif key == self.CAAS_CPU_POOL_SHARE:
+ self.validate_caas_cpu_pool_share(value)
+
+ def validate_hugepagesz(self, profile, value):
+ if value not in self.HUGEPAGESZ_VALUES:
+ self.raise_error(profile, self.ERR_HUGEPAGESZ)
+
+ def validate_default_hugepagesz(self, profile, value):
+ if value not in self.HUGEPAGESZ_VALUES:
+ self.raise_error(profile, self.ERR_DEFAULT_HUGEPAGESZ)
+
+ def validate_hugepages(self, profile, value):
+ if not (isinstance(value, (int, long)) and value > 0):
+ self.raise_error(profile, self.ERR_HUGEPAGES)
+
+ def validate_numa_names(self, profile, cpus):
+ if isinstance(cpus, dict):
+ for key in cpus.keys():
+ if key not in self.NUMA_VALUES:
+ self.raise_error(profile, self.ERR_NUMA)
+
+ def validate_cpu_values(self, profile, cpus):
+ if isinstance(cpus, dict):
+ for value in cpus.values():
+ if not (isinstance(value, (int, long)) and value >= 0):
+ self.raise_error(profile, self.ERR_CPUS)
+
+ def validate_platform_cpus(self, profile, cpus):
+ self.validate_numa_names(profile, cpus)
+ if cpus.get(self.NUMA1, None) is not None and cpus.get(self.NUMA0, None) is None:
+ self.raise_error(profile, self.ERR_PLATFORM_CPUS)
+ if cpus.get(self.NUMA1, None) is not None and cpus.get(self.NUMA0, None) == 0:
+ self.raise_error(profile, self.ERR_PLATFORM_CPUS)
+ self.validate_cpu_values(profile, cpus)
+
+ def validate_ovs_dpdk_cpus(self, profile, cpus):
+ self.validate_numa_names(profile, cpus)
+ self.validate_cpu_values(profile, cpus)
+
+ def validate_caas_cpu_pools(self, profile, pools):
+ sum_ratio = 0
+ self.allowed_attributes(profile, pools, self.CAAS_CPU_POOL_ATTRIBUTES)
+ self.is_attribute_present(profile, pools, self.CAAS_CPU_POOL_ATTRIBUTES)
+ for value in pools.values():
+ if not isinstance(value, int) or (value > 100) or (value < 0):
+ self.raise_error(profile, self.ERR_CAAS_CPU_POOL_TYPE)
+ sum_ratio += value
+ if sum_ratio > 100:
+ self.raise_error(profile, self.ERR_CPU_POOL_RATIO)
+
+ def allowed_attributes(self, profile, entries, allowed_attributes):
+ for key in entries.keys():
+ if key not in allowed_attributes:
+ self.raise_error(profile, 'Attribute %s is not allowed in profile %s, '
+ 'allowed attributes: \"%s\"' %
+ (key, profile, str(",".join(allowed_attributes))))
+
+ def is_attribute_present(self, profile, entries, attributes):
+ is_present = False
+ for key in entries.keys():
+ if key in attributes:
+ is_present = True
+ if not is_present:
+ self.raise_error(profile, 'Profile: %s should contain at least one of the following '
+ 'attributes: \"%s\"' % (profile, str(",".join(attributes))))
+
+ def validate_caas_cpu_pool_share(self, value):
+ if not isinstance(value, (int)) or (value > 100) or (value < 0):
+ self.raise_error(value, self.ERR_CAAS_DEFAULT_POOL)