]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-deploy.git/commitdiff
[RM-18164] Use /etc/os-release if platform.linux_distribution() empty 453/head
authorTim Serong <tserong@suse.com>
Wed, 6 Sep 2017 05:53:32 +0000 (15:53 +1000)
committerTim Serong <tserong@suse.com>
Mon, 18 Sep 2017 15:34:32 +0000 (17:34 +0200)
On systems with only /etc/os-release (rather than distro-specific
release files), platform.linux_distribution() returns ('', '', '').
In this case, fall back to parsing /etc/os-release instead.

It would better to flip the ordering, and use /etc/os-release first,
with platform.linux_distribution() as a fallback.  There's tests for
seven different distros' os-release files already, but we may want
more before flipping this around.

(It would be better still to just use the distro.linux_distribution()
function, especially since platform.linux_distribution() is
deprecated, but I don't know that there's a way of ensuring that
module is present in advance on all the remote hosts.)

Fixes: http://tracker.ceph.com/issues/18164
Signed-off-by: Tim Serong <tserong@suse.com>
ceph_deploy/hosts/__init__.py
ceph_deploy/hosts/remotes.py
ceph_deploy/tests/test_remotes.py

index a96e61466c9b720d3a3f5c585ef47f1056615ea0..c8605d5d5e39055be7b7c492e799e816dd1bfa41 100644 (file)
@@ -114,7 +114,7 @@ def _normalized_distro_name(distro):
         return 'scientific'
     elif distro.startswith('oracle'):
         return 'oracle'
-    elif distro.startswith(('suse', 'opensuse')):
+    elif distro.startswith(('suse', 'opensuse', 'sles')):
         return 'suse'
     elif distro.startswith('centos'):
         return 'centos'
index e3aef4aecc15920ed4987d276b93cfc8541d021c..fec1da0d6031690396ef1ba43c4ea215dd6db6b9 100644 (file)
@@ -8,12 +8,15 @@ import os
 import shutil
 import tempfile
 import platform
+import re
 
 
 def platform_information(_linux_distribution=None):
     """ detect platform information from remote host """
     linux_distribution = _linux_distribution or platform.linux_distribution
     distro, release, codename = linux_distribution()
+    if not distro:
+        distro, release, codename = parse_os_release()
     if not codename and 'debian' in distro.lower():  # this could be an empty string in Debian
         debian_codenames = {
             '10': 'buster',
@@ -45,6 +48,34 @@ def platform_information(_linux_distribution=None):
     )
 
 
+def parse_os_release(release_path='/etc/os-release'):
+    """ Extract (distro, release, codename) from /etc/os-release if present """
+    release_info = {}
+    if os.path.isfile(release_path):
+        for line in open(release_path, 'r').readlines():
+            line = line.strip()
+            if line.startswith('#'):
+                continue
+            parts = line.split('=')
+            if len(parts) != 2:
+                continue
+            release_info[parts[0].strip()] = parts[1].strip("\"'\n\t ")
+    # In theory, we want ID/NAME, VERSION_ID and VERSION_CODENAME (with a
+    # possible fallback to VERSION on the latter), based on information at:
+    # https://www.freedesktop.org/software/systemd/man/os-release.html
+    # However, after reviewing several distros /etc/os-release, getting
+    # the codename is a bit of a mess.  It's usually in parentheses in
+    # VERSION, with some exceptions.
+    distro = release_info.get('ID', '')
+    release = release_info.get('VERSION_ID', '')
+    codename = release_info.get('UBUNTU_CODENAME', release_info.get('VERSION', ''))
+    match = re.match(r'^[^(]+ \(([^)]+)\)', codename)
+    if match:
+        codename = match.group(1).lower()
+    if not codename and release_info.get('NAME', '') == 'openSUSE Tumbleweed':
+        codename = 'tumbleweed'
+    return (distro, release, codename)
+
 def machine_type():
     """ detect machine type """
     return platform.machine()
index 71384290f1f56d2ad7105cd6e3b0f28bf44f1bdd..4378ab75ea618e5b73b6d77af3415685efbb319e 100644 (file)
@@ -1,6 +1,6 @@
 from mock import patch
 from ceph_deploy.hosts import remotes
-from ceph_deploy.hosts.remotes import platform_information
+from ceph_deploy.hosts.remotes import platform_information, parse_os_release
 
 class FakeExists(object):
 
@@ -83,3 +83,154 @@ class TestPlatformInformation(object):
         assert distro == 'Ubuntu'
         assert release == '12.04'
         assert codename == 'precise'
