Skip to content

Commit

Permalink
Use /etc/os-release to detect linux platforms
Browse files Browse the repository at this point in the history
This is the modern way of identifying Linux platforms and versions. It's
far more reliable than the brittle regex mess that we have built up over
the last decade. It also allows us to easily detect unknown / obscure
distros.

Signed-off-by: Tim Smith <tsmith@chef.io>
  • Loading branch information
tas50 committed Nov 24, 2018
1 parent 6b14655 commit 0d842f7
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 42 deletions.
93 changes: 67 additions & 26 deletions lib/ohai/plugins/linux/platform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,20 @@
provides "platform", "platform_version", "platform_family"
depends "lsb"

# @deprecated
def get_redhatish_platform(contents)
contents[/^Red Hat/i] ? "redhat" : contents[/(\w+)/i, 1].downcase
end

# Amazon Linux AMI release 2013.09
# Amazon Linux 2
# Amazon Linux 2 (Karoo)
# Fedora release 28 (Twenty Eight)
# CentOS release 5.8 (Final)
# CentOS release 6.7 (Final)
# Red Hat Enterprise Linux Server release 7.5 (Maipo)
#
# @deprecated
def get_redhatish_version(contents)
contents[/Rawhide/i] ? contents[/((\d+) \(Rawhide\))/i, 1].downcase : contents[/(release)? ([\d\.]+)/, 2]
end
Expand Down Expand Up @@ -81,6 +85,8 @@ def os_release_file_is_cisco?
#
# Determines the platform version for Cumulus Linux systems
#
# @deprecated
#
# @returns [String] cumulus Linux version from /etc/cumulus/etc.replace/os-release
#
def cumulus_version
Expand All @@ -94,6 +100,8 @@ def cumulus_version
#
# Determines the platform version for F5 Big-IP systems
#
# @deprecated
#
# @returns [String] bigip Linux version from /etc/f5-release
#
def bigip_version
Expand All @@ -107,6 +115,8 @@ def bigip_version
#
# Determines the platform version for Debian based systems
#
# @deprecated
#
# @returns [String] version of the platform
#
def debian_platform_version
Expand All @@ -120,11 +130,13 @@ def debian_platform_version
#
# Determines the platform_family based on the platform
#
# @param plat [String] the platform name
#
# @returns [String] platform_family value
#
def determine_platform_family
case platform
when /debian/, /ubuntu/, /linuxmint/, /raspbian/, /cumulus/
def platform_family_from_platform(plat)
case plat
when /debian/, /ubuntu/, /linuxmint/, /raspbian/, /cumulus/, /kali/
# apt-get+dpkg almost certainly goes here
"debian"
when /oracle/, /centos/, /redhat/, /scientific/, /enterpriseenterprise/, /xenserver/, /cloudlinux/, /ibm_powerkvm/, /parallels/, /nexus_centos/, /clearos/, /bigip/ # Note that 'enterpriseenterprise' is oracle's LSB "distributor ID"
Expand All @@ -139,7 +151,7 @@ def determine_platform_family
"amazon"
when /suse/, /sles/, /opensuse/
"suse"
when /fedora/, /pidora/, /arista_eos/
when /fedora/, /pidora/, /arista_eos/, /arista_eos/
# In the broadest sense: RPM-based, fedora-derived distributions which are not strictly re-compiled RHEL (if it uses RPMs, and smells more like redhat and less like
# SuSE it probably goes here).
"fedora"
Expand All @@ -149,7 +161,7 @@ def determine_platform_family
"gentoo"
when /slackware/
"slackware"
when /arch/
when /arch/, /manjaro/
"arch"
when /exherbo/
"exherbo"
Expand All @@ -160,7 +172,13 @@ def determine_platform_family
end
end

collect_data(:linux) do
# modern linux distros include a /etc/os-release file, which we now rely on for
# OS detection. For older distros that do not include that file we fall back to
# our pre-Ohai 15 detection logic, which is the method below. No new functionality
# should be added to this logic.
#
# @deprecated
def legacy_platform_detection
# platform [ and platform_version ? ] should be lower case to avoid dealing with RedHat/Redhat/redhat matching
if File.exist?("/etc/oracle-release")
contents = File.read("/etc/oracle-release").chomp
Expand Down Expand Up @@ -227,7 +245,6 @@ def determine_platform_family
elsif File.exist?("/etc/Eos-release")
platform "arista_eos"
platform_version File.read("/etc/Eos-release").strip.split[-1]
platform_family "fedora"
elsif os_release_file_is_cisco?
raise "unknown Cisco /etc/os-release or /etc/cisco-release ID_LIKE field" if
os_release_info["ID_LIKE"].nil? || ! os_release_info["ID_LIKE"].include?("wrlinux")
Expand All @@ -241,7 +258,6 @@ def determine_platform_family
raise "unknown Cisco /etc/os-release or /etc/cisco-release ID field"
end

