diff options
Diffstat (limited to 'nova/virt/libvirt/host.py')
-rw-r--r-- | nova/virt/libvirt/host.py | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/nova/virt/libvirt/host.py b/nova/virt/libvirt/host.py index 46435a9a7f..1ae86d9f47 100644 --- a/nova/virt/libvirt/host.py +++ b/nova/virt/libvirt/host.py @@ -66,6 +66,7 @@ from nova.virt.libvirt import event as libvirtevent from nova.virt.libvirt import guest as libvirt_guest from nova.virt.libvirt import migration as libvirt_migrate from nova.virt.libvirt import utils as libvirt_utils +import nova.virt.node # noqa if ty.TYPE_CHECKING: import libvirt @@ -138,6 +139,7 @@ class Host(object): self._caps = None self._domain_caps = None self._hostname = None + self._node_uuid = None self._wrapped_conn = None self._wrapped_conn_lock = threading.Lock() @@ -738,6 +740,14 @@ class Host(object): return doms + def get_available_cpus(self): + """Get the set of CPUs that exist on the host. + + :returns: set of CPUs, raises libvirtError on error + """ + cpus, cpu_map, online = self.get_connection().getCPUMap() + return {cpu for cpu in range(cpus)} + def get_online_cpus(self): """Get the set of CPUs that are online on the host @@ -1059,6 +1069,12 @@ class Host(object): {'old': self._hostname, 'new': hostname}) return self._hostname + def get_node_uuid(self): + """Returns the UUID of this node.""" + if not self._node_uuid: + self._node_uuid = nova.virt.node.get_local_node_uuid() + return self._node_uuid + def find_secret(self, usage_type, usage_id): """Find a secret. @@ -1605,21 +1621,66 @@ class Host(object): """Compares the given CPU description with the host CPU.""" return self.get_connection().compareCPU(xmlDesc, flags) + def compare_hypervisor_cpu(self, xmlDesc, flags=0): + """Compares the given CPU description with the CPU provided by + the host hypervisor. This is different from the older method, + compare_cpu(), which compares a given CPU definition with the + host CPU without considering the abilities of the host + hypervisor. Except @xmlDesc, rest of all the parameters to + compareHypervisorCPU API are optional (libvirt will choose + sensible defaults). + """ + emulator = None + arch = None + machine = None + virttype = None + return self.get_connection().compareHypervisorCPU( + emulator, arch, machine, virttype, xmlDesc, flags) + def is_cpu_control_policy_capable(self): """Returns whether kernel configuration CGROUP_SCHED is enabled CONFIG_CGROUP_SCHED may be disabled in some kernel configs to improve scheduler latency. """ + return self._has_cgroupsv1_cpu_controller() or \ + self._has_cgroupsv2_cpu_controller() + + def _has_cgroupsv1_cpu_controller(self): + LOG.debug(f"Searching host: '{self.get_hostname()}' " + "for CPU controller through CGroups V1...") try: with open("/proc/self/mounts", "r") as fd: for line in fd.readlines(): # mount options and split options bits = line.split()[3].split(",") if "cpu" in bits: + LOG.debug("CPU controller found on host.") + return True + LOG.debug("CPU controller missing on host.") + return False + except IOError as ex: + LOG.debug(f"Search failed due to: '{ex}'. " + "Maybe the host is not running under CGroups V1. " + "Deemed host to be missing controller by this approach.") + return False + + def _has_cgroupsv2_cpu_controller(self): + LOG.debug(f"Searching host: '{self.get_hostname()}' " + "for CPU controller through CGroups V2...") + try: + with open("/sys/fs/cgroup/cgroup.controllers", "r") as fd: + for line in fd.readlines(): + bits = line.split() + if "cpu" in bits: + LOG.debug("CPU controller found on host.") return True + LOG.debug("CPU controller missing on host.") return False - except IOError: + except IOError as ex: + LOG.debug(f"Search failed due to: '{ex}'. " + "Maybe the host is not running under CGroups V2. " + "Deemed host to be missing controller by this approach.") return False def get_canonical_machine_type(self, arch, machine) -> str: |