azurelinuxagent/common/future.py (101 lines of code) (raw):

import contextlib import platform import sys import os import re # Note broken dependency handling to avoid potential backward # compatibility issues on different distributions try: import distro # pylint: disable=E0401 except Exception: pass # pylint: disable=W0105 """ Add alias for python2 and python3 libs and functions. """ # pylint: enable=W0105 if sys.version_info[0] == 3: import http.client as httpclient # pylint: disable=W0611,import-error from urllib.parse import urlparse # pylint: disable=W0611,import-error,no-name-in-module """Rename Python3 str to ustr""" # pylint: disable=W0105 ustr = str bytebuffer = memoryview # We aren't using these imports in this file, but we want them to be available # to import from this module in others. # Additionally, python2 doesn't have this, so we need to disable import-error # as well. # unused-import<W0611>, import-error<E0401> Disabled: Due to backward compatibility between py2 and py3 from builtins import int, range # pylint: disable=unused-import,import-error from collections import OrderedDict # pylint: disable=W0611 from queue import Queue, Empty # pylint: disable=W0611,import-error # unused-import<W0611> Disabled: python2.7 doesn't have subprocess.DEVNULL # so this import is only used by python3. import subprocess # pylint: disable=unused-import elif sys.version_info[0] == 2: import httplib as httpclient # pylint: disable=E0401,W0611 from urlparse import urlparse # pylint: disable=E0401 from Queue import Queue, Empty # pylint: disable=W0611,import-error # We want to suppress the following: # - undefined-variable<E0602>: # These builtins are not defined in python3 # - redefined-builtin<W0622>: # This is intentional, so that code that wants to use builtins we're # assigning new names to doesn't need to check python versions before # doing so. # pylint: disable=undefined-variable,redefined-builtin ustr = unicode # Rename Python2 unicode to ustr bytebuffer = buffer range = xrange int = long if sys.version_info[1] >= 7: from collections import OrderedDict # For Py 2.7+ else: from ordereddict import OrderedDict # Works only on 2.6 # pylint: disable=E0401 else: raise ImportError("Unknown python version: {0}".format(sys.version_info)) def get_linux_distribution(get_full_name, supported_dists): """Abstract platform.linux_distribution() call which is deprecated as of Python 3.5 and removed in Python 3.7""" try: supported = platform._supported_dists + (supported_dists,) osinfo = list( platform.linux_distribution( # pylint: disable=W1505 full_distribution_name=get_full_name, supported_dists=supported ) ) # The platform.linux_distribution() lib has issue with detecting OpenWRT linux distribution. # Merge the following patch provided by OpenWRT as a temporary fix. if os.path.exists("/etc/openwrt_release"): osinfo = get_openwrt_platform() if not osinfo or osinfo == ['', '', '']: return get_linux_distribution_from_distro(get_full_name) full_name = platform.linux_distribution()[0].strip() # pylint: disable=W1505 osinfo.append(full_name) except AttributeError: return get_linux_distribution_from_distro(get_full_name) return osinfo def get_linux_distribution_from_distro(get_full_name): """Get the distribution information from the distro Python module.""" # If we get here we have to have the distro module, thus we do # not wrap the call in a try-except block as it would mask the problem # and result in a broken agent installation osinfo = list( distro.linux_distribution( full_distribution_name=get_full_name ) ) full_name = distro.linux_distribution()[0].strip() osinfo.append(full_name) # Fixing is the problem https://github.com/Azure/WALinuxAgent/issues/2715. Distro.linux_distribution method not retuning full version # If best is true, the most precise version number out of all examined sources is returned. if "mariner" in osinfo[0].lower(): osinfo[1] = distro.version(best=True) return osinfo def get_openwrt_platform(): """ Add this workaround for detecting OpenWRT products because the version and product information is contained in the /etc/openwrt_release file. """ result = [None, None, None] openwrt_version = re.compile(r"^DISTRIB_RELEASE=['\"](\d+\.\d+.\d+)['\"]") openwrt_product = re.compile(r"^DISTRIB_ID=['\"]([\w-]+)['\"]") with open('/etc/openwrt_release', 'r') as fh: content = fh.readlines() for line in content: version_matches = openwrt_version.match(line) product_matches = openwrt_product.match(line) if version_matches: result[1] = version_matches.group(1) elif product_matches: if product_matches.group(1) == "OpenWrt": result[0] = "openwrt" return result def is_file_not_found_error(exception): # pylint for python2 complains, but FileNotFoundError is # defined for python3. # pylint: disable=undefined-variable if sys.version_info[0] == 2: # Python 2 uses OSError(errno=2) return isinstance(exception, OSError) and exception.errno == 2 elif sys.version_info[0] == 3: return isinstance(exception, FileNotFoundError) return isinstance(exception, FileNotFoundError) @contextlib.contextmanager def subprocess_dev_null(): if sys.version_info[0] == 3: # Suppress no-member errors on python2.7 yield subprocess.DEVNULL # pylint: disable=no-member else: try: devnull = open(os.devnull, "a+") yield devnull except Exception: yield None finally: if devnull is not None: devnull.close() def array_to_bytes(buff): # Python 3.9 removed the tostring() method on arrays, the new alias is tobytes() if sys.version_info[0] == 2: return buff.tostring() if sys.version_info[0] == 3 and sys.version_info[1] <= 8: return buff.tostring() return buff.tobytes()