+
+class TestParseOsRelease(object):
+    """ test various forms of /etc/os-release """
+
+    def setup(self):
+        pass
+
+    def test_handles_centos_7(self, tmpdir):
+        path = str(tmpdir.join('os_release'))
+        with open(path, 'w') as os_release:
+            os_release.write("""
+NAME="CentOS Linux"
+VERSION="7 (Core)"
+ID="centos"
+ID_LIKE="rhel fedora"
+VERSION_ID="7"
+PRETTY_NAME="CentOS Linux 7 (Core)"
+ANSI_COLOR="0;31"
+CPE_NAME="cpe:/o:centos:centos:7"
+HOME_URL="https://www.centos.org/"
+BUG_REPORT_URL="https://bugs.centos.org/"
+
+CENTOS_MANTISBT_PROJECT="CentOS-7"
+CENTOS_MANTISBT_PROJECT_VERSION="7"
+REDHAT_SUPPORT_PRODUCT="centos"
+REDHAT_SUPPORT_PRODUCT_VERSION="7"
+""")
+        distro, release, codename = parse_os_release(path)
+        assert distro == 'centos'
+        assert release == '7'
+        assert codename == 'core'
+
+
+    def test_handles_debian_stretch(self, tmpdir):
+        path = str(tmpdir.join('os_release'))
+        with open(path, 'w') as os_release:
+            os_release.write("""
+PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
+NAME="Debian GNU/Linux"
+VERSION_ID="9"
+VERSION="9 (stretch)"
+ID=debian
+HOME_URL="https://www.debian.org/"
+SUPPORT_URL="https://www.debian.org/support"
+BUG_REPORT_URL="https://bugs.debian.org/"
+""")
+        distro, release, codename = parse_os_release(path)
+        assert distro == 'debian'
+        assert release == '9'
+        assert codename == 'stretch'
+
+    def test_handles_fedora_26(self, tmpdir):
+        path = str(tmpdir.join('os_release'))
+        with open(path, 'w') as os_release:
+            os_release.write("""
+NAME=Fedora
+VERSION="26 (Twenty Six)"
+ID=fedora
+VERSION_ID=26
+PRETTY_NAME="Fedora 26 (Twenty Six)"
+ANSI_COLOR="0;34"
+CPE_NAME="cpe:/o:fedoraproject:fedora:26"
+HOME_URL="https://fedoraproject.org/"
+BUG_REPORT_URL="https://bugzilla.redhat.com/"
+REDHAT_BUGZILLA_PRODUCT="Fedora"
+REDHAT_BUGZILLA_PRODUCT_VERSION=26
+REDHAT_SUPPORT_PRODUCT="Fedora"
+REDHAT_SUPPORT_PRODUCT_VERSION=26
+PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy
+""")
+        distro, release, codename = parse_os_release(path)
+        assert distro == 'fedora'
+        assert release == '26'
+        assert codename == 'twenty six'
+
+    def test_handles_opensuse_leap_42_2(self, tmpdir):
+        path = str(tmpdir.join('os_release'))
+        with open(path, 'w') as os_release:
+            os_release.write("""
+NAME="openSUSE Leap"
+VERSION="42.2"
+ID=opensuse
+ID_LIKE="suse"
+VERSION_ID="42.2"
+PRETTY_NAME="openSUSE Leap 42.2"
+ANSI_COLOR="0;32"
+CPE_NAME="cpe:/o:opensuse:leap:42.2"
+BUG_REPORT_URL="https://bugs.opensuse.org"
+HOME_URL="https://www.opensuse.org/"
+""")
+        distro, release, codename = parse_os_release(path)
+        assert distro == 'opensuse'
+        assert release == '42.2'
+        assert codename == '42.2'
+
+    def test_handles_opensuse_tumbleweed(self, tmpdir):
+        path = str(tmpdir.join('os_release'))
+        with open(path, 'w') as os_release:
+            os_release.write("""
+NAME="openSUSE Tumbleweed"
+# VERSION="20170502"
+ID=opensuse
+ID_LIKE="suse"
+VERSION_ID="20170502"
+PRETTY_NAME="openSUSE Tumbleweed"
+ANSI_COLOR="0;32"
+CPE_NAME="cpe:/o:opensuse:tumbleweed:20170502"
+BUG_REPORT_URL="https://bugs.opensuse.org"
+HOME_URL="https://www.opensuse.org/"
+""")
+        distro, release, codename = parse_os_release(path)
+        assert distro == 'opensuse'
+        assert release == '20170502'
+        assert codename == 'tumbleweed'
+
+    def test_handles_sles_12_sp3(self, tmpdir):
+        path = str(tmpdir.join('os_release'))
+        with open(path, 'w') as os_release:
+            os_release.write("""
+NAME="SLES"
+VERSION="12-SP3"
+VERSION_ID="12.3"
+PRETTY_NAME="SUSE Linux Enterprise Server 12 SP3"
+ID="sles"
+ANSI_COLOR="0;32"
+CPE_NAME="cpe:/o:suse:sles:12:sp3"
+""")
+        distro, release, codename = parse_os_release(path)
+        assert distro == 'sles'
+        assert release == '12.3'
+        assert codename == '12-SP3'
+
+    def test_handles_ubuntu_xenial(self, tmpdir):
+        path = str(tmpdir.join('os_release'))
+        with open(path, 'w') as os_release:
+            os_release.write("""
+NAME="Ubuntu"
+VERSION="16.04 LTS (Xenial Xerus)"
+ID=ubuntu
+ID_LIKE=debian
+PRETTY_NAME="Ubuntu 16.04 LTS"
+VERSION_ID="16.04"
+HOME_URL="http://www.ubuntu.com/"
+SUPPORT_URL="http://help.ubuntu.com/"
+BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
+UBUNTU_CODENAME=xenial
+""")
+        distro, release, codename = parse_os_release(path)
+        assert distro == 'ubuntu'
+        assert release == '16.04'
+        assert codename == 'xenial'