lib/metadata/linux/LinuxOSInfo.rb
require 'manageiq/gems/pending'
require 'util/miq-xml'
module MiqLinux
class OSInfo
attr_reader :os, :networks
ETC = "/etc"
IFCFGFILE = "/etc/sysconfig/network-scripts"
DHCLIENTFILE = "/var/lib/dhclient/"
DEBIANDHCLIENTFILE = "/var/lib/dhcp3/"
DEBIANIFCFGILE = "/etc/network"
DISTRIBUTIONS = ["mandriva", "mandrake", "mandrakelinux", "gentoo", "SuSE", "fedora", "redhat", "knoppix", "debian", "lsb", "distro"]
def initialize(fs)
@fs = fs
@os_type = "Linux"
@distribution = nil
@description = nil
@hostname = nil
release_file = nil
version_file = nil
@networks = []
@os = {}
DISTRIBUTIONS.each do |dist|
release_file = File.join(ETC, dist + "-release")
if fs.fileExists?(release_file)
@distribution = dist
break
end
end
if @distribution == "lsb"
lsbd = ""
fs.fileOpen(release_file) { |fo| lsbd = fo.read }
dist = desc = chrome_dist = chrome_desc = nil
lsbd.each_line do |lsbl|
dist = $1 if lsbl =~ /^\s*DISTRIB_ID\s*=\s*(.*)$/
desc = $1 if lsbl =~ /^\s*DISTRIB_DESCRIPTION\s*=\s*(.*)$/
chrome_dist = $1 if lsbl =~ /^\s*CHROMEOS_RELEASE_NAME\s*=\s*(.*)$/
chrome_desc = $1 if lsbl =~ /^\s*CHROMEOS_RELEASE_DESCRIPTION\s*=\s*(.*)$/
end
chrome_desc = "#{chrome_dist} #{chrome_desc}" if chrome_dist && chrome_desc
@distribution = chrome_dist || dist if chrome_dist || dist
@description = chrome_desc || desc if chrome_desc || desc
elsif @distribution
fs.fileOpen(release_file) { |fo| @description = fo.read.to_s.chomp }
@distribution = "CentOS" if @distribution == "redhat" && @description.include?("CentOS")
@distribution = "rPath" if @distribution == "distro"
end
unless @distribution
DISTRIBUTIONS.each do |distrib|
version_file = File.join(ETC, distrib + "-release")
if fs.fileExists?(version_file)
@distribution = distrib
break
end
end
fs.fileOpen(version_file) { |fo| @description = fo.read.chomp } if @distribution
end
unless @distribution
read_file(fs, File.join(ETC, "issue")) do |line|
case line
when /\s*Hercules\s*/
@distribution = "hercules"
@description = "Hercules"
break
end
end
end
@distribution = "" unless @distribution
@description = "" unless @description
@description = @description.gsub(/^"/, "").gsub(/"$/, "")
["/etc/hostname", "/etc/HOSTNAME"].each do |hnf|
next unless fs.fileExists?(hnf)
fs.fileOpen(hnf) { |fo| @hostname = fo.read.chomp } if fs.fileExists?(hnf)
end
# return if @hostname
["/etc/conf.d/hostname", "/etc/sysconfig/network"].each do |hnf|
next unless fs.fileExists?(hnf)
next if fs.fileDirectory?(hnf)
hnfd = ""
fs.fileOpen(hnf) { |fo| hnfd = fo.read }
hnfd.each_line do |hnfl|
if hnfl =~ /^\s*HOSTNAME\s*=\s*(.*)$/
@hostname = $1
break
end
end
end
@hostname = "" unless @hostname
network_attrs = {:hostname => @hostname}
# Collect network settings
case @distribution.downcase
when "ubuntu" then networking_debian(fs, network_attrs)
when "redhat", "fedora" then networking_redhat(fs, network_attrs)
when "hercules" then networking_hercules(fs, network_attrs)
end
@os = {:type => "linux", :machine_name => @hostname, :product_type => @os_type, :distribution => @distribution, :product_name => @description}
$log.info "VM OS information: [#{@os.inspect}]" if $log
end
def networking_debian(fs, attrs)
read_file(fs, File.join(DEBIANIFCFGILE, "interfaces")) do |line|
case line
when /^\s*iface eth0 inet dhcp\s*(.*)$/ then attrs[:dhcp_enabled] = 1
when /^\s*iface eth0 inet static\s*(.*)$/ then attrs[:dhcp_enabled] = 0
when /^\s*address\s*(.*)$/ then attrs[:ipaddress] = $1
when /^\s*netmask\s*(.*)$/ then attrs[:subnet_mask] = $1
when /^\s*gateway\s*(.*)$/ then attrs[:default_gateway] = $1
when /^\s*network\s*(.*)$/ then attrs[:network] = $1
end
end
if attrs[:dhcp_enabled] == 1
read_file(fs, File.join(DEBIANDHCLIENTFILE, "dhclient.eth0.leases")) do |line|
case line
when /^\s*fixed-address\s*(.*)\;$/ then attrs[:ipaddress] = $1
when /^\s*option subnet-mask\s*(.*)\;$/ then attrs[:subnet_mask] = $1
when /^\s*option routers\s*(.*)\;$/ then attrs[:default_gateway] = $1
when /^\s*option domain-name-servers\s*(.*)\;$/ then attrs[:dns_server] = $1
when /^\s*option dhcp-server-identifier\s*(.*)\;$/ then attrs[:dhcp_server] = $1
when /^\s*option domain-name\s*"*(.*)"\;$/ then attrs[:domain] = $1
when /^\s*expire\s*[0-9]?\s*(.*)\;$/ then attrs[:lease_expires] = $1
when /^\s*renew\s*[0-9]?\s*(.*)\;$/ then attrs[:lease_obtained] = $1
end
end
end
fix_attr_values(attrs)
@networks << attrs
end
def networking_redhat(fs, attrs)
read_file(fs, File.join(IFCFGFILE, "ifcfg-eth0")) do |line|
case line
when /^\s*BOOTPROTO=dhcp\s*(.*)$/ then attrs[:dhcp_enabled] = 1
when /^\s*BOOTPROTO=static\s*(.*)$/ then attrs[:dhcp_enabled] = 0
when /^\s*DEVICE\s*=\s*(.*)$/ then attrs[:device] = $1
when /^\s*HWADDR\s*=\s*(.*)$/ then attrs[:hwaddr] = $1
# static setting will have these entries
when /^\s*IPADDR\s*=\s*(.*)$/ then attrs[:ipaddress] = $1
when /^\s*NETMASK\s*=\s*(.*)$/ then attrs[:subnet_mask] = $1
# static setting might have these entries
when /^\s*BROADCAST\s*=\s*(.*)$/ then attrs[:broadcast] = $1
when /^\s*NETWORK\s*=\s*(.*)$/ then attrs[:network] = $1
end
end
if attrs[:dhcp_enabled] == 1
read_file(fs, File.join(DHCLIENTFILE, "dhclient-eth0.leases")) do |line|
case line
when /^\s*fixed-address\s*(.*)\;$/ then attrs[:ipaddress] = $1
when /^\s*option subnet-mask\s*(.*)\;$/ then attrs[:subnet_mask] = $1
when /^\s*option routers\s*(.*)\;$/ then attrs[:default_gateway] = $1
when /^\s*option domain-name-servers\s*(.*)\;$/ then attrs[:dns_server] = $1
when /^\s*option dhcp-server-identifier\s*(.*)\;$/ then attrs[:dhcp_server] = $1
when /^\s*option domain-name\s*"*(.*)"\;$/ then attrs[:domain] = $1
when /^\s*expire\s*[0-9]?\s*(.*)\;$/ then attrs[:lease_expires] = $1
when /^\s*renew\s*[0-9]?\s*(.*)\;$/ then attrs[:lease_obtained] = $1
end
end
end
fix_attr_values(attrs)
@networks << attrs
end
def networking_hercules(fs, attrs)
read_file(fs, File.join(DEBIANIFCFGILE, "interfaces")) do |line|
case line
when /^\s*iface eth0 inet dhcp\s*(.*)$/ then attrs[:dhcp_enabled] = 1
when /^\s*iface eth0 inet static\s*(.*)$/ then attrs[:dhcp_enabled] = 0
end
end
fix_attr_values(attrs)
@networks << attrs
end
def toXml(doc = nil)
doc = MiqXml.createDoc(nil) unless doc
doc.add_element(:os, @os)
networksToXml(doc)
doc
end
def networksToXml(doc = nil)
doc = MiqXml.createDoc(nil) unless doc
unless @networks.empty?
node = doc.add_element(:networks)
@networks.each do |n|
[:hwaddr, :network, :device, :broadcast].each { |key| n.delete(key) }
node.add_element(:network, n)
end
end
doc
end
def read_file(fs, filename)
if fs.fileExists?(filename)
file_content = ""
fs.fileOpen(filename) { |fo| file_content = fo.read }
unless file_content.nil?
file_content.each_line { |line| yield(line.chomp) }
end
end
end
def fix_attr_values(attrs)
# Clean the lease times and check they are in a reasonable range
[:lease_obtained, :lease_expires].each do |t|
if attrs[t] && attrs[t].to_i >= 0 && attrs[t].to_i < 0x80000000
attrs[t] = Time.parse(attrs[t]).utc.iso8601
else
attrs.delete(t)
end
end
attrs[:dns_server].gsub!(/(,)/) { (' ') } unless attrs[:dns_server].nil?
end
end # class OSInfo
end # module MiqLinux