X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwcal%2Fplugins%2Fvala%2Frwcal_openstack%2Frift%2Frwcal%2Fopenstack%2Futils%2Fflavor.py;fp=rwcal%2Fplugins%2Fvala%2Frwcal_openstack%2Frift%2Frwcal%2Fopenstack%2Futils%2Fflavor.py;h=31997756aa867cb3a2e536bfe066d9efd99a4ba4;hb=eb223959413d75048f484c1978af10d6b551f19c;hp=0000000000000000000000000000000000000000;hpb=c148feb9a12330f67e4093e4848506106961b737;p=osm%2FSO.git diff --git a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/utils/flavor.py b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/utils/flavor.py new file mode 100644 index 00000000..31997756 --- /dev/null +++ b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/utils/flavor.py @@ -0,0 +1,1308 @@ +#!/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 = ' '+ " ".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 = ['=', '', '', '==', '!=', '>=', '<=', '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 +