virt facts: allow guest/host to have >1 virt tech (#70832)

Change:
- Allow systems to declare multiple virt techs. For example if a system
  is both a docker container, but virtualized on KVM, show both. If a
  system is set up to run virtualbox and KVM VMs, show both.

- This is done by introducing new facts keys:
  - virtualization_tech_guest
  - virtualization_tech_host

- Backwards compatibility is preserved by keeping track of the previous
  return-points and refusing to update those keys after we would have
  returned, but now returning them at the end, so that the new keys can
  accumulate their data.

Test Plan:
- Local
- CI

Tickets:
- Refs #66304
- Refs #17151
- Refs #17058
- Probably others

Signed-off-by: Rick Elrod <rick@elrod.me>
This commit is contained in:
Rick Elrod 2020-08-06 09:45:37 -05:00 committed by GitHub
parent fc83055425
commit 4e55b93613
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 357 additions and 126 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- New virtualization facts, ``virtualization_tech_guest`` and ``virtualization_tech_host`` now allow for conveying when a system is a host or guest of multiple virtualization technologies.

View file

@ -131,7 +131,8 @@ No notable changes
Noteworthy module changes Noteworthy module changes
------------------------- -------------------------
* facts - ``ansible_virtualization_type`` now tries to report a more accurate result than ``xen`` when virtualized and not running on Xen. * facts - On NetBSD, ``ansible_virtualization_type`` now tries to report a more accurate result than ``xen`` when virtualized and not running on Xen.
* facts - Virtualization facts now include ``virtualization_tech_guest`` and ``virtualization_tech_host`` keys. These are lists of virtualization technologies that a guest is a part of, or that a host provides, respectively. As an example, a host may be set up to provide both KVM and VirtualBox, and these will be included in ``virtualization_tech_host``, and a podman container running on a VM powered by KVM will have a ``virtualization_tech_guest`` of ``["kvm", "podman", "container"]``.
Plugins Plugins

View file

@ -46,16 +46,24 @@ class Virtual:
return virtual_facts return virtual_facts
def get_virtual_facts(self): def get_virtual_facts(self):
virtual_facts = {'virtualization_type': '', virtual_facts = {
'virtualization_role': ''} 'virtualization_type': '',
'virtualization_role': '',
'virtualization_tech_guest': set(),
'virtualization_tech_host': set(),
}
return virtual_facts return virtual_facts
class VirtualCollector(BaseFactCollector): class VirtualCollector(BaseFactCollector):
name = 'virtual' name = 'virtual'
_fact_class = Virtual _fact_class = Virtual
_fact_ids = set(['virtualization_type', _fact_ids = set([
'virtualization_role']) 'virtualization_type',
'virtualization_role',
'virtualization_tech_guest',
'virtualization_tech_host',
])
def collect(self, module=None, collected_facts=None): def collect(self, module=None, collected_facts=None):
collected_facts = collected_facts or {} collected_facts = collected_facts or {}

View file

@ -32,23 +32,45 @@ class FreeBSDVirtual(Virtual, VirtualSysctlDetectionMixin):
def get_virtual_facts(self): def get_virtual_facts(self):
virtual_facts = {} virtual_facts = {}
host_tech = set()
guest_tech = set()
# Set empty values as default # Set empty values as default
virtual_facts['virtualization_type'] = '' virtual_facts['virtualization_type'] = ''
virtual_facts['virtualization_role'] = '' virtual_facts['virtualization_role'] = ''
if os.path.exists('/dev/xen/xenstore'): if os.path.exists('/dev/xen/xenstore'):
guest_tech.add('xen')
virtual_facts['virtualization_type'] = 'xen' virtual_facts['virtualization_type'] = 'xen'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
if virtual_facts['virtualization_type'] == '': kern_vm_guest = self.detect_virt_product('kern.vm_guest')
virtual_product_facts = self.detect_virt_product('kern.vm_guest') or self.detect_virt_product( guest_tech.update(kern_vm_guest['virtualization_tech_guest'])
'hw.hv_vendor') or self.detect_virt_product('security.jail.jailed') host_tech.update(kern_vm_guest['virtualization_tech_host'])
virtual_facts.update(virtual_product_facts)
hw_hv_vendor = self.detect_virt_product('hw.hv_vendor')
guest_tech.update(hw_hv_vendor['virtualization_tech_guest'])
host_tech.update(hw_hv_vendor['virtualization_tech_host'])
sec_jail_jailed = self.detect_virt_product('security.jail.jailed')
guest_tech.update(sec_jail_jailed['virtualization_tech_guest'])
host_tech.update(sec_jail_jailed['virtualization_tech_host'])
if virtual_facts['virtualization_type'] == '': if virtual_facts['virtualization_type'] == '':
sysctl = kern_vm_guest or hw_hv_vendor or sec_jail_jailed
# We call update here, then re-set virtualization_tech_host/guest
# later.
virtual_facts.update(sysctl)
virtual_vendor_facts = self.detect_virt_vendor('hw.model') virtual_vendor_facts = self.detect_virt_vendor('hw.model')
guest_tech.update(virtual_vendor_facts['virtualization_tech_guest'])
host_tech.update(virtual_vendor_facts['virtualization_tech_host'])
if virtual_facts['virtualization_type'] == '':
virtual_facts.update(virtual_vendor_facts) virtual_facts.update(virtual_vendor_facts)
virtual_facts['virtualization_tech_guest'] = guest_tech
virtual_facts['virtualization_tech_host'] = host_tech
return virtual_facts return virtual_facts

View file

@ -32,28 +32,38 @@ class HPUXVirtual(Virtual):
def get_virtual_facts(self): def get_virtual_facts(self):
virtual_facts = {} virtual_facts = {}
host_tech = set()
guest_tech = set()
if os.path.exists('/usr/sbin/vecheck'): if os.path.exists('/usr/sbin/vecheck'):
rc, out, err = self.module.run_command("/usr/sbin/vecheck") rc, out, err = self.module.run_command("/usr/sbin/vecheck")
if rc == 0: if rc == 0:
guest_tech.add('HP vPar')
virtual_facts['virtualization_type'] = 'guest' virtual_facts['virtualization_type'] = 'guest'
virtual_facts['virtualization_role'] = 'HP vPar' virtual_facts['virtualization_role'] = 'HP vPar'
if os.path.exists('/opt/hpvm/bin/hpvminfo'): if os.path.exists('/opt/hpvm/bin/hpvminfo'):
rc, out, err = self.module.run_command("/opt/hpvm/bin/hpvminfo") rc, out, err = self.module.run_command("/opt/hpvm/bin/hpvminfo")
if rc == 0 and re.match('.*Running.*HPVM vPar.*', out): if rc == 0 and re.match('.*Running.*HPVM vPar.*', out):
guest_tech.add('HPVM vPar')
virtual_facts['virtualization_type'] = 'guest' virtual_facts['virtualization_type'] = 'guest'
virtual_facts['virtualization_role'] = 'HPVM vPar' virtual_facts['virtualization_role'] = 'HPVM vPar'
elif rc == 0 and re.match('.*Running.*HPVM guest.*', out): elif rc == 0 and re.match('.*Running.*HPVM guest.*', out):
guest_tech.add('HPVM IVM')
virtual_facts['virtualization_type'] = 'guest' virtual_facts['virtualization_type'] = 'guest'
virtual_facts['virtualization_role'] = 'HPVM IVM' virtual_facts['virtualization_role'] = 'HPVM IVM'
elif rc == 0 and re.match('.*Running.*HPVM host.*', out): elif rc == 0 and re.match('.*Running.*HPVM host.*', out):
guest_tech.add('HPVM')
virtual_facts['virtualization_type'] = 'host' virtual_facts['virtualization_type'] = 'host'
virtual_facts['virtualization_role'] = 'HPVM' virtual_facts['virtualization_role'] = 'HPVM'
if os.path.exists('/usr/sbin/parstatus'): if os.path.exists('/usr/sbin/parstatus'):
rc, out, err = self.module.run_command("/usr/sbin/parstatus") rc, out, err = self.module.run_command("/usr/sbin/parstatus")
if rc == 0: if rc == 0:
guest_tech.add('HP nPar')
virtual_facts['virtualization_type'] = 'guest' virtual_facts['virtualization_type'] = 'guest'
virtual_facts['virtualization_role'] = 'HP nPar' virtual_facts['virtualization_role'] = 'HP nPar'
virtual_facts['virtualization_tech_guest'] = guest_tech
virtual_facts['virtualization_tech_host'] = host_tech
return virtual_facts return virtual_facts

View file

@ -35,140 +35,217 @@ class LinuxVirtual(Virtual):
# For more information, check: http://people.redhat.com/~rjones/virt-what/ # For more information, check: http://people.redhat.com/~rjones/virt-what/
def get_virtual_facts(self): def get_virtual_facts(self):
virtual_facts = {} virtual_facts = {}
# We want to maintain compatibility with the old "virtualization_type"
# and "virtualization_role" entries, so we need to track if we found
# them. We won't return them until the end, but if we found them early,
# we should avoid updating them again.
found_virt = False
# But as we go along, we also want to track virt tech the new way.
host_tech = set()
guest_tech = set()
# lxc/docker # lxc/docker
if os.path.exists('/proc/1/cgroup'): if os.path.exists('/proc/1/cgroup'):
for line in get_file_lines('/proc/1/cgroup'): for line in get_file_lines('/proc/1/cgroup'):
if re.search(r'/docker(/|-[0-9a-f]+\.scope)', line): if re.search(r'/docker(/|-[0-9a-f]+\.scope)', line):
guest_tech.add('docker')
if not found_virt:
virtual_facts['virtualization_type'] = 'docker' virtual_facts['virtualization_type'] = 'docker'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
if re.search('/lxc/', line) or re.search('/machine.slice/machine-lxc', line): if re.search('/lxc/', line) or re.search('/machine.slice/machine-lxc', line):
guest_tech.add('lxc')
if not found_virt:
virtual_facts['virtualization_type'] = 'lxc' virtual_facts['virtualization_type'] = 'lxc'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
# lxc does not always appear in cgroups anymore but sets 'container=lxc' environment var, requires root privs # lxc does not always appear in cgroups anymore but sets 'container=lxc' environment var, requires root privs
if os.path.exists('/proc/1/environ'): if os.path.exists('/proc/1/environ'):
for line in get_file_lines('/proc/1/environ', line_sep='\x00'): for line in get_file_lines('/proc/1/environ', line_sep='\x00'):
if re.search('container=lxc', line): if re.search('container=lxc', line):
guest_tech.add('lxc')
if not found_virt:
virtual_facts['virtualization_type'] = 'lxc' virtual_facts['virtualization_type'] = 'lxc'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
if re.search('container=podman', line): if re.search('container=podman', line):
guest_tech.add('podman')
if not found_virt:
virtual_facts['virtualization_type'] = 'podman' virtual_facts['virtualization_type'] = 'podman'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
if re.search('^container=.', line): if re.search('^container=.', line):
guest_tech.add('container')
if not found_virt:
virtual_facts['virtualization_type'] = 'container' virtual_facts['virtualization_type'] = 'container'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
if os.path.exists('/proc/vz') and not os.path.exists('/proc/lve'): if os.path.exists('/proc/vz') and not os.path.exists('/proc/lve'):
virtual_facts['virtualization_type'] = 'openvz' virtual_facts['virtualization_type'] = 'openvz'
if os.path.exists('/proc/bc'): if os.path.exists('/proc/bc'):
host_tech.add('openvz')
if not found_virt:
virtual_facts['virtualization_role'] = 'host' virtual_facts['virtualization_role'] = 'host'
else: else:
guest_tech.add('openvz')
if not found_virt:
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
systemd_container = get_file_content('/run/systemd/container') systemd_container = get_file_content('/run/systemd/container')
if systemd_container: if systemd_container:
guest_tech.add(systemd_container)
if not found_virt:
virtual_facts['virtualization_type'] = systemd_container virtual_facts['virtualization_type'] = systemd_container
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
if os.path.exists("/proc/xen"): if os.path.exists("/proc/xen"):
virtual_facts['virtualization_type'] = 'xen' is_xen_host = False
virtual_facts['virtualization_role'] = 'guest'
try: try:
for line in get_file_lines('/proc/xen/capabilities'): for line in get_file_lines('/proc/xen/capabilities'):
if "control_d" in line: if "control_d" in line:
virtual_facts['virtualization_role'] = 'host' is_xen_host = True
except IOError: except IOError:
pass pass
return virtual_facts
if is_xen_host:
host_tech.add('xen')
if not found_virt:
virtual_facts['virtualization_type'] = 'xen'
virtual_facts['virtualization_role'] = 'host'
else:
if not found_virt:
virtual_facts['virtualization_type'] = 'xen'
virtual_facts['virtualization_role'] = 'guest'
found_virt = True
# assume guest for this block # assume guest for this block
if not found_virt:
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
product_name = get_file_content('/sys/devices/virtual/dmi/id/product_name') product_name = get_file_content('/sys/devices/virtual/dmi/id/product_name')
if product_name in ('KVM', 'KVM Server', 'Bochs', 'AHV'): if product_name in ('KVM', 'KVM Server', 'Bochs', 'AHV'):
guest_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
return virtual_facts found_virt = True
if product_name == 'RHEV Hypervisor': if product_name == 'RHEV Hypervisor':
guest_tech.add('RHEV')
if not found_virt:
virtual_facts['virtualization_type'] = 'RHEV' virtual_facts['virtualization_type'] = 'RHEV'
return virtual_facts found_virt = True
if product_name in ('VMware Virtual Platform', 'VMware7,1'): if product_name in ('VMware Virtual Platform', 'VMware7,1'):
guest_tech.add('VMware')
if not found_virt:
virtual_facts['virtualization_type'] = 'VMware' virtual_facts['virtualization_type'] = 'VMware'
return virtual_facts found_virt = True
if product_name in ('OpenStack Compute', 'OpenStack Nova'): if product_name in ('OpenStack Compute', 'OpenStack Nova'):
guest_tech.add('openstack')
if not found_virt:
virtual_facts['virtualization_type'] = 'openstack' virtual_facts['virtualization_type'] = 'openstack'
return virtual_facts found_virt = True
bios_vendor = get_file_content('/sys/devices/virtual/dmi/id/bios_vendor') bios_vendor = get_file_content('/sys/devices/virtual/dmi/id/bios_vendor')
if bios_vendor == 'Xen': if bios_vendor == 'Xen':
guest_tech.add('xen')
if not found_virt:
virtual_facts['virtualization_type'] = 'xen' virtual_facts['virtualization_type'] = 'xen'
return virtual_facts found_virt = True
if bios_vendor == 'innotek GmbH': if bios_vendor == 'innotek GmbH':
guest_tech.add('virtualbox')
if not found_virt:
virtual_facts['virtualization_type'] = 'virtualbox' virtual_facts['virtualization_type'] = 'virtualbox'
return virtual_facts found_virt = True
if bios_vendor in ('Amazon EC2', 'DigitalOcean', 'Hetzner'): if bios_vendor in ('Amazon EC2', 'DigitalOcean', 'Hetzner'):
guest_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
return virtual_facts found_virt = True
sys_vendor = get_file_content('/sys/devices/virtual/dmi/id/sys_vendor') sys_vendor = get_file_content('/sys/devices/virtual/dmi/id/sys_vendor')
KVM_SYS_VENDORS = ('QEMU', 'oVirt', 'Amazon EC2', 'DigitalOcean', 'Google', 'Scaleway', 'Nutanix') KVM_SYS_VENDORS = ('QEMU', 'oVirt', 'Amazon EC2', 'DigitalOcean', 'Google', 'Scaleway', 'Nutanix')
if sys_vendor in KVM_SYS_VENDORS: if sys_vendor in KVM_SYS_VENDORS:
guest_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
return virtual_facts found_virt = True
# FIXME: This does also match hyperv # FIXME: This does also match hyperv
if sys_vendor == 'Microsoft Corporation': if sys_vendor == 'Microsoft Corporation':
guest_tech.add('VirtualPC')
if not found_virt:
virtual_facts['virtualization_type'] = 'VirtualPC' virtual_facts['virtualization_type'] = 'VirtualPC'
return virtual_facts found_virt = True
if sys_vendor == 'Parallels Software International Inc.': if sys_vendor == 'Parallels Software International Inc.':
guest_tech.add('parallels')
if not found_virt:
virtual_facts['virtualization_type'] = 'parallels' virtual_facts['virtualization_type'] = 'parallels'
return virtual_facts found_virt = True
if sys_vendor == 'OpenStack Foundation': if sys_vendor == 'OpenStack Foundation':
guest_tech.add('openstack')
if not found_virt:
virtual_facts['virtualization_type'] = 'openstack' virtual_facts['virtualization_type'] = 'openstack'
return virtual_facts found_virt = True
# unassume guest # unassume guest
if not found_virt:
del virtual_facts['virtualization_role'] del virtual_facts['virtualization_role']
if os.path.exists('/proc/self/status'): if os.path.exists('/proc/self/status'):
for line in get_file_lines('/proc/self/status'): for line in get_file_lines('/proc/self/status'):
if re.match(r'^VxID:\s+\d+', line): if re.match(r'^VxID:\s+\d+', line):
if not found_virt:
virtual_facts['virtualization_type'] = 'linux_vserver' virtual_facts['virtualization_type'] = 'linux_vserver'
if re.match(r'^VxID:\s+0', line): if re.match(r'^VxID:\s+0', line):
host_tech.add('linux_vserver')
if not found_virt:
virtual_facts['virtualization_role'] = 'host' virtual_facts['virtualization_role'] = 'host'
else: else:
guest_tech.add('linux_vserver')
if not found_virt:
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
if os.path.exists('/proc/cpuinfo'): if os.path.exists('/proc/cpuinfo'):
for line in get_file_lines('/proc/cpuinfo'): for line in get_file_lines('/proc/cpuinfo'):
if re.match('^model name.*QEMU Virtual CPU', line): if re.match('^model name.*QEMU Virtual CPU', line):
guest_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
elif re.match('^vendor_id.*User Mode Linux', line): elif re.match('^vendor_id.*User Mode Linux', line):
guest_tech.add('uml')
if not found_virt:
virtual_facts['virtualization_type'] = 'uml' virtual_facts['virtualization_type'] = 'uml'
elif re.match('^model name.*UML', line): elif re.match('^model name.*UML', line):
guest_tech.add('uml')
if not found_virt:
virtual_facts['virtualization_type'] = 'uml' virtual_facts['virtualization_type'] = 'uml'
elif re.match('^machine.*CHRP IBM pSeries .emulated by qemu.', line): elif re.match('^machine.*CHRP IBM pSeries .emulated by qemu.', line):
guest_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
elif re.match('^vendor_id.*PowerVM Lx86', line): elif re.match('^vendor_id.*PowerVM Lx86', line):
guest_tech.add('powervm_lx86')
if not found_virt:
virtual_facts['virtualization_type'] = 'powervm_lx86' virtual_facts['virtualization_type'] = 'powervm_lx86'
elif re.match('^vendor_id.*IBM/S390', line): elif re.match('^vendor_id.*IBM/S390', line):
guest_tech.add('PR/SM')
if not found_virt:
virtual_facts['virtualization_type'] = 'PR/SM' virtual_facts['virtualization_type'] = 'PR/SM'
lscpu = self.module.get_bin_path('lscpu') lscpu = self.module.get_bin_path('lscpu')
if lscpu: if lscpu:
@ -178,16 +255,24 @@ class LinuxVirtual(Virtual):
data = line.split(":", 1) data = line.split(":", 1)
key = data[0].strip() key = data[0].strip()
if key == 'Hypervisor': if key == 'Hypervisor':
virtual_facts['virtualization_type'] = data[1].strip() tech = data[1].strip()
guest_tech.add(tech)
if not found_virt:
virtual_facts['virtualization_type'] = tech
else: else:
guest_tech.add('ibm_systemz')
if not found_virt:
virtual_facts['virtualization_type'] = 'ibm_systemz' virtual_facts['virtualization_type'] = 'ibm_systemz'
else: else:
continue continue
if virtual_facts['virtualization_type'] == 'PR/SM': if virtual_facts['virtualization_type'] == 'PR/SM':
if not found_virt:
virtual_facts['virtualization_role'] = 'LPAR' virtual_facts['virtualization_role'] = 'LPAR'
else: else:
if not found_virt:
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts if not found_virt:
found_virt = True
# Beware that we can have both kvm and virtualbox running on a single system # Beware that we can have both kvm and virtualbox running on a single system
if os.path.exists("/proc/modules") and os.access('/proc/modules', os.R_OK): if os.path.exists("/proc/modules") and os.access('/proc/modules', os.R_OK):
@ -197,6 +282,8 @@ class LinuxVirtual(Virtual):
modules.append(data[0]) modules.append(data[0])
if 'kvm' in modules: if 'kvm' in modules:
host_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
virtual_facts['virtualization_role'] = 'host' virtual_facts['virtualization_role'] = 'host'
@ -206,23 +293,32 @@ class LinuxVirtual(Virtual):
try: try:
with open(f) as virt_fh: with open(f) as virt_fh:
comm_content = virt_fh.read().rstrip() comm_content = virt_fh.read().rstrip()
if comm_content in ('vdsm', 'vdsmd'): if comm_content in ('vdsm', 'vdsmd'):
# We add both kvm and RHEV to host_tech in this case.
# It's accurate. RHEV uses KVM.
host_tech.add('RHEV')
if not found_virt:
virtual_facts['virtualization_type'] = 'RHEV' virtual_facts['virtualization_type'] = 'RHEV'
break break
except Exception: except Exception:
pass pass
return virtual_facts found_virt = True
if 'vboxdrv' in modules: if 'vboxdrv' in modules:
host_tech.add('virtualbox')
if not found_virt:
virtual_facts['virtualization_type'] = 'virtualbox' virtual_facts['virtualization_type'] = 'virtualbox'
virtual_facts['virtualization_role'] = 'host' virtual_facts['virtualization_role'] = 'host'
return virtual_facts found_virt = True
if 'virtio' in modules: if 'virtio' in modules:
host_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
# In older Linux Kernel versions, /sys filesystem is not available # In older Linux Kernel versions, /sys filesystem is not available
# dmidecode is the safest option to parse virtualization related values # dmidecode is the safest option to parse virtualization related values
@ -234,20 +330,28 @@ class LinuxVirtual(Virtual):
# Strip out commented lines (specific dmidecode output) # Strip out commented lines (specific dmidecode output)
vendor_name = ''.join([line.strip() for line in out.splitlines() if not line.startswith('#')]) vendor_name = ''.join([line.strip() for line in out.splitlines() if not line.startswith('#')])
if vendor_name.startswith('VMware'): if vendor_name.startswith('VMware'):
guest_tech.add('VMware')
if not found_virt:
virtual_facts['virtualization_type'] = 'VMware' virtual_facts['virtualization_type'] = 'VMware'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
return virtual_facts found_virt = True
if os.path.exists('/dev/kvm'): if os.path.exists('/dev/kvm'):
host_tech.add('kvm')
if not found_virt:
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
virtual_facts['virtualization_role'] = 'host' virtual_facts['virtualization_role'] = 'host'
return virtual_facts found_virt = True
# If none of the above matches, return 'NA' for virtualization_type # If none of the above matches, return 'NA' for virtualization_type
# and virtualization_role. This allows for proper grouping. # and virtualization_role. This allows for proper grouping.
if not found_virt:
virtual_facts['virtualization_type'] = 'NA' virtual_facts['virtualization_type'] = 'NA'
virtual_facts['virtualization_role'] = 'NA' virtual_facts['virtualization_role'] = 'NA'
found_virt = True
virtual_facts['virtualization_tech_guest'] = guest_tech
virtual_facts['virtualization_tech_host'] = host_tech
return virtual_facts return virtual_facts

View file

@ -27,29 +27,44 @@ class NetBSDVirtual(Virtual, VirtualSysctlDetectionMixin):
def get_virtual_facts(self): def get_virtual_facts(self):
virtual_facts = {} virtual_facts = {}
host_tech = set()
guest_tech = set()
# Set empty values as default # Set empty values as default
virtual_facts['virtualization_type'] = '' virtual_facts['virtualization_type'] = ''
virtual_facts['virtualization_role'] = '' virtual_facts['virtualization_role'] = ''
virtual_product_facts = self.detect_virt_product('machdep.dmi.system-product') virtual_product_facts = self.detect_virt_product('machdep.dmi.system-product')
guest_tech.update(virtual_product_facts['virtualization_tech_guest'])
host_tech.update(virtual_product_facts['virtualization_tech_host'])
virtual_facts.update(virtual_product_facts) virtual_facts.update(virtual_product_facts)
if virtual_facts['virtualization_type'] == '':
virtual_vendor_facts = self.detect_virt_vendor('machdep.dmi.system-vendor') virtual_vendor_facts = self.detect_virt_vendor('machdep.dmi.system-vendor')
guest_tech.update(virtual_vendor_facts['virtualization_tech_guest'])
host_tech.update(virtual_vendor_facts['virtualization_tech_host'])
if virtual_facts['virtualization_type'] == '':
virtual_facts.update(virtual_vendor_facts) virtual_facts.update(virtual_vendor_facts)
# The above logic is tried first for backwards compatibility. If # The above logic is tried first for backwards compatibility. If
# something above matches, use it. Otherwise if the result is still # something above matches, use it. Otherwise if the result is still
# empty, try machdep.hypervisor. # empty, try machdep.hypervisor.
if virtual_facts['virtualization_type'] == '':
virtual_vendor_facts = self.detect_virt_vendor('machdep.hypervisor') virtual_vendor_facts = self.detect_virt_vendor('machdep.hypervisor')
guest_tech.update(virtual_vendor_facts['virtualization_tech_guest'])
host_tech.update(virtual_vendor_facts['virtualization_tech_host'])
if virtual_facts['virtualization_type'] == '':
virtual_facts.update(virtual_vendor_facts) virtual_facts.update(virtual_vendor_facts)
if (virtual_facts['virtualization_type'] == '' and if os.path.exists('/dev/xencons'):
os.path.exists('/dev/xencons')): guest_tech.add('xen')
if virtual_facts['virtualization_type'] == '':
virtual_facts['virtualization_type'] = 'xen' virtual_facts['virtualization_type'] = 'xen'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
virtual_facts['virtualization_tech_guest'] = guest_tech
virtual_facts['virtualization_tech_host'] = host_tech
return virtual_facts return virtual_facts

View file

@ -35,16 +35,23 @@ class OpenBSDVirtual(Virtual, VirtualSysctlDetectionMixin):
def get_virtual_facts(self): def get_virtual_facts(self):
virtual_facts = {} virtual_facts = {}
host_tech = set()
guest_tech = set()
# Set empty values as default # Set empty values as default
virtual_facts['virtualization_type'] = '' virtual_facts['virtualization_type'] = ''
virtual_facts['virtualization_role'] = '' virtual_facts['virtualization_role'] = ''
virtual_product_facts = self.detect_virt_product('hw.product') virtual_product_facts = self.detect_virt_product('hw.product')
guest_tech.update(virtual_product_facts['virtualization_tech_guest'])
host_tech.update(virtual_product_facts['virtualization_tech_host'])
virtual_facts.update(virtual_product_facts) virtual_facts.update(virtual_product_facts)
if virtual_facts['virtualization_type'] == '':
virtual_vendor_facts = self.detect_virt_vendor('hw.vendor') virtual_vendor_facts = self.detect_virt_vendor('hw.vendor')
guest_tech.update(virtual_vendor_facts['virtualization_tech_guest'])
host_tech.update(virtual_vendor_facts['virtualization_tech_host'])
if virtual_facts['virtualization_type'] == '':
virtual_facts.update(virtual_vendor_facts) virtual_facts.update(virtual_vendor_facts)
# Check the dmesg if vmm(4) attached, indicating the host is # Check the dmesg if vmm(4) attached, indicating the host is
@ -53,9 +60,12 @@ class OpenBSDVirtual(Virtual, VirtualSysctlDetectionMixin):
for line in dmesg_boot.splitlines(): for line in dmesg_boot.splitlines():
match = re.match('^vmm0 at mainbus0: (SVM/RVI|VMX/EPT)$', line) match = re.match('^vmm0 at mainbus0: (SVM/RVI|VMX/EPT)$', line)
if match: if match:
host_tech.add('vmm')
virtual_facts['virtualization_type'] = 'vmm' virtual_facts['virtualization_type'] = 'vmm'
virtual_facts['virtualization_role'] = 'host' virtual_facts['virtualization_role'] = 'host'
virtual_facts['virtualization_tech_guest'] = guest_tech
virtual_facts['virtualization_tech_host'] = host_tech
return virtual_facts return virtual_facts

View file

@ -32,19 +32,27 @@ class SunOSVirtual(Virtual):
def get_virtual_facts(self): def get_virtual_facts(self):
virtual_facts = {} virtual_facts = {}
# Check if it's a zone host_tech = set()
guest_tech = set()
# Check if it's a zone
zonename = self.module.get_bin_path('zonename') zonename = self.module.get_bin_path('zonename')
if zonename: if zonename:
rc, out, err = self.module.run_command(zonename) rc, out, err = self.module.run_command(zonename)
if rc == 0 and out.rstrip() != "global": if rc == 0:
if out.rstrip() == "global":
host_tech.add('zone')
else:
guest_tech.add('zone')
virtual_facts['container'] = 'zone' virtual_facts['container'] = 'zone'
# Check if it's a branded zone (i.e. Solaris 8/9 zone) # Check if it's a branded zone (i.e. Solaris 8/9 zone)
if os.path.isdir('/.SUNWnative'): if os.path.isdir('/.SUNWnative'):
guest_tech.add('zone')
virtual_facts['container'] = 'zone' virtual_facts['container'] = 'zone'
# If it's a zone check if we can detect if our global zone is itself virtualized. # If it's a zone check if we can detect if our global zone is itself virtualized.
# Relies on the "guest tools" (e.g. vmware tools) to be installed # Relies on the "guest tools" (e.g. vmware tools) to be installed
if 'container' in virtual_facts and virtual_facts['container'] == 'zone': if 'container' in virtual_facts and virtual_facts['container'] == 'zone':
modinfo = self.module.get_bin_path('modinfo') modinfo = self.module.get_bin_path('modinfo')
if modinfo: if modinfo:
@ -52,13 +60,16 @@ class SunOSVirtual(Virtual):
if rc == 0: if rc == 0:
for line in out.splitlines(): for line in out.splitlines():
if 'VMware' in line: if 'VMware' in line:
guest_tech.add('vmware')
virtual_facts['virtualization_type'] = 'vmware' virtual_facts['virtualization_type'] = 'vmware'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
if 'VirtualBox' in line: if 'VirtualBox' in line:
guest_tech.add('virtualbox')
virtual_facts['virtualization_type'] = 'virtualbox' virtual_facts['virtualization_type'] = 'virtualbox'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
if os.path.exists('/proc/vz'): if os.path.exists('/proc/vz'):
guest_tech.add('virtuozzo')
virtual_facts['virtualization_type'] = 'virtuozzo' virtual_facts['virtualization_type'] = 'virtuozzo'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
@ -77,6 +88,7 @@ class SunOSVirtual(Virtual):
for line in out.splitlines(): for line in out.splitlines():
fields = line.split('|') fields = line.split('|')
if fields[0] == 'DOMAINROLE' and fields[1] == 'impl=LDoms': if fields[0] == 'DOMAINROLE' and fields[1] == 'impl=LDoms':
guest_tech.add('ldom')
virtual_facts['virtualization_type'] = 'ldom' virtual_facts['virtualization_type'] = 'ldom'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
hostfeatures = [] hostfeatures = []
@ -97,21 +109,28 @@ class SunOSVirtual(Virtual):
if rc == 0: if rc == 0:
for line in out.splitlines(): for line in out.splitlines():
if 'VMware' in line: if 'VMware' in line:
guest_tech.add('vmware')
virtual_facts['virtualization_type'] = 'vmware' virtual_facts['virtualization_type'] = 'vmware'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
elif 'Parallels' in line: elif 'Parallels' in line:
guest_tech.add('parallels')
virtual_facts['virtualization_type'] = 'parallels' virtual_facts['virtualization_type'] = 'parallels'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
elif 'VirtualBox' in line: elif 'VirtualBox' in line:
guest_tech.add('virtualbox')
virtual_facts['virtualization_type'] = 'virtualbox' virtual_facts['virtualization_type'] = 'virtualbox'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
elif 'HVM domU' in line: elif 'HVM domU' in line:
guest_tech.add('xen')
virtual_facts['virtualization_type'] = 'xen' virtual_facts['virtualization_type'] = 'xen'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
elif 'KVM' in line: elif 'KVM' in line:
guest_tech.add('kvm')
virtual_facts['virtualization_type'] = 'kvm' virtual_facts['virtualization_type'] = 'kvm'
virtual_facts['virtualization_role'] = 'guest' virtual_facts['virtualization_role'] = 'guest'
virtual_facts['virtualization_tech_guest'] = guest_tech
virtual_facts['virtualization_tech_host'] = host_tech
return virtual_facts return virtual_facts

View file

@ -25,48 +25,88 @@ class VirtualSysctlDetectionMixin(object):
def detect_virt_product(self, key): def detect_virt_product(self, key):
virtual_product_facts = {} virtual_product_facts = {}
host_tech = set()
guest_tech = set()
# We do similar to what we do in linux.py -- We want to allow multiple
# virt techs to show up, but maintain compatibility, so we have to track
# when we would have stopped, even though now we go through everything.
found_virt = False
self.detect_sysctl() self.detect_sysctl()
if self.sysctl_path: if self.sysctl_path:
rc, out, err = self.module.run_command("%s -n %s" % (self.sysctl_path, key)) rc, out, err = self.module.run_command("%s -n %s" % (self.sysctl_path, key))
if rc == 0: if rc == 0:
if re.match('(KVM|kvm|Bochs|SmartDC).*', out): if re.match('(KVM|kvm|Bochs|SmartDC).*', out):
guest_tech.add('kvm')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'kvm' virtual_product_facts['virtualization_type'] = 'kvm'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
elif re.match('.*VMware.*', out): found_virt = True
if re.match('.*VMware.*', out):
guest_tech.add('VMware')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'VMware' virtual_product_facts['virtualization_type'] = 'VMware'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
elif out.rstrip() == 'VirtualBox': found_virt = True
if out.rstrip() == 'VirtualBox':
guest_tech.add('virtualbox')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'virtualbox' virtual_product_facts['virtualization_type'] = 'virtualbox'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
elif re.match('(HVM domU|XenPVH|XenPV|XenPVHVM).*', out): found_virt = True
if re.match('(HVM domU|XenPVH|XenPV|XenPVHVM).*', out):
guest_tech.add('xen')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'xen' virtual_product_facts['virtualization_type'] = 'xen'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
elif out.rstrip() == 'Hyper-V': found_virt = True
if out.rstrip() == 'Hyper-V':
guest_tech.add('Hyper-V')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'Hyper-V' virtual_product_facts['virtualization_type'] = 'Hyper-V'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
elif out.rstrip() == 'Parallels': found_virt = True
if out.rstrip() == 'Parallels':
guest_tech.add('parallels')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'parallels' virtual_product_facts['virtualization_type'] = 'parallels'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
elif out.rstrip() == 'RHEV Hypervisor': found_virt = True
if out.rstrip() == 'RHEV Hypervisor':
guest_tech.add('RHEV')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'RHEV' virtual_product_facts['virtualization_type'] = 'RHEV'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
elif (key == 'security.jail.jailed') and (out.rstrip() == '1'): found_virt = True
if (key == 'security.jail.jailed') and (out.rstrip() == '1'):
guest_tech.add('jails')
if not found_virt:
virtual_product_facts['virtualization_type'] = 'jails' virtual_product_facts['virtualization_type'] = 'jails'
virtual_product_facts['virtualization_role'] = 'guest' virtual_product_facts['virtualization_role'] = 'guest'
found_virt = True
virtual_product_facts['virtualization_tech_guest'] = guest_tech
virtual_product_facts['virtualization_tech_host'] = host_tech
return virtual_product_facts return virtual_product_facts
def detect_virt_vendor(self, key): def detect_virt_vendor(self, key):
virtual_vendor_facts = {} virtual_vendor_facts = {}
host_tech = set()
guest_tech = set()
self.detect_sysctl() self.detect_sysctl()
if self.sysctl_path: if self.sysctl_path:
rc, out, err = self.module.run_command("%s -n %s" % (self.sysctl_path, key)) rc, out, err = self.module.run_command("%s -n %s" % (self.sysctl_path, key))
if rc == 0: if rc == 0:
if out.rstrip() == 'QEMU': if out.rstrip() == 'QEMU':
guest_tech.add('kvm')
virtual_vendor_facts['virtualization_type'] = 'kvm' virtual_vendor_facts['virtualization_type'] = 'kvm'
virtual_vendor_facts['virtualization_role'] = 'guest' virtual_vendor_facts['virtualization_role'] = 'guest'
if out.rstrip() == 'OpenBSD': if out.rstrip() == 'OpenBSD':
guest_tech.add('vmm')
virtual_vendor_facts['virtualization_type'] = 'vmm' virtual_vendor_facts['virtualization_type'] = 'vmm'
virtual_vendor_facts['virtualization_role'] = 'guest' virtual_vendor_facts['virtualization_role'] = 'guest'
virtual_vendor_facts['virtualization_tech_guest'] = guest_tech
virtual_vendor_facts['virtualization_tech_host'] = host_tech
return virtual_vendor_facts return virtual_vendor_facts