platform_family "wrlinux"
platform_version os_release_info["VERSION"]
elsif File.exist?("/etc/gentoo-release")
platform "gentoo"
Expand Down Expand Up @@ -286,25 +302,50 @@ def determine_platform_family
elsif lsb[:id] # LSB can provide odd data that changes between releases, so we currently fall back on it rather than dealing with its subtleties
platform lsb[:id].downcase
platform_version lsb[:release]
# Use os-release (present on all modern linux distros) BUT use old *-release files as fallback.
# os-release will only be used if no other *-release file is present.
# We have to do this for compatibility reasons, or older OS releases might get different
# "platform" or "platform_version" attributes (e.g. SLES12, RHEL7).
elsif File.exist?("/etc/os-release")
case os_release_info["ID"]
when "sles"
platform "suse" # SLES is wrong. We call it SUSE
when "opensuse-leap"
platform "opensuseleap"
else
platform os_release_info["ID"]
end
platform_version os_release_info["VERSION_ID"]
# platform_family also does not need to be hardcoded anymore.
# This would be the correct way, but we stick with "determine_platform_family" for compatibility reasons.
# platform_family os_release_info["ID_LIKE"]
end
end

# our platform names don't match os-release. given a time machine they would but ohai
# came before the os-release file. This method remaps the os-release names to
# the ohai names
#
# @param id [String] the platform ID from /etc/os-release
#
# @returns [String] the platform name to use in Ohai
#
def platform_id_remap(id)
case id
when "rhel"
"redhat"
when "amzn"
"amazon"
when "ol"
"oracle"
when "sles"
"suse"
when "opensuse-leap"
"opensuseleap"
when "xenenterprise"
"xenserver"
else
id
end
end

collect_data(:linux) do
if ::File.exist?("/etc/os-release")
logger.trace("Plugin platform: Using /etc/os-release for platform detection")

# fixup os-release names to ohai platform names
platform platform_id_remap(os_release_info["ID"])

# unless we already set it in a specific way above set the plaform_version from os-release file
platform_version os_release_info["VERSION_ID"] if platform_version.nil?
else # we're on an old Linux distro
legacy_platform_detection
end

platform_family determine_platform_family if platform_family.nil?
# unless we set it in a specific way with the platform logic above set based on platform data
platform_family platform_family_from_platform(platform) if platform_family.nil?
end
end
24 changes: 8 additions & 16 deletions spec/unit/plugins/linux/platform_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,14 @@
expect(@plugin[:platform_version].to_f).to eq(2)
end

it "should read the platform as amazon and version as 2 when codename is in the release string" do
expect(File).to receive(:read).with("/etc/redhat-release").and_return("Amazon Linux release 2 (Karoo)")
@plugin.run
expect(@plugin[:platform]).to eq("amazon")
expect(@plugin[:platform_family]).to eq("amazon")
expect(@plugin[:platform_version].to_f).to eq(2)
end

# https://github.com/chef/ohai/issues/560
# Issue is seen on EL7, so that's what we're testing.
context "on versions that have /etc/os-release" do
Expand Down Expand Up @@ -819,14 +827,6 @@
expect(@plugin[:platform_family]).to eq("suse")
end

it "should read the version as 10.1 for bogus SLES 10" do
expect(File).to receive(:read).with("/etc/SuSE-release").and_return("SUSE Linux Enterprise Server 10 (i586)\nVERSION = 10\nPATCHLEVEL = 1\n")
@plugin.run
expect(@plugin[:platform]).to eq("suse")
expect(@plugin[:platform_version]).to eq("10.1")
expect(@plugin[:platform_family]).to eq("suse")
end

it "should read the version as 11.2" do
expect(File).to receive(:read).with("/etc/SuSE-release").and_return("SUSE Linux Enterprise Server 11.2 (i586)\nVERSION = 11\nPATCHLEVEL = 2\n")
@plugin.run
Expand All @@ -843,14 +843,6 @@
expect(@plugin[:platform_family]).to eq("suse")
end

it "[OHAI-272] should read the version as 9.1" do
expect(File).to receive(:read).with("/etc/SuSE-release").exactly(1).times.and_return("SuSE Linux 9.1 (i586)\nVERSION = 9.1")
@plugin.run
expect(@plugin[:platform]).to eq("suse")
expect(@plugin[:platform_version]).to eq("9.1")
expect(@plugin[:platform_family]).to eq("suse")
end

it "[OHAI-272] should read the version as 11.4" do
expect(File).to receive(:read).with("/etc/SuSE-release").exactly(1).times.and_return("openSUSE 11.4 (i586)\nVERSION = 11.4\nCODENAME = Celadon")
@plugin.run
Expand Down

0 comments on commit 0d842f7

Please sign in to comment.