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