Arturo Herrero
Arturo Herrero

Reputation: 13122

Detecting Linux distribution/platform in Ruby

I can check the operating system of the platform that is running my Ruby code in a several ways:

Is it possible to know what Linux distribution is running? For example a Debian based or a Red Hat based distribution.

Upvotes: 7

Views: 2453

Answers (4)

Mike Slinn
Mike Slinn

Reputation: 8403

The question does not indicate the purpose. If the purpose is to determine if a distribution-specific command is available, this might be an appropriate answer.

The Ruby standard library provides find_executable. You can use find_executable and find_executable0 to check the package manager.

For example, to detect Debian, or derivatives such as Ubuntu, just check for the existence of dpkg.

require 'mkmf'

MakeMakefile::Logging.instance_variable_set(:@logfile, nil)
puts "Debian compatible" if find_executable0 'dpkg'

To detect Ubuntu, or a derivative such as Mint, check for apt.

require 'mkmf'

MakeMakefile::Logging.instance_variable_set(:@logfile, nil)
puts "Ubuntu compatible" if find_executable0 'apt'

Note that find_executable outputs a message, which you might not want. find_executable0 performs the same task, without generating the message:

irb(main):006> require 'mkmf'
=> false
irb(main):007> find_executable 'dpkg'
checking for dpkg... yes
=> "/usr/bin/dpkg"
irb(main):008> find_executable0 'dpkg'
=> "/usr/bin/dpkg"

Upvotes: 0

sondra.kinsey
sondra.kinsey

Reputation: 843

A Linux distribution is a collection of software, usually distinguishable by their package manager, window system, window manager, and desktop environment. That's a lot of interchangeable parts. If a system keeps the package manager, but changes the window system and desktop environment, do we call it a new distribution? There's no definitive answer, so various tools will give slightly different answers.

Train has a whole hierarchy of distribution families and may be the most sophisticated of the bunch. A quick comparison of Train and Ohai is here. It's designed to be run over a network connection, but works fine locally, too, as shown here:

# gem install train
Train.create('local').connection.os[:name] #=> eg. "centos", "linuxmint"
Train.create('local').connection.os[:family] #=> eg. "redhat", "debian"

Facter's osfamily fact returns, eg. "Debian" for Ubuntu. With Facter, the general form for retrieving facts is Facter[factname].value.

# gem install facter
require 'facter'
puts Facter['osfamily'].value

Ohai's platform_family fact returns, eg. "debian" for Ubuntu and "rhel" for CentOS. With Ohai, the general form for retrieving facts is node[factname].

# gem install ohai
node['platform'] #=> eg. "ubuntu" or "mint"
node['platform_family'] #=> eg. "debian" for Ubuntu and Mint

Ruby system info libraries which won't distinguish platforms

Platform retrieves some basic data, and can distinguish well between a variety of Unix platforms. However, it doesn't handle different distributions of Linux at all. Platform::IMPL will return :freebsd, :netbsd, :hpux, etc., but all Linux distros are just :linux. sys-uname and sysinfo are similar. utilinfo is even more basic, and will fail on any systems beyond Windows, Mac, and Linux.

Upvotes: 1

Que
Que

Reputation: 1

require 'facter'

puts Facter['osfamily'].value

Upvotes: -1

user2845360
user2845360

Reputation:

As pointed above in the comment section, it seems that there is no sure "works in every distribution" way of doing this. What follows is what I've used to detect what kind of an environment a script is being run:

def linux_variant
  r = { :distro => nil, :family => nil }

  if File.exists?('/etc/lsb-release')
    File.open('/etc/lsb-release', 'r').read.each_line do |line|
      r = { :distro => $1 } if line =~ /^DISTRIB_ID=(.*)/
    end
  end

  if File.exists?('/etc/debian_version')
    r[:distro] = 'Debian' if r[:distro].nil?
    r[:family] = 'Debian' if r[:variant].nil?
  elsif File.exists?('/etc/redhat-release') or File.exists?('/etc/centos-release')
    r[:family] = 'RedHat' if r[:family].nil?
    r[:distro] = 'CentOS' if File.exists?('/etc/centos-release')
  elsif File.exists?('/etc/SuSE-release')
    r[:distro] = 'SLES' if r[:distro].nil?
  end

  return r
end

This is not a complete solution to handle every GNU/Linux distribution on earth. Far from it, actually. For example it makes no distinction between OpenSUSE and SUSE Linux Enterprise Server, though they are two quite different beasts. Besides, it's quite a spaghetti even with just a few distros. But it might be something one might be able to build on.

You can find a more complete example of distribution detection from the source code of Facter which is used, among other things, to feed facts to a configuration management system Puppet.

Upvotes: 3

Related Questions