summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Galić <me+github@igalic.co>2019-11-25 23:10:50 +0100
committerChad Smith <chad.smith@canonical.com>2019-11-25 15:10:50 -0700
commit2a135c4a421af47f5bd511e89e385a72f62bde33 (patch)
tree9abda1673b01fa4838874adb3a8551282552d984
parentaa935aefd2a01e792a397a28a915f0e029aeaed6 (diff)
downloadvyos-cloud-init-2a135c4a421af47f5bd511e89e385a72f62bde33.tar.gz
vyos-cloud-init-2a135c4a421af47f5bd511e89e385a72f62bde33.zip
FreeBSD: fix for get_linux_distro() and lru_cache (#59)
Since `is_FreeBSD()` is used a lot, which uses `system_info()`, which uses `get_linux_distro()` we add caching, by decorating the following functions with `@lru_cache`: - get_architecture() - _lsb_release() - is_FreeBSD - get_linux_distro - system_info() - _get_cmdline() Since [functools](https://docs.python.org/3/library/functools.html) only exists in Python 3, only python 3 will benefit from this improvement. For python 2, our shim is just a pass-thru. Too bad, but, also… https://pythonclock.org/ The main motivation here was, at first, to cache more, following the style of _lsb_release. That is now consolidated under this very same roof. LP: #1815030
-rw-r--r--cloudinit/tests/test_util.py19
-rw-r--r--cloudinit/util.py47
-rw-r--r--tests/unittests/test_net.py19
3 files changed, 61 insertions, 24 deletions
diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py
index f4f95e92..64ed82ea 100644
--- a/cloudinit/tests/test_util.py
+++ b/cloudinit/tests/test_util.py
@@ -387,6 +387,11 @@ class TestUdevadmSettle(CiTestCase):
@mock.patch('os.path.exists')
class TestGetLinuxDistro(CiTestCase):
+ def setUp(self):
+ # python2 has no lru_cache, and therefore, no cache_clear()
+ if hasattr(util.get_linux_distro, "cache_clear"):
+ util.get_linux_distro.cache_clear()
+
@classmethod
def os_release_exists(self, path):
"""Side effect function"""
@@ -399,6 +404,12 @@ class TestGetLinuxDistro(CiTestCase):
if path == '/etc/redhat-release':
return 1
+ @classmethod
+ def freebsd_version_exists(self, path):
+ """Side effect function """
+ if path == '/bin/freebsd-version':
+ return 1
+
@mock.patch('cloudinit.util.load_file')
def test_get_linux_distro_quoted_name(self, m_os_release, m_path_exists):
"""Verify we get the correct name if the os-release file has
@@ -417,6 +428,14 @@ class TestGetLinuxDistro(CiTestCase):
dist = util.get_linux_distro()
self.assertEqual(('ubuntu', '16.04', 'xenial'), dist)
+ @mock.patch('cloudinit.util.subp')
+ def test_get_linux_freebsd(self, m_subp, m_path_exists):
+ """Verify we get the correct name and release name on FreeBSD."""
+ m_path_exists.side_effect = TestGetLinuxDistro.freebsd_version_exists
+ m_subp.return_value = ("12.0-RELEASE-p10\n", '')
+ dist = util.get_linux_distro()
+ self.assertEqual(('freebsd', '12.0-RELEASE-p10', ''), dist)
+
@mock.patch('cloudinit.util.load_file')
def test_get_linux_centos6(self, m_os_release, m_path_exists):
"""Verify we get the correct name and release name on CentOS 6."""
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 1f600df4..c498414d 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -50,6 +50,16 @@ from cloudinit import version
from cloudinit.settings import (CFG_BUILTIN)
+try:
+ from functools import lru_cache
+except ImportError:
+ def lru_cache():
+ """pass-thru replace for Python3's lru_cache()"""
+ def wrapper(f):
+ return f
+ return wrapper
+
+
_DNS_REDIRECT_IP = None
LOG = logging.getLogger(__name__)
@@ -68,17 +78,15 @@ CONTAINER_TESTS = (['systemd-detect-virt', '--quiet', '--container'],
['running-in-container'],
['lxc-is-container'])
-PROC_CMDLINE = None
-
-_LSB_RELEASE = {}
-
+@lru_cache()
def get_architecture(target=None):
out, _ = subp(['dpkg', '--print-architecture'], capture=True,
target=target)
return out.strip()
+@lru_cache()
def _lsb_release(target=None):
fmap = {'Codename': 'codename', 'Description': 'description',
'Distributor ID': 'id', 'Release': 'release'}
@@ -107,11 +115,7 @@ def lsb_release(target=None):
# do not use or update cache if target is provided
return _lsb_release(target)
- global _LSB_RELEASE
- if not _LSB_RELEASE:
- data = _lsb_release()
- _LSB_RELEASE.update(data)
- return _LSB_RELEASE
+ return _lsb_release()
def target_path(target, path=None):
@@ -546,6 +550,7 @@ def is_ipv4(instr):
return len(toks) == 4
+@lru_cache()
def is_FreeBSD():
return system_info()['variant'] == "freebsd"
@@ -595,6 +600,7 @@ def _parse_redhat_release(release_file=None):
return {}
+@lru_cache()
def get_linux_distro():
distro_name = ''
distro_version = ''
@@ -622,6 +628,10 @@ def get_linux_distro():
flavor = match.groupdict()['codename']
if distro_name == 'rhel':
distro_name = 'redhat'
+ elif os.path.exists('/bin/freebsd-version'):
+ distro_name = 'freebsd'
+ distro_version, _ = subp(['uname', '-r'])
+ distro_version = distro_version.strip()
else:
dist = ('', '', '')
try:
@@ -642,6 +652,7 @@ def get_linux_distro():
return (distro_name, distro_version, flavor)
+@lru_cache()
def system_info():
info = {
'platform': platform.platform(),
@@ -1371,14 +1382,8 @@ def load_file(fname, read_cb=None, quiet=False, decode=True):
return contents
-def get_cmdline():
- if 'DEBUG_PROC_CMDLINE' in os.environ:
- return os.environ["DEBUG_PROC_CMDLINE"]
-
- global PROC_CMDLINE
- if PROC_CMDLINE is not None:
- return PROC_CMDLINE
-
+@lru_cache()
+def _get_cmdline():
if is_container():
try:
contents = load_file("/proc/1/cmdline")
@@ -1393,10 +1398,16 @@ def get_cmdline():
except Exception:
cmdline = ""
- PROC_CMDLINE = cmdline
return cmdline
+def get_cmdline():
+ if 'DEBUG_PROC_CMDLINE' in os.environ:
+ return os.environ["DEBUG_PROC_CMDLINE"]
+
+ return _get_cmdline()
+
+
def pipe_in_out(in_fh, out_fh, chunk_size=1024, chunk_cb=None):
bytes_piped = 0
while True:
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 0f45dc38..01119e0a 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -4576,6 +4576,7 @@ class TestNetRenderers(CiTestCase):
priority=['sysconfig', 'eni'])
@mock.patch("cloudinit.net.renderers.netplan.available")
+ @mock.patch("cloudinit.net.renderers.sysconfig.available")
@mock.patch("cloudinit.net.renderers.sysconfig.available_sysconfig")
@mock.patch("cloudinit.net.renderers.sysconfig.available_nm")
@mock.patch("cloudinit.net.renderers.eni.available")
@@ -4583,14 +4584,16 @@ class TestNetRenderers(CiTestCase):
def test_sysconfig_selected_on_sysconfig_enabled_distros(self, m_distro,
m_eni, m_sys_nm,
m_sys_scfg,
+ m_sys_avail,
m_netplan):
"""sysconfig only selected on specific distros (rhel/sles)."""
# Ubuntu with Network-Manager installed
- m_eni.return_value = False # no ifupdown (ifquery)
- m_sys_scfg.return_value = False # no sysconfig/ifup/ifdown
- m_sys_nm.return_value = True # network-manager is installed
- m_netplan.return_value = True # netplan is installed
+ m_eni.return_value = False # no ifupdown (ifquery)
+ m_sys_scfg.return_value = False # no sysconfig/ifup/ifdown
+ m_sys_nm.return_value = True # network-manager is installed
+ m_netplan.return_value = True # netplan is installed
+ m_sys_avail.return_value = False # no sysconfig on Ubuntu
m_distro.return_value = ('ubuntu', None, None)
self.assertEqual('netplan', renderers.select(priority=None)[0])
@@ -4598,7 +4601,8 @@ class TestNetRenderers(CiTestCase):
m_eni.return_value = False # no ifupdown (ifquery)
m_sys_scfg.return_value = False # no sysconfig/ifup/ifdown
m_sys_nm.return_value = True # network-manager is installed
- m_netplan.return_value = False # netplan is not installed
+ m_netplan.return_value = False # netplan is not installed
+ m_sys_avail.return_value = True # sysconfig is available on centos
m_distro.return_value = ('centos', None, None)
self.assertEqual('sysconfig', renderers.select(priority=None)[0])
@@ -4606,7 +4610,8 @@ class TestNetRenderers(CiTestCase):
m_eni.return_value = False # no ifupdown (ifquery)
m_sys_scfg.return_value = False # no sysconfig/ifup/ifdown
m_sys_nm.return_value = True # network-manager is installed
- m_netplan.return_value = False # netplan is not installed
+ m_netplan.return_value = False # netplan is not installed
+ m_sys_avail.return_value = True # sysconfig is available on opensuse
m_distro.return_value = ('opensuse', None, None)
self.assertEqual('sysconfig', renderers.select(priority=None)[0])
@@ -4625,6 +4630,8 @@ class TestNetRenderers(CiTestCase):
]
for (distro_name, distro_version, flavor) in distro_values:
m_distro.return_value = (distro_name, distro_version, flavor)
+ if hasattr(util.system_info, "cache_clear"):
+ util.system_info.cache_clear()
result = sysconfig.available()
self.assertTrue(result)