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()