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.