--- /dev/null
+#!/usr/bin/python
+
+#
+# Copyright 2017 RIFT.IO Inc
+#
+# 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 re
+import gi
+
+gi.require_version('RwcalYang', '1.0')
+from gi.repository import RwcalYang
+
+
+class GuestEPAUtils(object):
+ """
+ Utility class for Host EPA to Openstack flavor extra_specs conversion routines
+ """
+ def __init__(self):
+ self._mano_to_espec_cpu_pinning_policy = {
+ 'DEDICATED' : 'dedicated',
+ 'SHARED' : 'shared',
+ 'ANY' : 'any',
+ }
+
+ self._espec_to_mano_cpu_pinning_policy = {
+ 'dedicated' : 'DEDICATED',
+ 'shared' : 'SHARED',
+ 'any' : 'ANY',
+ }
+
+ self._mano_to_espec_mempage_size = {
+ 'LARGE' : 'large',
+ 'SMALL' : 'small',
+ 'SIZE_2MB' : 2048,
+ 'SIZE_1GB' : 1048576,
+ 'PREFER_LARGE' : 'large',
+ }
+
+ self._espec_to_mano_mempage_size = {
+ 'large' : 'LARGE',
+ 'small' : 'SMALL',
+ 2048 : 'SIZE_2MB',
+ 1048576 : 'SIZE_1GB',
+ 'large' : 'PREFER_LARGE',
+ }
+
+ self._mano_to_espec_cpu_thread_pinning_policy = {
+ 'AVOID' : 'avoid',
+ 'SEPARATE' : 'separate',
+ 'ISOLATE' : 'isolate',
+ 'PREFER' : 'prefer',
+ }
+
+ self._espec_to_mano_cpu_thread_pinning_policy = {
+ 'avoid' : 'AVOID',
+ 'separate' : 'SEPARATE',
+ 'isolate' : 'ISOLATE',
+ 'prefer' : 'PREFER',
+ }
+
+ self._espec_to_mano_numa_memory_policy = {
+ 'strict' : 'STRICT',
+ 'preferred': 'PREFERRED'
+ }
+
+ self._mano_to_espec_numa_memory_policy = {
+ 'STRICT' : 'strict',
+ 'PREFERRED': 'preferred'
+ }
+
+ def mano_to_extra_spec_cpu_pinning_policy(self, cpu_pinning_policy):
+ if cpu_pinning_policy in self._mano_to_espec_cpu_pinning_policy:
+ return self._mano_to_espec_cpu_pinning_policy[cpu_pinning_policy]
+ else:
+ return None
+
+ def extra_spec_to_mano_cpu_pinning_policy(self, cpu_pinning_policy):
+ if cpu_pinning_policy in self._espec_to_mano_cpu_pinning_policy:
+ return self._espec_to_mano_cpu_pinning_policy[cpu_pinning_policy]
+ else:
+ return None
+
+ def mano_to_extra_spec_mempage_size(self, mempage_size):
+ if mempage_size in self._mano_to_espec_mempage_size:
+ return self._mano_to_espec_mempage_size[mempage_size]
+ else:
+ return None
+
+ def extra_spec_to_mano_mempage_size(self, mempage_size):
+ if mempage_size in self._espec_to_mano_mempage_size:
+ return self._espec_to_mano_mempage_size[mempage_size]
+ else:
+ return None
+
+ def mano_to_extra_spec_cpu_thread_pinning_policy(self, cpu_thread_pinning_policy):
+ if cpu_thread_pinning_policy in self._mano_to_espec_cpu_thread_pinning_policy:
+ return self._mano_to_espec_cpu_thread_pinning_policy[cpu_thread_pinning_policy]
+ else:
+ return None
+
+ def extra_spec_to_mano_cpu_thread_pinning_policy(self, cpu_thread_pinning_policy):
+ if cpu_thread_pinning_policy in self._espec_to_mano_cpu_thread_pinning_policy:
+ return self._espec_to_mano_cpu_thread_pinning_policy[cpu_thread_pinning_policy]
+ else:
+ return None
+
+ def mano_to_extra_spec_trusted_execution(self, trusted_execution):
+ if trusted_execution:
+ return 'trusted'
+ else:
+ return 'untrusted'
+
+ def extra_spec_to_mano_trusted_execution(self, trusted_execution):
+ if trusted_execution == 'trusted':
+ return True
+ elif trusted_execution == 'untrusted':
+ return False
+ else:
+ return None
+
+ def mano_to_extra_spec_numa_node_count(self, numa_node_count):
+ return numa_node_count
+
+ def extra_specs_to_mano_numa_node_count(self, numa_node_count):
+ return int(numa_node_count)
+
+ def mano_to_extra_spec_numa_memory_policy(self, numa_memory_policy):
+ if numa_memory_policy in self._mano_to_espec_numa_memory_policy:
+ return self._mano_to_espec_numa_memory_policy[numa_memory_policy]
+ else:
+ return None
+
+ def extra_to_mano_spec_numa_memory_policy(self, numa_memory_policy):
+ if numa_memory_policy in self._espec_to_mano_numa_memory_policy:
+ return self._espec_to_mano_numa_memory_policy[numa_memory_policy]
+ else:
+ return None
+
+
+
+
+class HostEPAUtils(object):
+ """
+ Utility class for Host EPA to Openstack flavor extra_specs conversion routines
+ """
+ def __init__(self):
+ self._mano_to_espec_cpumodel = {
+ "PREFER_WESTMERE" : "Westmere",
+ "REQUIRE_WESTMERE" : "Westmere",
+ "PREFER_SANDYBRIDGE" : "SandyBridge",
+ "REQUIRE_SANDYBRIDGE" : "SandyBridge",
+ "PREFER_IVYBRIDGE" : "IvyBridge",
+ "REQUIRE_IVYBRIDGE" : "IvyBridge",
+ "PREFER_HASWELL" : "Haswell",
+ "REQUIRE_HASWELL" : "Haswell",
+ "PREFER_BROADWELL" : "Broadwell",
+ "REQUIRE_BROADWELL" : "Broadwell",
+ "PREFER_NEHALEM" : "Nehalem",
+ "REQUIRE_NEHALEM" : "Nehalem",
+ "PREFER_PENRYN" : "Penryn",
+ "REQUIRE_PENRYN" : "Penryn",
+ "PREFER_CONROE" : "Conroe",
+ "REQUIRE_CONROE" : "Conroe",
+ "PREFER_CORE2DUO" : "Core2Duo",
+ "REQUIRE_CORE2DUO" : "Core2Duo",
+ }
+
+ self._espec_to_mano_cpumodel = {
+ "Westmere" : "REQUIRE_WESTMERE",
+ "SandyBridge" : "REQUIRE_SANDYBRIDGE",
+ "IvyBridge" : "REQUIRE_IVYBRIDGE",
+ "Haswell" : "REQUIRE_HASWELL",
+ "Broadwell" : "REQUIRE_BROADWELL",
+ "Nehalem" : "REQUIRE_NEHALEM",
+ "Penryn" : "REQUIRE_PENRYN",
+ "Conroe" : "REQUIRE_CONROE",
+ "Core2Duo" : "REQUIRE_CORE2DUO",
+ }
+
+ self._mano_to_espec_cpuarch = {
+ "PREFER_X86" : "x86",
+ "REQUIRE_X86" : "x86",
+ "PREFER_X86_64" : "x86_64",
+ "REQUIRE_X86_64" : "x86_64",
+ "PREFER_I686" : "i686",
+ "REQUIRE_I686" : "i686",
+ "PREFER_IA64" : "ia64",
+ "REQUIRE_IA64" : "ia64",
+ "PREFER_ARMV7" : "ARMv7",
+ "REQUIRE_ARMV7" : "ARMv7",
+ "PREFER_ARMV8" : "ARMv8-A",
+ "REQUIRE_ARMV8" : "ARMv8-A",
+ }
+
+ self._espec_to_mano_cpuarch = {
+ "x86" : "REQUIRE_X86",
+ "x86_64" : "REQUIRE_X86_64",
+ "i686" : "REQUIRE_I686",
+ "ia64" : "REQUIRE_IA64",
+ "ARMv7-A" : "REQUIRE_ARMV7",
+ "ARMv8-A" : "REQUIRE_ARMV8",
+ }
+
+ self._mano_to_espec_cpuvendor = {
+ "PREFER_INTEL" : "Intel",
+ "REQUIRE_INTEL" : "Intel",
+ "PREFER_AMD" : "AMD",
+ "REQUIRE_AMD" : "AMD",
+ }
+
+ self._espec_to_mano_cpuvendor = {
+ "Intel" : "REQUIRE_INTEL",
+ "AMD" : "REQUIRE_AMD",
+ }
+
+ self._mano_to_espec_cpufeatures = {
+ "PREFER_AES" : "aes",
+ "REQUIRE_AES" : "aes",
+ "REQUIRE_VME" : "vme",
+ "PREFER_VME" : "vme",
+ "REQUIRE_DE" : "de",
+ "PREFER_DE" : "de",
+ "REQUIRE_PSE" : "pse",
+ "PREFER_PSE" : "pse",
+ "REQUIRE_TSC" : "tsc",
+ "PREFER_TSC" : "tsc",
+ "REQUIRE_MSR" : "msr",
+ "PREFER_MSR" : "msr",
+ "REQUIRE_PAE" : "pae",
+ "PREFER_PAE" : "pae",
+ "REQUIRE_MCE" : "mce",
+ "PREFER_MCE" : "mce",
+ "REQUIRE_CX8" : "cx8",
+ "PREFER_CX8" : "cx8",
+ "REQUIRE_APIC" : "apic",
+ "PREFER_APIC" : "apic",
+ "REQUIRE_SEP" : "sep",
+ "PREFER_SEP" : "sep",
+ "REQUIRE_MTRR" : "mtrr",
+ "PREFER_MTRR" : "mtrr",
+ "REQUIRE_PGE" : "pge",
+ "PREFER_PGE" : "pge",
+ "REQUIRE_MCA" : "mca",
+ "PREFER_MCA" : "mca",
+ "REQUIRE_CMOV" : "cmov",
+ "PREFER_CMOV" : "cmov",
+ "REQUIRE_PAT" : "pat",
+ "PREFER_PAT" : "pat",
+ "REQUIRE_PSE36" : "pse36",
+ "PREFER_PSE36" : "pse36",
+ "REQUIRE_CLFLUSH" : "clflush",
+ "PREFER_CLFLUSH" : "clflush",
+ "REQUIRE_DTS" : "dts",
+ "PREFER_DTS" : "dts",
+ "REQUIRE_ACPI" : "acpi",
+ "PREFER_ACPI" : "acpi",
+ "REQUIRE_MMX" : "mmx",
+ "PREFER_MMX" : "mmx",
+ "REQUIRE_FXSR" : "fxsr",
+ "PREFER_FXSR" : "fxsr",
+ "REQUIRE_SSE" : "sse",
+ "PREFER_SSE" : "sse",
+ "REQUIRE_SSE2" : "sse2",
+ "PREFER_SSE2" : "sse2",
+ "REQUIRE_SS" : "ss",
+ "PREFER_SS" : "ss",
+ "REQUIRE_HT" : "ht",
+ "PREFER_HT" : "ht",
+ "REQUIRE_TM" : "tm",
+ "PREFER_TM" : "tm",
+ "REQUIRE_IA64" : "ia64",
+ "PREFER_IA64" : "ia64",
+ "REQUIRE_PBE" : "pbe",
+ "PREFER_PBE" : "pbe",
+ "REQUIRE_RDTSCP" : "rdtscp",
+ "PREFER_RDTSCP" : "rdtscp",
+ "REQUIRE_PNI" : "pni",
+ "PREFER_PNI" : "pni",
+ "REQUIRE_PCLMULQDQ": "pclmulqdq",
+ "PREFER_PCLMULQDQ" : "pclmulqdq",
+ "REQUIRE_DTES64" : "dtes64",
+ "PREFER_DTES64" : "dtes64",
+ "REQUIRE_MONITOR" : "monitor",
+ "PREFER_MONITOR" : "monitor",
+ "REQUIRE_DS_CPL" : "ds_cpl",
+ "PREFER_DS_CPL" : "ds_cpl",
+ "REQUIRE_VMX" : "vmx",
+ "PREFER_VMX" : "vmx",
+ "REQUIRE_SMX" : "smx",
+ "PREFER_SMX" : "smx",
+ "REQUIRE_EST" : "est",
+ "PREFER_EST" : "est",
+ "REQUIRE_TM2" : "tm2",
+ "PREFER_TM2" : "tm2",
+ "REQUIRE_SSSE3" : "ssse3",
+ "PREFER_SSSE3" : "ssse3",
+ "REQUIRE_CID" : "cid",
+ "PREFER_CID" : "cid",
+ "REQUIRE_FMA" : "fma",
+ "PREFER_FMA" : "fma",
+ "REQUIRE_CX16" : "cx16",
+ "PREFER_CX16" : "cx16",
+ "REQUIRE_XTPR" : "xtpr",
+ "PREFER_XTPR" : "xtpr",
+ "REQUIRE_PDCM" : "pdcm",
+ "PREFER_PDCM" : "pdcm",
+ "REQUIRE_PCID" : "pcid",
+ "PREFER_PCID" : "pcid",
+ "REQUIRE_DCA" : "dca",
+ "PREFER_DCA" : "dca",
+ "REQUIRE_SSE4_1" : "sse4_1",
+ "PREFER_SSE4_1" : "sse4_1",
+ "REQUIRE_SSE4_2" : "sse4_2",
+ "PREFER_SSE4_2" : "sse4_2",
+ "REQUIRE_X2APIC" : "x2apic",
+ "PREFER_X2APIC" : "x2apic",
+ "REQUIRE_MOVBE" : "movbe",
+ "PREFER_MOVBE" : "movbe",
+ "REQUIRE_POPCNT" : "popcnt",
+ "PREFER_POPCNT" : "popcnt",
+ "REQUIRE_TSC_DEADLINE_TIMER" : "tsc_deadline_timer",
+ "PREFER_TSC_DEADLINE_TIMER" : "tsc_deadline_timer",
+ "REQUIRE_XSAVE" : "xsave",
+ "PREFER_XSAVE" : "xsave",
+ "REQUIRE_AVX" : "avx",
+ "PREFER_AVX" : "avx",
+ "REQUIRE_F16C" : "f16c",
+ "PREFER_F16C" : "f16c",
+ "REQUIRE_RDRAND" : "rdrand",
+ "PREFER_RDRAND" : "rdrand",
+ "REQUIRE_FSGSBASE" : "fsgsbase",
+ "PREFER_FSGSBASE" : "fsgsbase",
+ "REQUIRE_BMI1" : "bmi1",
+ "PREFER_BMI1" : "bmi1",
+ "REQUIRE_HLE" : "hle",
+ "PREFER_HLE" : "hle",
+ "REQUIRE_AVX2" : "avx2",
+ "PREFER_AVX2" : "avx2",
+ "REQUIRE_SMEP" : "smep",
+ "PREFER_SMEP" : "smep",
+ "REQUIRE_BMI2" : "bmi2",
+ "PREFER_BMI2" : "bmi2",
+ "REQUIRE_ERMS" : "erms",
+ "PREFER_ERMS" : "erms",
+ "REQUIRE_INVPCID" : "invpcid",
+ "PREFER_INVPCID" : "invpcid",
+ "REQUIRE_RTM" : "rtm",
+ "PREFER_RTM" : "rtm",
+ "REQUIRE_MPX" : "mpx",
+ "PREFER_MPX" : "mpx",
+ "REQUIRE_RDSEED" : "rdseed",
+ "PREFER_RDSEED" : "rdseed",
+ "REQUIRE_ADX" : "adx",
+ "PREFER_ADX" : "adx",
+ "REQUIRE_SMAP" : "smap",
+ "PREFER_SMAP" : "smap",
+ }
+
+ self._espec_to_mano_cpufeatures = {
+ "aes" : "REQUIRE_AES",
+ "vme" : "REQUIRE_VME",
+ "de" : "REQUIRE_DE",
+ "pse" : "REQUIRE_PSE",
+ "tsc" : "REQUIRE_TSC",
+ "msr" : "REQUIRE_MSR",
+ "pae" : "REQUIRE_PAE",
+ "mce" : "REQUIRE_MCE",
+ "cx8" : "REQUIRE_CX8",
+ "apic" : "REQUIRE_APIC",
+ "sep" : "REQUIRE_SEP",
+ "mtrr" : "REQUIRE_MTRR",
+ "pge" : "REQUIRE_PGE",
+ "mca" : "REQUIRE_MCA",
+ "cmov" : "REQUIRE_CMOV",
+ "pat" : "REQUIRE_PAT",
+ "pse36" : "REQUIRE_PSE36",
+ "clflush" : "REQUIRE_CLFLUSH",
+ "dts" : "REQUIRE_DTS",
+ "acpi" : "REQUIRE_ACPI",
+ "mmx" : "REQUIRE_MMX",
+ "fxsr" : "REQUIRE_FXSR",
+ "sse" : "REQUIRE_SSE",
+ "sse2" : "REQUIRE_SSE2",
+ "ss" : "REQUIRE_SS",
+ "ht" : "REQUIRE_HT",
+ "tm" : "REQUIRE_TM",
+ "ia64" : "REQUIRE_IA64",
+ "pbe" : "REQUIRE_PBE",
+ "rdtscp" : "REQUIRE_RDTSCP",
+ "pni" : "REQUIRE_PNI",
+ "pclmulqdq": "REQUIRE_PCLMULQDQ",
+ "dtes64" : "REQUIRE_DTES64",
+ "monitor" : "REQUIRE_MONITOR",
+ "ds_cpl" : "REQUIRE_DS_CPL",
+ "vmx" : "REQUIRE_VMX",
+ "smx" : "REQUIRE_SMX",
+ "est" : "REQUIRE_EST",
+ "tm2" : "REQUIRE_TM2",
+ "ssse3" : "REQUIRE_SSSE3",
+ "cid" : "REQUIRE_CID",
+ "fma" : "REQUIRE_FMA",
+ "cx16" : "REQUIRE_CX16",
+ "xtpr" : "REQUIRE_XTPR",
+ "pdcm" : "REQUIRE_PDCM",
+ "pcid" : "REQUIRE_PCID",
+ "dca" : "REQUIRE_DCA",
+ "sse4_1" : "REQUIRE_SSE4_1",
+ "sse4_2" : "REQUIRE_SSE4_2",
+ "x2apic" : "REQUIRE_X2APIC",
+ "movbe" : "REQUIRE_MOVBE",
+ "popcnt" : "REQUIRE_POPCNT",
+ "tsc_deadline_timer" : "REQUIRE_TSC_DEADLINE_TIMER",
+ "xsave" : "REQUIRE_XSAVE",
+ "avx" : "REQUIRE_AVX",
+ "f16c" : "REQUIRE_F16C",
+ "rdrand" : "REQUIRE_RDRAND",
+ "fsgsbase" : "REQUIRE_FSGSBASE",
+ "bmi1" : "REQUIRE_BMI1",
+ "hle" : "REQUIRE_HLE",
+ "avx2" : "REQUIRE_AVX2",
+ "smep" : "REQUIRE_SMEP",
+ "bmi2" : "REQUIRE_BMI2",
+ "erms" : "REQUIRE_ERMS",
+ "invpcid" : "REQUIRE_INVPCID",
+ "rtm" : "REQUIRE_RTM",
+ "mpx" : "REQUIRE_MPX",
+ "rdseed" : "REQUIRE_RDSEED",
+ "adx" : "REQUIRE_ADX",
+ "smap" : "REQUIRE_SMAP",
+ }
+
+ def mano_to_extra_spec_cpu_model(self, cpu_model):
+ if cpu_model in self._mano_to_espec_cpumodel:
+ return self._mano_to_espec_cpumodel[cpu_model]
+ else:
+ return None
+
+ def extra_specs_to_mano_cpu_model(self, cpu_model):
+ if cpu_model in self._espec_to_mano_cpumodel:
+ return self._espec_to_mano_cpumodel[cpu_model]
+ else:
+ return None
+
+ def mano_to_extra_spec_cpu_arch(self, cpu_arch):
+ if cpu_arch in self._mano_to_espec_cpuarch:
+ return self._mano_to_espec_cpuarch[cpu_arch]
+ else:
+ return None
+
+ def extra_specs_to_mano_cpu_arch(self, cpu_arch):
+ if cpu_arch in self._espec_to_mano_cpuarch:
+ return self._espec_to_mano_cpuarch[cpu_arch]
+ else:
+ return None
+
+ def mano_to_extra_spec_cpu_vendor(self, cpu_vendor):
+ if cpu_vendor in self._mano_to_espec_cpuvendor:
+ return self._mano_to_espec_cpuvendor[cpu_vendor]
+ else:
+ return None
+
+ def extra_spec_to_mano_cpu_vendor(self, cpu_vendor):
+ if cpu_vendor in self._espec_to_mano_cpuvendor:
+ return self._espec_to_mano_cpuvendor[cpu_vendor]
+ else:
+ return None
+
+ def mano_to_extra_spec_cpu_socket_count(self, cpu_sockets):
+ return cpu_sockets
+
+ def extra_spec_to_mano_cpu_socket_count(self, cpu_sockets):
+ return int(cpu_sockets)
+
+ def mano_to_extra_spec_cpu_core_count(self, cpu_core_count):
+ return cpu_core_count
+
+ def extra_spec_to_mano_cpu_core_count(self, cpu_core_count):
+ return int(cpu_core_count)
+
+ def mano_to_extra_spec_cpu_core_thread_count(self, core_thread_count):
+ return core_thread_count
+
+ def extra_spec_to_mano_cpu_core_thread_count(self, core_thread_count):
+ return int(core_thread_count)
+
+ def mano_to_extra_spec_cpu_features(self, features):
+ cpu_features = []
+ epa_feature_str = None
+ for f in features:
+ if f in self._mano_to_espec_cpufeatures:
+ cpu_features.append(self._mano_to_espec_cpufeatures[f])
+
+ if len(cpu_features) > 1:
+ epa_feature_str = '<all-in> '+ " ".join(cpu_features)
+ elif len(cpu_features) == 1:
+ epa_feature_str = " ".join(cpu_features)
+
+ return epa_feature_str
+
+ def extra_spec_to_mano_cpu_features(self, features):
+ oper_symbols = ['=', '<in>', '<all-in>', '==', '!=', '>=', '<=', 's==', 's!=', 's<', 's<=', 's>', 's>=']
+ cpu_features = []
+ result = None
+ for oper in oper_symbols:
+ regex = '^'+oper+' (.*?)$'
+ result = re.search(regex, features)
+ if result is not None:
+ break
+
+ if result is not None:
+ feature_list = result.group(1)
+ else:
+ feature_list = features
+
+ for f in feature_list.split():
+ if f in self._espec_to_mano_cpufeatures:
+ cpu_features.append(self._espec_to_mano_cpufeatures[f])
+
+ return cpu_features
+
+
+class ExtraSpecUtils(object):
+ """
+ General utility class for flavor Extra Specs processing
+ """
+ def __init__(self):
+ self.host = HostEPAUtils()
+ self.guest = GuestEPAUtils()
+ self.extra_specs_keywords = [ 'hw:cpu_policy',
+ 'hw:cpu_threads_policy',
+ 'hw:mem_page_size',
+ 'hw:numa_nodes',
+ 'hw:numa_mempolicy',
+ 'hw:numa_cpus',
+ 'hw:numa_mem',
+ 'trust:trusted_host',
+ 'pci_passthrough:alias',
+ 'capabilities:cpu_info:model',
+ 'capabilities:cpu_info:arch',
+ 'capabilities:cpu_info:vendor',
+ 'capabilities:cpu_info:topology:sockets',
+ 'capabilities:cpu_info:topology:cores',
+ 'capabilities:cpu_info:topology:threads',
+ 'capabilities:cpu_info:features',
+ ]
+ self.extra_specs_regex = re.compile("^"+"|^".join(self.extra_specs_keywords))
+
+
+
+class FlavorUtils(object):
+ """
+ Utility class for handling the flavor
+ """
+ def __init__(self, driver):
+ """
+ Constructor for class
+ Arguments:
+ driver: object of OpenstackDriver()
+ """
+ self._epa = ExtraSpecUtils()
+ self._driver = driver
+ self.log = driver.log
+
+ @property
+ def driver(self):
+ return self._driver
+
+ def _get_guest_epa_specs(self, guest_epa):
+ """
+ Returns EPA Specs dictionary for guest_epa attributes
+ """
+ epa_specs = dict()
+ if guest_epa.has_field('mempage_size'):
+ mempage_size = self._epa.guest.mano_to_extra_spec_mempage_size(guest_epa.mempage_size)
+ if mempage_size is not None:
+ epa_specs['hw:mem_page_size'] = mempage_size
+
+ if guest_epa.has_field('cpu_pinning_policy'):
+ cpu_pinning_policy = self._epa.guest.mano_to_extra_spec_cpu_pinning_policy(guest_epa.cpu_pinning_policy)
+ if cpu_pinning_policy is not None:
+ epa_specs['hw:cpu_policy'] = cpu_pinning_policy
+
+ if guest_epa.has_field('cpu_thread_pinning_policy'):
+ cpu_thread_pinning_policy = self._epa.guest.mano_to_extra_spec_cpu_thread_pinning_policy(guest_epa.cpu_thread_pinning_policy)
+ if cpu_thread_pinning_policy is None:
+ epa_specs['hw:cpu_threads_policy'] = cpu_thread_pinning_policy
+
+ if guest_epa.has_field('trusted_execution'):
+ trusted_execution = self._epa.guest.mano_to_extra_spec_trusted_execution(guest_epa.trusted_execution)
+ if trusted_execution is not None:
+ epa_specs['trust:trusted_host'] = trusted_execution
+
+ if guest_epa.has_field('numa_node_policy'):
+ if guest_epa.numa_node_policy.has_field('node_cnt'):
+ numa_node_count = self._epa.guest.mano_to_extra_spec_numa_node_count(guest_epa.numa_node_policy.node_cnt)
+ if numa_node_count is not None:
+ epa_specs['hw:numa_nodes'] = numa_node_count
+
+ if guest_epa.numa_node_policy.has_field('mem_policy'):
+ numa_memory_policy = self._epa.guest.mano_to_extra_spec_numa_memory_policy(guest_epa.numa_node_policy.mem_policy)
+ if numa_memory_policy is not None:
+ epa_specs['hw:numa_mempolicy'] = numa_memory_policy
+
+ if guest_epa.numa_node_policy.has_field('node'):
+ for node in guest_epa.numa_node_policy.node:
+ if node.has_field('vcpu') and node.vcpu:
+ epa_specs['hw:numa_cpus.'+str(node.id)] = ','.join([str(j.id) for j in node.vcpu])
+ if node.memory_mb:
+ epa_specs['hw:numa_mem.'+str(node.id)] = str(node.memory_mb)
+
+ if guest_epa.has_field('pcie_device'):
+ pci_devices = []
+ for device in guest_epa.pcie_device:
+ pci_devices.append(device.device_id +':'+str(device.count))
+ epa_specs['pci_passthrough:alias'] = ','.join(pci_devices)
+
+ return epa_specs
+
+ def _get_host_epa_specs(self,host_epa):
+ """
+ Returns EPA Specs dictionary for host_epa attributes
+ """
+ epa_specs = dict()
+
+ if host_epa.has_field('cpu_model'):
+ cpu_model = self._epa.host.mano_to_extra_spec_cpu_model(host_epa.cpu_model)
+ if cpu_model is not None:
+ epa_specs['capabilities:cpu_info:model'] = cpu_model
+
+ if host_epa.has_field('cpu_arch'):
+ cpu_arch = self._epa.host.mano_to_extra_spec_cpu_arch(host_epa.cpu_arch)
+ if cpu_arch is not None:
+ epa_specs['capabilities:cpu_info:arch'] = cpu_arch
+
+ if host_epa.has_field('cpu_vendor'):
+ cpu_vendor = self._epa.host.mano_to_extra_spec_cpu_vendor(host_epa.cpu_vendor)
+ if cpu_vendor is not None:
+ epa_specs['capabilities:cpu_info:vendor'] = cpu_vendor
+
+ if host_epa.has_field('cpu_socket_count'):
+ cpu_socket_count = self._epa.host.mano_to_extra_spec_cpu_socket_count(host_epa.cpu_socket_count)
+ if cpu_socket_count is not None:
+ epa_specs['capabilities:cpu_info:topology:sockets'] = cpu_socket_count
+
+ if host_epa.has_field('cpu_core_count'):
+ cpu_core_count = self._epa.host.mano_to_extra_spec_cpu_core_count(host_epa.cpu_core_count)
+ if cpu_core_count is not None:
+ epa_specs['capabilities:cpu_info:topology:cores'] = cpu_core_count
+
+ if host_epa.has_field('cpu_core_thread_count'):
+ cpu_core_thread_count = self._epa.host.mano_to_extra_spec_cpu_core_thread_count(host_epa.cpu_core_thread_count)
+ if cpu_core_thread_count is not None:
+ epa_specs['capabilities:cpu_info:topology:threads'] = cpu_core_thread_count
+
+ if host_epa.has_field('cpu_feature'):
+ cpu_features = []
+ espec_cpu_features = []
+ for feature in host_epa.cpu_feature:
+ cpu_features.append(feature.feature)
+ espec_cpu_features = self._epa.host.mano_to_extra_spec_cpu_features(cpu_features)
+ if espec_cpu_features is not None:
+ epa_specs['capabilities:cpu_info:features'] = espec_cpu_features
+ return epa_specs
+
+ def _get_hypervisor_epa_specs(self,guest_epa):
+ """
+ Returns EPA Specs dictionary for hypervisor_epa attributes
+ """
+ hypervisor_epa = dict()
+ return hypervisor_epa
+
+ def _get_vswitch_epa_specs(self, guest_epa):
+ """
+ Returns EPA Specs dictionary for vswitch_epa attributes
+ """
+ vswitch_epa = dict()
+ return vswitch_epa
+
+ def _get_host_aggregate_epa_specs(self, host_aggregate):
+ """
+ Returns EPA Specs dictionary for host aggregates
+ """
+ epa_specs = dict()
+ for aggregate in host_aggregate:
+ epa_specs['aggregate_instance_extra_specs:'+aggregate.metadata_key] = aggregate.metadata_value
+
+ return epa_specs
+
+ def get_extra_specs(self, flavor):
+ """
+ Returns epa_specs dictionary based on flavor information
+ Arguments
+ flavor -- Protobuf GI object for flavor_info (RwcalYang.FlavorInfoItem())
+ Returns:
+ A dictionary of extra_specs in format understood by novaclient library
+ """
+ epa_specs = dict()
+ if flavor.has_field('guest_epa'):
+ guest_epa = self._get_guest_epa_specs(flavor.guest_epa)
+ epa_specs.update(guest_epa)
+ if flavor.has_field('host_epa'):
+ host_epa = self._get_host_epa_specs(flavor.host_epa)
+ epa_specs.update(host_epa)
+ if flavor.has_field('hypervisor_epa'):
+ hypervisor_epa = self._get_hypervisor_epa_specs(flavor.hypervisor_epa)
+ epa_specs.update(hypervisor_epa)
+ if flavor.has_field('vswitch_epa'):
+ vswitch_epa = self._get_vswitch_epa_specs(flavor.vswitch_epa)
+ epa_specs.update(vswitch_epa)
+ if flavor.has_field('host_aggregate'):
+ host_aggregate = self._get_host_aggregate_epa_specs(flavor.host_aggregate)
+ epa_specs.update(host_aggregate)
+ return epa_specs
+
+
+ def parse_vm_flavor_epa_info(self, flavor_info):
+ """
+ Parse the flavor_info dictionary (returned by python-client) for vm_flavor
+
+ Arguments:
+ flavor_info: A dictionary object return by novaclient library listing flavor attributes
+
+ Returns:
+ vm_flavor = RwcalYang.FlavorInfoItem_VmFlavor()
+ """
+ vm_flavor = RwcalYang.FlavorInfoItem_VmFlavor()
+
+ if 'vcpus' in flavor_info and flavor_info['vcpus']:
+ vm_flavor.vcpu_count = flavor_info['vcpus']
+
+ if 'ram' in flavor_info and flavor_info['ram']:
+ vm_flavor.memory_mb = flavor_info['ram']
+
+ if 'disk' in flavor_info and flavor_info['disk']:
+ vm_flavor.storage_gb = flavor_info['disk']
+
+ return vm_flavor
+
+ def parse_guest_epa_info(self, flavor_info):
+ """
+ Parse the flavor_info dictionary (returned by python-client) for guest_epa
+
+ Arguments:
+ flavor_info: A dictionary object return by novaclient library listing flavor attributes
+
+ Returns:
+ guest_epa = RwcalYang.FlavorInfoItem_GuestEpa()
+ """
+ guest_epa = RwcalYang.FlavorInfoItem_GuestEpa()
+ for attr in flavor_info['extra_specs']:
+ if attr == 'hw:cpu_policy':
+ cpu_pinning_policy = self._epa.guest.extra_spec_to_mano_cpu_pinning_policy(flavor_info['extra_specs']['hw:cpu_policy'])
+ if cpu_pinning_policy is not None:
+ guest_epa.cpu_pinning_policy = cpu_pinning_policy
+
+ elif attr == 'hw:cpu_threads_policy':
+ cpu_thread_pinning_policy = self._epa.guest.extra_spec_to_mano_cpu_thread_pinning_policy(flavor_info['extra_specs']['hw:cpu_threads_policy'])
+ if cpu_thread_pinning_policy is not None:
+ guest_epa.cpu_thread_pinning_policy = cpu_thread_pinning_policy
+
+ elif attr == 'hw:mem_page_size':
+ mempage_size = self._epa.guest.extra_spec_to_mano_mempage_size(flavor_info['extra_specs']['hw:mem_page_size'])
+ if mempage_size is not None:
+ guest_epa.mempage_size = mempage_size
+
+ elif attr == 'hw:numa_nodes':
+ numa_node_count = self._epa.guest.extra_specs_to_mano_numa_node_count(flavor_info['extra_specs']['hw:numa_nodes'])
+ if numa_node_count is not None:
+ guest_epa.numa_node_policy.node_cnt = numa_node_count
+
+ elif attr.startswith('hw:numa_cpus.'):
+ node_id = attr.split('.')[1]
+ nodes = [ n for n in guest_epa.numa_node_policy.node if n.id == int(node_id) ]
+ if nodes:
+ numa_node = nodes[0]
+ else:
+ numa_node = guest_epa.numa_node_policy.node.add()
+ numa_node.id = int(node_id)
+
+ for x in flavor_info['extra_specs'][attr].split(','):
+ numa_node_vcpu = numa_node.vcpu.add()
+ numa_node_vcpu.id = int(x)
+
+ elif attr.startswith('hw:numa_mem.'):
+ node_id = attr.split('.')[1]
+ nodes = [ n for n in guest_epa.numa_node_policy.node if n.id == int(node_id) ]
+ if nodes:
+ numa_node = nodes[0]
+ else:
+ numa_node = guest_epa.numa_node_policy.node.add()
+ numa_node.id = int(node_id)
+
+ numa_node.memory_mb = int(flavor_info['extra_specs'][attr])
+
+ elif attr == 'hw:numa_mempolicy':
+ numa_memory_policy = self._epa.guest.extra_to_mano_spec_numa_memory_policy(flavor_info['extra_specs']['hw:numa_mempolicy'])
+ if numa_memory_policy is not None:
+ guest_epa.numa_node_policy.mem_policy = numa_memory_policy
+
+ elif attr == 'trust:trusted_host':
+ trusted_execution = self._epa.guest.extra_spec_to_mano_trusted_execution(flavor_info['extra_specs']['trust:trusted_host'])
+ if trusted_execution is not None:
+ guest_epa.trusted_execution = trusted_execution
+
+ elif attr == 'pci_passthrough:alias':
+ device_types = flavor_info['extra_specs']['pci_passthrough:alias']
+ for device in device_types.split(','):
+ dev = guest_epa.pcie_device.add()
+ dev.device_id = device.split(':')[0]
+ dev.count = int(device.split(':')[1])
+ return guest_epa
+
+ def parse_host_epa_info(self, flavor_info):
+ """
+ Parse the flavor_info dictionary (returned by python-client) for host_epa
+
+ Arguments:
+ flavor_info: A dictionary object return by novaclient library listing flavor attributes
+
+ Returns:
+ host_epa = RwcalYang.FlavorInfoItem_HostEpa()
+ """
+ host_epa = RwcalYang.FlavorInfoItem_HostEpa()
+ for attr in flavor_info['extra_specs']:
+ if attr == 'capabilities:cpu_info:model':
+ cpu_model = self._epa.host.extra_specs_to_mano_cpu_model(flavor_info['extra_specs']['capabilities:cpu_info:model'])
+ if cpu_model is not None:
+ host_epa.cpu_model = cpu_model
+
+ elif attr == 'capabilities:cpu_info:arch':
+ cpu_arch = self._epa.host.extra_specs_to_mano_cpu_arch(flavor_info['extra_specs']['capabilities:cpu_info:arch'])
+ if cpu_arch is not None:
+ host_epa.cpu_arch = cpu_arch
+
+ elif attr == 'capabilities:cpu_info:vendor':
+ cpu_vendor = self._epa.host.extra_spec_to_mano_cpu_vendor(flavor_info['extra_specs']['capabilities:cpu_info:vendor'])
+ if cpu_vendor is not None:
+ host_epa.cpu_vendor = cpu_vendor
+
+ elif attr == 'capabilities:cpu_info:topology:sockets':
+ cpu_sockets = self._epa.host.extra_spec_to_mano_cpu_socket_count(flavor_info['extra_specs']['capabilities:cpu_info:topology:sockets'])
+ if cpu_sockets is not None:
+ host_epa.cpu_socket_count = cpu_sockets
+
+ elif attr == 'capabilities:cpu_info:topology:cores':
+ cpu_cores = self._epa.host.extra_spec_to_mano_cpu_core_count(flavor_info['extra_specs']['capabilities:cpu_info:topology:cores'])
+ if cpu_cores is not None:
+ host_epa.cpu_core_count = cpu_cores
+
+ elif attr == 'capabilities:cpu_info:topology:threads':
+ cpu_threads = self._epa.host.extra_spec_to_mano_cpu_core_thread_count(flavor_info['extra_specs']['capabilities:cpu_info:topology:threads'])
+ if cpu_threads is not None:
+ host_epa.cpu_core_thread_count = cpu_threads
+
+ elif attr == 'capabilities:cpu_info:features':
+ cpu_features = self._epa.host.extra_spec_to_mano_cpu_features(flavor_info['extra_specs']['capabilities:cpu_info:features'])
+ if cpu_features is not None:
+ for feature in cpu_features:
+ host_epa.cpu_feature.append(feature)
+ return host_epa
+
+ def parse_host_aggregate_epa_info(self, flavor_info):
+ """
+ Parse the flavor_info dictionary (returned by python-client) for host_aggregate
+
+ Arguments:
+ flavor_info: A dictionary object return by novaclient library listing flavor attributes
+
+ Returns:
+ A list of objects host_aggregate of type RwcalYang.FlavorInfoItem_HostAggregate()
+ """
+ host_aggregates = list()
+ for attr in flavor_info['extra_specs']:
+ if attr.startswith('aggregate_instance_extra_specs:'):
+ aggregate = RwcalYang.FlavorInfoItem_HostAggregate()
+ aggregate.metadata_key = ":".join(attr.split(':')[1::])
+ aggregate.metadata_value = flavor_info['extra_specs'][attr]
+ host_aggregates.append(aggregate)
+ return host_aggregates
+
+
+ def parse_flavor_info(self, flavor_info):
+ """
+ Parse the flavor_info dictionary and put value in RIFT GI object for flavor
+ Arguments:
+ flavor_info: A dictionary object returned by novaclient library listing flavor attributes
+
+ Returns:
+ Protobuf GI Object of type RwcalYang.FlavorInfoItem()
+
+ """
+ flavor = RwcalYang.FlavorInfoItem()
+ if 'name' in flavor_info and flavor_info['name']:
+ flavor.name = flavor_info['name']
+ if 'id' in flavor_info and flavor_info['id']:
+ flavor.id = flavor_info['id']
+
+ ### If extra_specs in flavor_info
+ if 'extra_specs' in flavor_info:
+ flavor.vm_flavor = self.parse_vm_flavor_epa_info(flavor_info)
+ flavor.guest_epa = self.parse_guest_epa_info(flavor_info)
+ flavor.host_epa = self.parse_host_epa_info(flavor_info)
+ for aggr in self.parse_host_aggregate_epa_info(flavor_info):
+ ha = flavor.host_aggregate.add()
+ ha.from_dict(aggr.as_dict())
+ return flavor
+
+ def _match_vm_flavor(self, required, available):
+ self.log.info("Matching VM Flavor attributes")
+ if available.vcpu_count != required.vcpu_count:
+ self.log.debug("VCPU requirement mismatch. Required: %d, Available: %d",
+ required.vcpu_count,
+ available.vcpu_count)
+ return False
+ if available.memory_mb != required.memory_mb:
+ self.log.debug("Memory requirement mismatch. Required: %d MB, Available: %d MB",
+ required.memory_mb,
+ available.memory_mb)
+ return False
+ if available.storage_gb != required.storage_gb:
+ self.log.debug("Storage requirement mismatch. Required: %d GB, Available: %d GB",
+ required.storage_gb,
+ available.storage_gb)
+ return False
+ self.log.debug("VM Flavor match found")
+ return True
+
+ def _match_guest_epa(self, required, available):
+ self.log.info("Matching Guest EPA attributes")
+ if required.has_field('pcie_device'):
+ self.log.debug("Matching pcie_device")
+ if available.has_field('pcie_device') == False:
+ self.log.debug("Matching pcie_device failed. Not available in flavor")
+ return False
+ else:
+ for dev in required.pcie_device:
+ if not [ d for d in available.pcie_device
+ if ((d.device_id == dev.device_id) and (d.count == dev.count)) ]:
+ self.log.debug("Matching pcie_device failed. Required: %s, Available: %s",
+ required.pcie_device, available.pcie_device)
+ return False
+ elif available.has_field('pcie_device'):
+ self.log.debug("Rejecting available flavor because pcie_device not required but available")
+ return False
+
+
+ if required.has_field('mempage_size'):
+ self.log.debug("Matching mempage_size")
+ if available.has_field('mempage_size') == False:
+ self.log.debug("Matching mempage_size failed. Not available in flavor")
+ return False
+ else:
+ if required.mempage_size != available.mempage_size:
+ self.log.debug("Matching mempage_size failed. Required: %s, Available: %s",
+ required.mempage_size, available.mempage_size)
+ return False
+ elif available.has_field('mempage_size'):
+ self.log.debug("Rejecting available flavor because mempage_size not required but available")
+ return False
+
+ if required.has_field('cpu_pinning_policy'):
+ self.log.debug("Matching cpu_pinning_policy")
+ if required.cpu_pinning_policy != 'ANY':
+ if available.has_field('cpu_pinning_policy') == False:
+ self.log.debug("Matching cpu_pinning_policy failed. Not available in flavor")
+ return False
+ else:
+ if required.cpu_pinning_policy != available.cpu_pinning_policy:
+ self.log.debug("Matching cpu_pinning_policy failed. Required: %s, Available: %s",
+ required.cpu_pinning_policy, available.cpu_pinning_policy)
+ return False
+ elif available.has_field('cpu_pinning_policy'):
+ self.log.debug("Rejecting available flavor because cpu_pinning_policy not required but available")
+ return False
+
+ if required.has_field('cpu_thread_pinning_policy'):
+ self.log.debug("Matching cpu_thread_pinning_policy")
+ if available.has_field('cpu_thread_pinning_policy') == False:
+ self.log.debug("Matching cpu_thread_pinning_policy failed. Not available in flavor")
+ return False
+ else:
+ if required.cpu_thread_pinning_policy != available.cpu_thread_pinning_policy:
+ self.log.debug("Matching cpu_thread_pinning_policy failed. Required: %s, Available: %s",
+ required.cpu_thread_pinning_policy, available.cpu_thread_pinning_policy)
+ return False
+ elif available.has_field('cpu_thread_pinning_policy'):
+ self.log.debug("Rejecting available flavor because cpu_thread_pinning_policy not required but available")
+ return False
+
+ if required.has_field('trusted_execution'):
+ self.log.debug("Matching trusted_execution")
+ if required.trusted_execution == True:
+ if available.has_field('trusted_execution') == False:
+ self.log.debug("Matching trusted_execution failed. Not available in flavor")
+ return False
+ else:
+ if required.trusted_execution != available.trusted_execution:
+ self.log.debug("Matching trusted_execution failed. Required: %s, Available: %s",
+ required.trusted_execution, available.trusted_execution)
+ return False
+ elif available.has_field('trusted_execution'):
+ self.log.debug("Rejecting available flavor because trusted_execution not required but available")
+ return False
+
+ if required.has_field('numa_node_policy'):
+ self.log.debug("Matching numa_node_policy")
+ if available.has_field('numa_node_policy') == False:
+ self.log.debug("Matching numa_node_policy failed. Not available in flavor")
+ return False
+ else:
+ if required.numa_node_policy.has_field('node_cnt'):
+ self.log.debug("Matching numa_node_policy node_cnt")
+ if available.numa_node_policy.has_field('node_cnt') == False:
+ self.log.debug("Matching numa_node_policy node_cnt failed. Not available in flavor")
+ return False
+ else:
+ if required.numa_node_policy.node_cnt != available.numa_node_policy.node_cnt:
+ self.log.debug("Matching numa_node_policy node_cnt failed. Required: %s, Available: %s",
+ required.numa_node_policy.node_cnt, available.numa_node_policy.node_cnt)
+ return False
+ elif available.numa_node_policy.has_field('node_cnt'):
+ self.log.debug("Rejecting available flavor because numa node count not required but available")
+ return False
+
+ if required.numa_node_policy.has_field('mem_policy'):
+ self.log.debug("Matching numa_node_policy mem_policy")
+ if available.numa_node_policy.has_field('mem_policy') == False:
+ self.log.debug("Matching numa_node_policy mem_policy failed. Not available in flavor")
+ return False
+ else:
+ if required.numa_node_policy.mem_policy != available.numa_node_policy.mem_policy:
+ self.log.debug("Matching numa_node_policy mem_policy failed. Required: %s, Available: %s",
+ required.numa_node_policy.mem_policy, available.numa_node_policy.mem_policy)
+ return False
+ elif available.numa_node_policy.has_field('mem_policy'):
+ self.log.debug("Rejecting available flavor because num node mem_policy not required but available")
+ return False
+
+ if required.numa_node_policy.has_field('node'):
+ self.log.debug("Matching numa_node_policy nodes configuration")
+ if available.numa_node_policy.has_field('node') == False:
+ self.log.debug("Matching numa_node_policy nodes configuration failed. Not available in flavor")
+ return False
+ for required_node in required.numa_node_policy.node:
+ self.log.debug("Matching numa_node_policy nodes configuration for node %s",
+ required_node)
+ numa_match = False
+ for available_node in available.numa_node_policy.node:
+ if required_node.id != available_node.id:
+ self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s",
+ required_node, available_node)
+ continue
+ if required_node.vcpu != available_node.vcpu:
+ self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s",
+ required_node, available_node)
+ continue
+ if required_node.memory_mb != available_node.memory_mb:
+ self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s",
+ required_node, available_node)
+ continue
+ numa_match = True
+ if numa_match == False:
+ return False
+ elif available.numa_node_policy.has_field('node'):
+ self.log.debug("Rejecting available flavor because numa nodes not required but available")
+ return False
+ elif available.has_field('numa_node_policy'):
+ self.log.debug("Rejecting available flavor because numa_node_policy not required but available")
+ return False
+ self.log.info("Successful match for Guest EPA attributes")
+ return True
+
+ def _match_vswitch_epa(self, required, available):
+ self.log.debug("VSwitch EPA match found")
+ return True
+
+ def _match_hypervisor_epa(self, required, available):
+ self.log.debug("Hypervisor EPA match found")
+ return True
+
+ def _match_host_epa(self, required, available):
+ self.log.info("Matching Host EPA attributes")
+ if required.has_field('cpu_model'):
+ self.log.debug("Matching CPU model")
+ if available.has_field('cpu_model') == False:
+ self.log.debug("Matching CPU model failed. Not available in flavor")
+ return False
+ else:
+ #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
+ if required.cpu_model.replace('PREFER', 'REQUIRE') != available.cpu_model:
+ self.log.debug("Matching CPU model failed. Required: %s, Available: %s",
+ required.cpu_model, available.cpu_model)
+ return False
+ elif available.has_field('cpu_model'):
+ self.log.debug("Rejecting available flavor because cpu_model not required but available")
+ return False
+
+ if required.has_field('cpu_arch'):
+ self.log.debug("Matching CPU architecture")
+ if available.has_field('cpu_arch') == False:
+ self.log.debug("Matching CPU architecture failed. Not available in flavor")
+ return False
+ else:
+ #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
+ if required.cpu_arch.replace('PREFER', 'REQUIRE') != available.cpu_arch:
+ self.log.debug("Matching CPU architecture failed. Required: %s, Available: %s",
+ required.cpu_arch, available.cpu_arch)
+ return False
+ elif available.has_field('cpu_arch'):
+ self.log.debug("Rejecting available flavor because cpu_arch not required but available")
+ return False
+
+ if required.has_field('cpu_vendor'):
+ self.log.debug("Matching CPU vendor")
+ if available.has_field('cpu_vendor') == False:
+ self.log.debug("Matching CPU vendor failed. Not available in flavor")
+ return False
+ else:
+ #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
+ if required.cpu_vendor.replace('PREFER', 'REQUIRE') != available.cpu_vendor:
+ self.log.debug("Matching CPU vendor failed. Required: %s, Available: %s",
+ required.cpu_vendor, available.cpu_vendor)
+ return False
+ elif available.has_field('cpu_vendor'):
+ self.log.debug("Rejecting available flavor because cpu_vendor not required but available")
+ return False
+
+ if required.has_field('cpu_socket_count'):
+ self.log.debug("Matching CPU socket count")
+ if available.has_field('cpu_socket_count') == False:
+ self.log.debug("Matching CPU socket count failed. Not available in flavor")
+ return False
+ else:
+ if required.cpu_socket_count != available.cpu_socket_count:
+ self.log.debug("Matching CPU socket count failed. Required: %s, Available: %s",
+ required.cpu_socket_count, available.cpu_socket_count)
+ return False
+ elif available.has_field('cpu_socket_count'):
+ self.log.debug("Rejecting available flavor because cpu_socket_count not required but available")
+ return False
+
+ if required.has_field('cpu_core_count'):
+ self.log.debug("Matching CPU core count")
+ if available.has_field('cpu_core_count') == False:
+ self.log.debug("Matching CPU core count failed. Not available in flavor")
+ return False
+ else:
+ if required.cpu_core_count != available.cpu_core_count:
+ self.log.debug("Matching CPU core count failed. Required: %s, Available: %s",
+ required.cpu_core_count, available.cpu_core_count)
+ return False
+ elif available.has_field('cpu_core_count'):
+ self.log.debug("Rejecting available flavor because cpu_core_count not required but available")
+ return False
+
+ if required.has_field('cpu_core_thread_count'):
+ self.log.debug("Matching CPU core thread count")
+ if available.has_field('cpu_core_thread_count') == False:
+ self.log.debug("Matching CPU core thread count failed. Not available in flavor")
+ return False
+ else:
+ if required.cpu_core_thread_count != available.cpu_core_thread_count:
+ self.log.debug("Matching CPU core thread count failed. Required: %s, Available: %s",
+ required.cpu_core_thread_count, available.cpu_core_thread_count)
+ return False
+ elif available.has_field('cpu_core_thread_count'):
+ self.log.debug("Rejecting available flavor because cpu_core_thread_count not required but available")
+ return False
+
+ if required.has_field('cpu_feature'):
+ self.log.debug("Matching CPU feature list")
+ if available.has_field('cpu_feature') == False:
+ self.log.debug("Matching CPU feature list failed. Not available in flavor")
+ return False
+ else:
+ for feature in required.cpu_feature:
+ if feature not in available.cpu_feature:
+ self.log.debug("Matching CPU feature list failed. Required feature: %s is not present. Available features: %s",
+ feature, available.cpu_feature)
+ return False
+ elif available.has_field('cpu_feature'):
+ self.log.debug("Rejecting available flavor because cpu_feature not required but available")
+ return False
+ self.log.info("Successful match for Host EPA attributes")
+ return True
+
+
+ def _match_placement_group_inputs(self, required, available):
+ self.log.info("Matching Host aggregate attributes")
+
+ if not required and not available:
+ # Host aggregate not required and not available => success
+ self.log.info("Successful match for Host Aggregate attributes")
+ return True
+ if required and available:
+ # Host aggregate requested and available => Do a match and decide
+ xx = [ x.as_dict() for x in required ]
+ yy = [ y.as_dict() for y in available ]
+ for i in xx:
+ if i not in yy:
+ self.log.debug("Rejecting available flavor because host Aggregate mismatch. Required: %s, Available: %s",
+ required, available)
+ return False
+ self.log.info("Successful match for Host Aggregate attributes")
+ return True
+ else:
+ # Either of following conditions => Failure
+ # - Host aggregate required but not available
+ # - Host aggregate not required but available
+ self.log.debug("Rejecting available flavor because host Aggregate mismatch. Required: %s, Available: %s",
+ required, available)
+ return False
+
+
+ def _match_epa_params(self, resource_info, request_params):
+ """
+ Match EPA attributes
+ Arguments:
+ resource_info: Protobuf GI object RwcalYang.FlavorInfoItem()
+ Following attributes would be accessed
+ - vm_flavor
+ - guest_epa
+ - host_epa
+ - host_aggregate
+
+ request_params: Protobuf GI object RwcalYang.VDUInitParams().
+ Following attributes would be accessed
+ - vm_flavor
+ - guest_epa
+ - host_epa
+ - host_aggregate
+ Returns:
+ True -- Match between resource_info and request_params
+ False -- No match between resource_info and request_params
+ """
+ result = False
+ result = self._match_vm_flavor(getattr(request_params, 'vm_flavor'),
+ getattr(resource_info, 'vm_flavor'))
+ if result == False:
+ self.log.debug("VM Flavor mismatched")
+ return False
+
+ result = self._match_guest_epa(getattr(request_params, 'guest_epa'),
+ getattr(resource_info, 'guest_epa'))
+ if result == False:
+ self.log.debug("Guest EPA mismatched")
+ return False
+
+ result = self._match_vswitch_epa(getattr(request_params, 'vswitch_epa'),
+ getattr(resource_info, 'vswitch_epa'))
+ if result == False:
+ self.log.debug("Vswitch EPA mismatched")
+ return False
+
+ result = self._match_hypervisor_epa(getattr(request_params, 'hypervisor_epa'),
+ getattr(resource_info, 'hypervisor_epa'))
+ if result == False:
+ self.log.debug("Hypervisor EPA mismatched")
+ return False
+
+ result = self._match_host_epa(getattr(request_params, 'host_epa'),
+ getattr(resource_info, 'host_epa'))
+ if result == False:
+ self.log.debug("Host EPA mismatched")
+ return False
+
+ result = self._match_placement_group_inputs(getattr(request_params, 'host_aggregate'),
+ getattr(resource_info, 'host_aggregate'))
+
+ if result == False:
+ self.log.debug("Host Aggregate mismatched")
+ return False
+
+ return True
+
+ def match_resource_flavor(self, vdu_init, flavor_list):
+ """
+ Arguments:
+ vdu_init: Protobuf GI object RwcalYang.VDUInitParams().
+ flavor_list: List of Protobuf GI object RwcalYang.FlavorInfoItem()
+
+ Returns:
+ Flavor_ID -- If match is found between vdu_init and one of flavor_info from flavor_list
+ None -- No match between vdu_init and one of flavor_info from flavor_list
+
+ Select a existing flavor if it matches the request or create new flavor
+ """
+ for flv in flavor_list:
+ self.log.info("Attempting to match compute requirement for VDU: %s with flavor %s",
+ vdu_init.name, flv)
+ if self._match_epa_params(flv, vdu_init):
+ self.log.info("Flavor match found for compute requirements for VDU: %s with flavor name: %s, flavor-id: %s",
+ vdu_init.name, flv.name, flv.id)
+ return flv.id
+ return None
+