Package: ansible
Version: 2.5.0+dfsg-1
Severity: important
Tags: patch upstream

Dear Maintainer,

*** Reporter, please consider answering these questions, where appropriate ***

   * What led up to the situation?
   * What exactly did you do (or not do) that was effective (or
     ineffective)?
   * What was the outcome of this action?
   * What outcome did you expect instead?

*** End of the template - remove these template lines ***

Since upgrading Ansible to 2.5.0, it has been failing to gather facts on my
servers which do not have dmidecode installed.  I diffed the 2.4.3 and 2.5.0
versions of ansible/module_utils/facts/virtual/linux.py and found the following
change:

@@ -220,6 +233,17 @@
                 virtual_facts['virtualization_role'] = 'guest'
                 return virtual_facts

+        # In older Linux Kernel versions, /sys filesystem is not available
+        # dmidecode is the safest option to parse virtualization related values
+        dmi_bin = self.module.get_bin_path('dmidecode')
+        (rc, out, err) = self.module.run_command('%s -s system-product-name' % 
dmi_bin)
+        if rc == 0:
+            # Strip out commented lines (specific dmidecode output)
+            vendor_name = ''.join([line.strip() for line in out.splitlines() 
if not line.startswith('#')])
+            if vendor_name in ['VMware Virtual Platform', 'VMware7,1']:
+                virtual_facts['virtualization_type'] = 'VMware'
+                virtual_facts['virtualization_role'] = 'guest'
+

If dmidecode is not installed, dmi_bin is None and the call to
self.module.run_command fails with a fatal error.  Compare this to the running
of dmidecode in ansible/module_utils/facts/hardware/linux.py (ll. 304ff.):

            # Fall back to using dmidecode, if available
            dmi_bin = self.module.get_bin_path('dmidecode')
            DMI_DICT = {
                'bios_date': 'bios-release-date',
                'bios_version': 'bios-version',
                'form_factor': 'chassis-type',
                'product_name': 'system-product-name',
                'product_serial': 'system-serial-number',
                'product_uuid': 'system-uuid',
                'product_version': 'system-version',
                'system_vendor': 'system-manufacturer'
            }
            for (k, v) in DMI_DICT.items():
                if dmi_bin is not None:
                    (rc, out, err) = self.module.run_command('%s -s %s' % 
(dmi_bin, v))
                    if rc == 0:
                        # Strip out commented lines (specific dmidecode output)
                        thisvalue = ''.join([line for line in out.splitlines() 
if not line.startswith('#')])
                        try:
                            json.dumps(thisvalue)
                        except UnicodeDecodeError:
                            thisvalue = "NA"

                        dmi_facts[k] = thisvalue
                    else:
                        dmi_facts[k] = 'NA'
                else:
                    dmi_facts[k] = 'NA'

In this case, the code checks whether dmi_bin is None before attempting to run
it.

I think the new code is also missing a return statement.

I have installed dmidecode on my amd64 hosts, but I have an armel on which
dmidecode is not available.

-- System Information:
Debian Release: buster/sid
  APT prefers testing
  APT policy: (990, 'testing'), (900, 'stable'), (500, 'oldoldstable-updates'), 
(99, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.14.0-2-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8) (ignored: LC_ALL 
set to en_GB.UTF-8), LANGUAGE=en_GB:en (charmap=UTF-8) (ignored: LC_ALL set to 
en_GB.UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages ansible depends on:
ii  python                2.7.14-4
ii  python-crypto         2.6.1-8
ii  python-cryptography   2.1.4-1
ii  python-httplib2       0.9.2+dfsg-1
ii  python-jinja2         2.10-1
ii  python-netaddr        0.7.19-1
ii  python-paramiko       2.4.0-1
ii  python-pkg-resources  39.0.1-1
ii  python-yaml           3.12-1+b1

Versions of packages ansible recommends:
pn  python-jmespath   <none>
pn  python-kerberos   <none>
pn  python-libcloud   <none>
pn  python-selinux    <none>
pn  python-winrm      <none>
pn  python-xmltodict  <none>

Versions of packages ansible suggests:
ii  cowsay   3.03+dfsg2-4
pn  sshpass  <none>

-- no debconf information
diff --git a/lib/ansible/module_utils/facts/virtual/linux.py 
b/lib/ansible/module_utils/facts/virtual/linux.py
index a0ad545..7b0b233 100644
--- a/lib/ansible/module_utils/facts/virtual/linux.py
+++ b/lib/ansible/module_utils/facts/virtual/linux.py
@@ -236,13 +236,15 @@ class LinuxVirtual(Virtual):
         # In older Linux Kernel versions, /sys filesystem is not available
         # dmidecode is the safest option to parse virtualization related values
         dmi_bin = self.module.get_bin_path('dmidecode')
-        (rc, out, err) = self.module.run_command('%s -s system-product-name' % 
dmi_bin)
-        if rc == 0:
-            # Strip out commented lines (specific dmidecode output)
-            vendor_name = ''.join([line.strip() for line in out.splitlines() 
if not line.startswith('#')])
-            if vendor_name in ['VMware Virtual Platform', 'VMware7,1']:
-                virtual_facts['virtualization_type'] = 'VMware'
-                virtual_facts['virtualization_role'] = 'guest'
+        if dmi_bin is not None:
+            (rc, out, err) = self.module.run_command('%s -s 
system-product-name' % dmi_bin)
+            if rc == 0:
+                # Strip out commented lines (specific dmidecode output)
+                vendor_name = ''.join([line.strip() for line in 
out.splitlines() if not line.startswith('#')])
+                if vendor_name in ['VMware Virtual Platform', 'VMware7,1']:
+                    virtual_facts['virtualization_type'] = 'VMware'
+                    virtual_facts['virtualization_role'] = 'guest'
+                    return virtual_facts
 
         # If none of the above matches, return 'NA' for virtualization_type
         # and virtualization_role. This allows for proper grouping.

Reply via email to