ohai 0.5.8 → 0.6.0.beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/Rakefile +16 -48
  2. data/bin/ohai +1 -1
  3. data/lib/ohai.rb +1 -3
  4. data/lib/ohai/mash.rb +211 -0
  5. data/lib/ohai/mixin/command.rb +157 -44
  6. data/lib/ohai/mixin/ec2_metadata.rb +87 -0
  7. data/lib/ohai/plugins/c.rb +16 -13
  8. data/lib/ohai/plugins/chef.rb +2 -1
  9. data/lib/ohai/plugins/cloud.rb +25 -0
  10. data/lib/ohai/plugins/darwin/network.rb +10 -1
  11. data/lib/ohai/plugins/dmi.rb +100 -37
  12. data/lib/ohai/plugins/dmi_common.rb +117 -0
  13. data/lib/ohai/plugins/ec2.rb +12 -61
  14. data/lib/ohai/plugins/eucalyptus.rb +65 -0
  15. data/lib/ohai/plugins/freebsd/network.rb +11 -2
  16. data/lib/ohai/plugins/java.rb +4 -4
  17. data/lib/ohai/plugins/linux/filesystem.rb +24 -0
  18. data/lib/ohai/plugins/linux/network.rb +14 -1
  19. data/lib/ohai/plugins/linux/platform.rb +3 -0
  20. data/lib/ohai/plugins/linux/virtualization.rb +28 -6
  21. data/lib/ohai/plugins/netbsd/network.rb +10 -1
  22. data/lib/ohai/plugins/network.rb +3 -1
  23. data/lib/ohai/plugins/ohai.rb +1 -0
  24. data/lib/ohai/plugins/openbsd/network.rb +10 -1
  25. data/lib/ohai/plugins/ruby.rb +1 -1
  26. data/lib/ohai/plugins/sigar/filesystem.rb +2 -0
  27. data/lib/ohai/plugins/solaris2/dmi.rb +176 -0
  28. data/lib/ohai/plugins/solaris2/filesystem.rb +101 -0
  29. data/lib/ohai/plugins/solaris2/hostname.rb +10 -1
  30. data/lib/ohai/plugins/solaris2/network.rb +6 -1
  31. data/lib/ohai/plugins/solaris2/uptime.rb +36 -0
  32. data/lib/ohai/plugins/solaris2/virtualization.rb +91 -0
  33. data/lib/ohai/plugins/virtualization.rb +1 -1
  34. data/lib/ohai/plugins/windows/network.rb +17 -11
  35. data/lib/ohai/system.rb +22 -32
  36. data/lib/ohai/version.rb +23 -0
  37. data/spec/ohai/plugins/c_spec.rb +58 -7
  38. data/spec/ohai/plugins/cloud_spec.rb +24 -0
  39. data/spec/ohai/plugins/dmi_spec.rb +107 -47
  40. data/spec/ohai/plugins/ec2_spec.rb +3 -3
  41. data/spec/ohai/plugins/eucalyptus_spec.rb +84 -0
  42. data/spec/ohai/plugins/java_spec.rb +55 -2
  43. data/spec/ohai/plugins/linux/platform_spec.rb +13 -0
  44. data/spec/ohai/plugins/linux/virtualization_spec.rb +47 -6
  45. data/spec/ohai/plugins/perl_spec.rb +15 -14
  46. data/spec/ohai/plugins/rackspace_spec.rb +14 -14
  47. data/spec/ohai/plugins/solaris2/hostname_spec.rb +3 -8
  48. data/spec/ohai/plugins/solaris2/kernel_spec.rb +6 -6
  49. data/spec/ohai/plugins/solaris2/network_spec.rb +22 -22
  50. data/spec/ohai/plugins/solaris2/virtualization_spec.rb +133 -0
  51. data/spec/spec_helper.rb +5 -13
  52. metadata +182 -179
@@ -19,78 +19,26 @@
19
19
 
20
20
  provides "ec2"
21
21
 
22
- require 'open-uri'
23
- require 'socket'
22
+ require 'ohai/mixin/ec2_metadata'
24
23
 
25
24
  require_plugin "hostname"
26
25
  require_plugin "kernel"
27
26
  require_plugin "network"
28
27
 
29
- EC2_METADATA_ADDR = "169.254.169.254" unless defined?(EC2_METADATA_ADDR)
30
- EC2_METADATA_URL = "http://#{EC2_METADATA_ADDR}/2008-02-01/meta-data" unless defined?(EC2_METADATA_URL)
31
- EC2_USERDATA_URL = "http://#{EC2_METADATA_ADDR}/2008-02-01/user-data" unless defined?(EC2_USERDATA_URL)
32
- EC2_ARRAY_VALUES = %w(security-groups)
33
-
34
- def can_metadata_connect?(addr, port, timeout=2)
35
- t = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0)
36
- saddr = Socket.pack_sockaddr_in(port, addr)
37
- connected = false
38
-
39
- begin
40
- t.connect_nonblock(saddr)
41
- rescue Errno::EINPROGRESS
42
- r,w,e = IO::select(nil,[t],nil,timeout)
43
- if !w.nil?
44
- connected = true
45
- else
46
- begin
47
- t.connect_nonblock(saddr)
48
- rescue Errno::EISCONN
49
- t.close
50
- connected = true
51
- rescue SystemCallError
52
- end
53
- end
54
- rescue SystemCallError
55
- end
56
-
57
- connected
58
- end
28
+ extend Ohai::Mixin::Ec2Metadata
59
29
 
60
30
  def has_ec2_mac?
61
31
  network[:interfaces].values.each do |iface|
62
32
  unless iface[:arp].nil?
63
- return true if iface[:arp].value?("fe:ff:ff:ff:ff:ff")
33
+ has_mac = iface[:arp].value?("fe:ff:ff:ff:ff:ff")
34
+ Ohai::Log.debug("has_ec2_mac? == true")
35
+ return true if has_mac
64
36
  end
65
37
  end
38
+ Ohai::Log.debug("has_ec2_mac? == false")
66
39
  false
67
40
  end
68
41
 
69
- def metadata(id='')
70
- OpenURI.open_uri("#{EC2_METADATA_URL}/#{id}").read.split("\n").each do |o|
71
- key = "#{id}#{o.gsub(/\=.*$/, '/')}"
72
- if key[-1..-1] != '/'
73
- ec2[key.gsub(/\-|\//, '_').to_sym] =
74
- if EC2_ARRAY_VALUES.include? key
75
- OpenURI.open_uri("#{EC2_METADATA_URL}/#{key}").read.split("\n")
76
- else
77
- OpenURI.open_uri("#{EC2_METADATA_URL}/#{key}").read
78
- end
79
- else
80
- metadata(key)
81
- end
82
- end
83
- end
84
-
85
- def userdata()
86
- ec2[:userdata] = nil
87
- # assumes the only expected error is the 404 if there's no user-data
88
- begin
89
- ec2[:userdata] = OpenURI.open_uri("#{EC2_USERDATA_URL}/").read
90
- rescue OpenURI::HTTPError
91
- end
92
- end
93
-
94
42
  def looks_like_ec2?
95
43
  # Try non-blocking connect so we don't "block" if
96
44
  # the Xen environment is *not* EC2
@@ -98,8 +46,11 @@ def looks_like_ec2?
98
46
  end
99
47
 
100
48
  if looks_like_ec2?
49
+ Ohai::Log.debug("looks_like_ec2? == true")
101
50
  ec2 Mash.new
102
- self.metadata
103
- self.userdata
51
+ self.fetch_metadata.each {|k, v| ec2[k] = v }
52
+ ec2[:userdata] = self.fetch_userdata
53
+ else
54
+ Ohai::Log.debug("looks_like_ec2? == false")
55
+ false
104
56
  end
105
-
@@ -0,0 +1,65 @@
1
+ #
2
+ # Author:: Tim Dysinger (<tim@dysinger.net>)
3
+ # Author:: Benjamin Black (<bb@opscode.com>)
4
+ # Author:: Christopher Brown (<cb@opscode.com>)
5
+ # Copyright:: Copyright (c) 2009 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+
20
+ provides "eucalyptus"
21
+
22
+ require 'ohai/mixin/ec2_metadata'
23
+
24
+ require_plugin "hostname"
25
+ require_plugin "kernel"
26
+ require_plugin "network"
27
+
28
+ extend Ohai::Mixin::Ec2Metadata
29
+
30
+ def get_mac_address(addresses)
31
+ detected_addresses = addresses.detect { |address, keypair| keypair == {"family"=>"lladdr"} }
32
+ if detected_addresses
33
+ return detected_addresses.first
34
+ else
35
+ return ""
36
+ end
37
+ end
38
+
39
+ def has_euca_mac?
40
+ network[:interfaces].values.each do |iface|
41
+ has_mac = (get_mac_address(iface[:addresses]) =~ /^[dD]0:0[dD]:/)
42
+ Ohai::Log.debug("has_euca_mac? == #{!!has_mac}")
43
+ return true if has_mac
44
+ end
45
+
46
+ Ohai::Log.debug("has_euca_mac? == false")
47
+ false
48
+ end
49
+
50
+ def looks_like_euca?
51
+ # Try non-blocking connect so we don't "block" if
52
+ # the Xen environment is *not* EC2
53
+ has_euca_mac? && can_metadata_connect?(EC2_METADATA_ADDR,80)
54
+ end
55
+
56
+ if looks_like_euca?
57
+ Ohai::Log.debug("looks_like_euca? == true")
58
+ eucalyptus Mash.new
59
+ self.fetch_metadata.each {|k, v| eucalyptus[k] = v }
60
+ eucalyptus[:userdata] = self.fetch_userdata
61
+ else
62
+ Ohai::Log.debug("looks_like_euca? == false")
63
+ false
64
+ end
65
+
@@ -18,7 +18,16 @@
18
18
 
19
19
  provides "network", "counters/network"
20
20
 
21
- network[:default_interface] = from("route -n get default \| grep interface: \| awk \'/: / \{print \$2\}\'")
21
+ from("route -n get default").split("\n").each do |line|
22
+ if line =~ /(\w+): ([\w\.]+)/
23
+ case $1
24
+ when "gateway"
25
+ network[:default_gateway] = $2
26
+ when "interface"
27
+ network[:default_interface] = $2
28
+ end
29
+ end
30
+ end
22
31
 
23
32
  iface = Mash.new
24
33
  popen4("/sbin/ifconfig -a") do |pid, stdin, stdout, stderr|
@@ -109,4 +118,4 @@ popen4("netstat -ibdn") do |pid, stdin, stdout, stderr|
109
118
  end
110
119
  end
111
120
 
112
- counters[:network][:interfaces] = net_counters
121
+ counters[:network][:interfaces] = net_counters
@@ -28,10 +28,10 @@ if status == 0
28
28
  case line
29
29
  when /java version \"([0-9\.\_]+)\"/
30
30
  java[:version] = $1
31
- when /^(.+Runtime Environment.*) \(build (.+)\)$/
32
- java[:runtime] = { "name" => $1, "build" => $2 }
33
- when /^(.+ Client VM) \(build (.+)\)$/
34
- java[:hotspot] = { "name" => $1, "build" => $2 }
31
+ when /^(.+Runtime Environment.*) \((build )?(.+)\)$/
32
+ java[:runtime] = { "name" => $1, "build" => $3 }
33
+ when /^(.+ (Client|Server) VM) \(build (.+)\)$/
34
+ java[:hotspot] = { "name" => $1, "build" => $3 }
35
35
  end
36
36
  end
37
37
 
@@ -53,5 +53,29 @@ popen4("mount -l") do |pid, stdin, stdout, stderr|
53
53
  end
54
54
  end
55
55
 
56
+ # Grab UUID from /dev/disk/by-uuid/*
57
+ popen4("ls -l /dev/disk/by-uuid/* | awk '{print $11, $9}'") do |pid, stdin, stdout, stderr|
58
+ stdin.close
59
+ stdout.each do |line|
60
+ if line =~ /^[.\/]+\/([a-z]+\d) \/.\/(.)$/
61
+ filesystem = "/dev/" + $1
62
+ fs[filesystem] = Mash.new unless fs.has_key?(filesystem)
63
+ fs[filesystem][:uuid] = $2
64
+ end
65
+ end
66
+ end
67
+
68
+ # Grab any missing mount information from /proc/mounts
69
+ File.open('/proc/mounts').each do |line|
70
+ if line =~ /^(\S+) (\S+) (\S+) (\S+) \S+ \S+$/
71
+ filesystem = $1
72
+ next if fs.has_key?(filesystem)
73
+ fs[filesystem] = Mash.new
74
+ fs[filesystem][:mount] = $2
75
+ fs[filesystem][:fs_type] = $3
76
+ fs[filesystem][:mount_options] = $4.split(",")
77
+ end
78
+ end
79
+
56
80
  # Set the filesystem data
57
81
  filesystem fs
@@ -18,7 +18,17 @@
18
18
 
19
19
  provides "network", "counters/network"
20
20
 
21
- network[:default_interface] = from("route -n \| grep -m 1 ^0.0.0.0 \| awk \'{print \$8\}\'")
21
+ begin
22
+ route_result = from("route -n \| grep -m 1 ^0.0.0.0").split(/[ \t]+/)
23
+ if route_result.last =~ /(venet\d+)/
24
+ network[:default_interface] = from("ip addr show dev #{$1} | grep -v 127.0.0.1 | grep -m 1 inet").split(/[ \t]+/).last
25
+ network[:default_gateway] = route_result[1]
26
+ else
27
+ network[:default_gateway], network[:default_interface] = route_result.values_at(1,7)
28
+ end
29
+ rescue Ohai::Exceptions::Exec
30
+ Ohai::Log.debug("Unable to determine default interface")
31
+ end
22
32
 
23
33
  def encaps_lookup(encap)
24
34
  return "Loopback" if encap.eql?("Local Loopback")
@@ -74,6 +84,9 @@ popen4("ifconfig -a") do |pid, stdin, stdout, stderr|
74
84
  if line =~ /MTU:(\d+)/
75
85
  iface[cint][:mtu] = $1
76
86
  end
87
+ if line =~ /P-t-P:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
88
+ iface[cint][:peer] = $1
89
+ end
77
90
  if line =~ /RX packets:(\d+) errors:(\d+) dropped:(\d+) overruns:(\d+) frame:(\d+)/
78
91
  net_counters[cint] = Mash.new unless net_counters[cint]
79
92
  net_counters[cint][:rx] = { "packets" => $1, "errors" => $2, "drop" => $3, "overrun" => $4, "frame" => $5 }
@@ -47,6 +47,9 @@ elsif File.exists?('/etc/gentoo-release')
47
47
  elsif File.exists?('/etc/SuSE-release')
48
48
  platform "suse"
49
49
  platform_version File.read("/etc/SuSE-release").scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join(".")
50
+ elsif File.exists?('/etc/slackware-version')
51
+ platform "slackware"
52
+ platform_version File.read("/etc/slackware-version").scan(/(\d+|\.+)/).join
50
53
  elsif File.exists?('/etc/arch-release')
51
54
  platform "arch"
52
55
  # no way to determine platform_version in a rolling release distribution
@@ -23,17 +23,17 @@ virtualization Mash.new
23
23
  # if it is possible to detect paravirt vs hardware virt, it should be put in
24
24
  # virtualization[:mechanism]
25
25
  if File.exists?("/proc/xen/capabilities") && File.read("/proc/xen/capabilities") =~ /control_d/i
26
- virtualization[:emulator] = "xen"
26
+ virtualization[:system] = "xen"
27
27
  virtualization[:role] = "host"
28
28
  elsif File.exists?("/proc/sys/xen/independent_wallclock")
29
- virtualization[:emulator] = "xen"
29
+ virtualization[:system] = "xen"
30
30
  virtualization[:role] = "guest"
31
31
  end
32
32
 
33
33
  # Detect KVM hosts by kernel module
34
34
  if File.exists?("/proc/modules")
35
35
  if File.read("/proc/modules") =~ /^kvm/
36
- virtualization[:emulator] = "kvm"
36
+ virtualization[:system] = "kvm"
37
37
  virtualization[:role] = "host"
38
38
  end
39
39
  end
@@ -45,7 +45,7 @@ end
45
45
  # Wait for reply to: http://article.gmane.org/gmane.comp.emulators.kvm.devel/27885
46
46
  if File.exists?("/proc/cpuinfo")
47
47
  if File.read("/proc/cpuinfo") =~ /QEMU Virtual CPU/
48
- virtualization[:emulator] = "kvm"
48
+ virtualization[:system] = "kvm"
49
49
  virtualization[:role] = "guest"
50
50
  end
51
51
  end
@@ -58,17 +58,39 @@ if File.exists?("/usr/sbin/dmidecode")
58
58
  case dmi_info
59
59
  when /Manufacturer: Microsoft/
60
60
  if dmi_info =~ /Product Name: Virtual Machine/
61
- virtualization[:emulator] = "virtualpc"
61
+ virtualization[:system] = "virtualpc"
62
62
  virtualization[:role] = "guest"
63
63
  end
64
64
  when /Manufacturer: VMware/
65
65
  if dmi_info =~ /Product Name: VMware Virtual Platform/
66
- virtualization[:emulator] = "vmware"
66
+ virtualization[:system] = "vmware"
67
67
  virtualization[:role] = "guest"
68
68
  end
69
+ when /Manufacturer: Xen/
70
+ if dmi_info =~ /Product Name: HVM domU/
71
+ virtualization[:system] = "xen"
72
+ virtualization[:role] = "guest"
73
+ end
69
74
  else
70
75
  nil
71
76
  end
72
77
 
73
78
  end
74
79
  end
80
+
81
+ # Detect Linux-VServer
82
+ if File.exists?("/proc/self/status")
83
+ proc_self_status = File.read("/proc/self/status")
84
+ vxid = proc_self_status.match(/^(s_context|VxID): (\d+)$/)
85
+ if vxid and vxid[2]
86
+ virtualization[:system] = "linux-vserver"
87
+ if vxid[2] == "0"
88
+ virtualization[:role] = "host"
89
+ else
90
+ virtualization[:role] = "guest"
91
+ end
92
+ end
93
+ end
94
+
95
+ # Detect OpenVZ
96
+ # something in /proc/vz/veinfo
@@ -18,7 +18,16 @@
18
18
 
19
19
  provides "network", "counters/network"
20
20
 
21
- network[:default_interface] = from("route -n get default \| grep interface: \| awk \'/: / \{print \$2\}\'")
21
+ from("route -n get default").split("\n").each do |line|
22
+ if line =~ /(\w+): ([\w\.]+)/
23
+ case $1
24
+ when "gateway"
25
+ network[:default_gateway] = $2
26
+ when "interface"
27
+ network[:default_interface] = $2
28
+ end
29
+ end
30
+ end
22
31
 
23
32
  iface = Mash.new
24
33
  popen4("/sbin/ifconfig -a") do |pid, stdin, stdout, stderr|
@@ -36,13 +36,15 @@ def find_ip_and_mac(addresses)
36
36
  [ip, mac]
37
37
  end
38
38
 
39
- unless network[:default_interface].nil?
39
+ if network[:default_interface]
40
+ Ohai::Log.debug("Using default interface for default ip and mac address")
40
41
  im = find_ip_and_mac(network["interfaces"][network[:default_interface]]["addresses"])
41
42
  ipaddress im.shift
42
43
  macaddress im.shift
43
44
  else
44
45
  network["interfaces"].keys.sort.each do |iface|
45
46
  if network["interfaces"][iface]["encapsulation"].eql?("Ethernet")
47
+ Ohai::Log.debug("Picking ip and mac address from first Ethernet interface")
46
48
  im = find_ip_and_mac(network["interfaces"][iface]["addresses"])
47
49
  ipaddress im.shift
48
50
  macaddress im.shift
@@ -22,3 +22,4 @@ provides "ohai"
22
22
  self[:chef_packages] = Mash.new unless self[:chef_packages]
23
23
  self[:chef_packages][:ohai] = Mash.new
24
24
  self[:chef_packages][:ohai][:version] = Ohai::VERSION
25
+ self[:chef_packages][:ohai][:ohai_root] = Ohai::OHAI_ROOT
@@ -18,7 +18,16 @@
18
18
 
19
19
  provides "network", "counters/network"
20
20
 
21
- network[:default_interface] = from("route -n get default \| grep interface: \| awk \'/: / \{print \$2\}\'")
21
+ from("route -n get default").split("\n").each do |line|
22
+ if line =~ /(\w+): ([\w\.]+)/
23
+ case $1
24
+ when "gateway"
25
+ network[:default_gateway] = $2
26
+ when "interface"
27
+ network[:default_interface] = $2
28
+ end
29
+ end
30
+ end
22
31
 
23
32
  iface = Mash.new
24
33
  popen4("/sbin/ifconfig -a") do |pid, stdin, stdout, stderr|
@@ -58,7 +58,7 @@ result = run_ruby "puts %Q(#{env_string})"
58
58
  # Parse results to plugin hash
59
59
  result.split(',').each do |entry|
60
60
  key, value = entry.split('=')
61
- languages[:ruby][key.to_sym] = value
61
+ languages[:ruby][key.to_sym] = value || ""
62
62
  end
63
63
 
64
64
  # Perform one more (conditional) query
@@ -36,6 +36,8 @@ sigar.file_system_list.each do |fsys|
36
36
  fs[filesystem][:kb_used] = ((usage.total - usage.free) / 1024).to_s
37
37
  fs[filesystem][:kb_available] = (usage.free / 1024).to_s
38
38
  fs[filesystem][:percent_used] = (usage.use_percent * 100).to_s + '%'
39
+ rescue SystemExit => e
40
+ raise
39
41
  rescue Exception => e
40
42
  #e.g. floppy or cdrom drive
41
43
  end
@@ -0,0 +1,176 @@
1
+ #
2
+ # Author:: Kurt Yoder (ktyopscode@yoderhome.com)
3
+ # Copyright:: Copyright (c) 2010 Kurt Yoder
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require_plugin "dmi"
20
+
21
+ # if we already have a "dmi" with keys (presumably from dmidecode), don't try smbios
22
+ # note that a single key just means dmidecode exited with its version
23
+ if (dmi.class.to_s == 'Mash') and (dmi.keys.length > 1)
24
+ Ohai::Log.debug('skipping smbios output, since DMI information has already been provided')
25
+ return
26
+ end
27
+
28
+ dmi Mash.new
29
+
30
+ # bad Solaris shows strings defined by system instead of SMB IDs
31
+ # this is what the *real* IDs are:
32
+ # pulled from http://src.opensolaris.org/source/xref/nwam/nwam1/usr/src/uts/common/sys/smbios.h
33
+ smb_to_id = {
34
+ 'SMB_TYPE_BIOS' => 0, # BIOS information (R)
35
+ 'SMB_TYPE_SYSTEM' => 1, # system information (R)
36
+ 'SMB_TYPE_BASEBOARD' => 2, # base board
37
+ 'SMB_TYPE_CHASSIS' => 3, # system enclosure or chassis (R)
38
+ 'SMB_TYPE_PROCESSOR' => 4, # processor (R)
39
+ 'SMB_TYPE_MEMCTL' => 5, # memory controller (O)
40
+ 'SMB_TYPE_MEMMOD' => 6, # memory module (O)
41
+ 'SMB_TYPE_CACHE' => 7, # processor cache (R)
42
+ 'SMB_TYPE_PORT' => 8, # port connector
43
+ 'SMB_TYPE_SLOT' => 9, # upgradeable system slot (R)
44
+ 'SMB_TYPE_OBDEVS' => 10, # on-board devices
45
+ 'SMB_TYPE_OEMSTR' => 11, # OEM string table
46
+ 'SMB_TYPE_SYSCONFSTR' => 12, # system configuration string table
47
+ 'SMB_TYPE_LANG' => 13, # BIOS language information
48
+ 'SMB_TYPE_GROUP' => 14, # group associations
49
+ 'SMB_TYPE_EVENTLOG' => 15, # system event log
50
+ 'SMB_TYPE_MEMARRAY' => 16, # physical memory array (R)
51
+ 'SMB_TYPE_MEMDEVICE' => 17, # memory device (R)
52
+ 'SMB_TYPE_MEMERR32' => 18, # 32-bit memory error information
53
+ 'SMB_TYPE_MEMARRAYMAP' => 19, # memory array mapped address (R)
54
+ 'SMB_TYPE_MEMDEVICEMAP' => 20, # memory device mapped address (R)
55
+ 'SMB_TYPE_POINTDEV' => 21, # built-in pointing device
56
+ 'SMB_TYPE_BATTERY' => 22, # portable battery
57
+ 'SMB_TYPE_RESET' => 23, # system reset settings
58
+ 'SMB_TYPE_SECURITY' => 24, # hardware security settings
59
+ 'SMB_TYPE_POWERCTL' => 25, # system power controls
60
+ 'SMB_TYPE_VPROBE' => 26, # voltage probe
61
+ 'SMB_TYPE_COOLDEV' => 27, # cooling device
62
+ 'SMB_TYPE_TPROBE' => 28, # temperature probe
63
+ 'SMB_TYPE_IPROBE' => 29, # current probe
64
+ 'SMB_TYPE_OOBRA' => 30, # out-of-band remote access facility
65
+ 'SMB_TYPE_BIS' => 31, # boot integrity services
66
+ 'SMB_TYPE_BOOT' => 32, # system boot status (R)
67
+ 'SMB_TYPE_MEMERR64' => 33, # 64-bit memory error information
68
+ 'SMB_TYPE_MGMTDEV' => 34, # management device
69
+ 'SMB_TYPE_MGMTDEVCP' => 35, # management device component
70
+ 'SMB_TYPE_MGMTDEVDATA' => 36, # management device threshold data
71
+ 'SMB_TYPE_MEMCHAN' => 37, # memory channel
72
+ 'SMB_TYPE_IPMIDEV' => 38, # IPMI device information
73
+ 'SMB_TYPE_POWERSUP' => 39, # system power supply
74
+ 'SMB_TYPE_INACTIVE' => 126, # inactive table entry
75
+ 'SMB_TYPE_EOT' => 127, # end of table
76
+ 'SMB_TYPE_OEM_LO' => 128, # start of OEM-specific type range
77
+ 'SUN_OEM_EXT_PROCESSOR' => 132, # processor extended info
78
+ 'SUN_OEM_PCIEXRC' => 138, # PCIE RootComplex/RootPort info
79
+ 'SUN_OEM_EXT_MEMARRAY' => 144, # phys memory array extended info
80
+ 'SUN_OEM_EXT_MEMDEVICE' => 145, # memory device extended info
81
+ 'SMB_TYPE_OEM_HI' => 256, # end of OEM-specific type range
82
+ }
83
+
84
+ # all output lines should fall within one of these patterns
85
+ header_type_line = /^ID\s+SIZE\s+TYPE/
86
+ header_information_line = /^(\d+)\s+(\d+)\s+(\S+)\s+\(([^\)]+)\)/
87
+ blank_line = /^\s*$/
88
+ data_key_value_line = /^ ([^:]+): (.*)/
89
+ data_key_only_line = /^ (\S.*)(:\s*)?$/
90
+ extended_data_line = /^\t(\S+) \((.+)\)/
91
+
92
+ dmi_record = nil
93
+ field = nil
94
+
95
+ popen4("smbios") do |pid, stdin, stdout, stderr|
96
+ stdin.close
97
+
98
+ # ==== EXAMPLE: ====
99
+ # ID SIZE TYPE
100
+ # 0 40 SMB_TYPE_BIOS (BIOS information)
101
+ #
102
+ # Vendor: HP
103
+ # Version String: 2.16
104
+ # ... similar lines trimmed
105
+ # Characteristics: 0x7fc9da80
106
+ # SMB_BIOSFL_PCI (PCI is supported)
107
+ # ... similar lines trimmed
108
+ # note the second level of indentation is via a *tab*
109
+ stdout.each do |raw_line|
110
+ next if header_type_line.match(raw_line)
111
+ next if blank_line.match(raw_line)
112
+
113
+ # remove/replace any characters that don't fall inside permissible ASCII range, or whitespace
114
+ line = raw_line.gsub(/[^\x20-\x7E\n\t\r]/, '.')
115
+ if (line != raw_line)
116
+ Ohai::Log.debug("converted characters from line:\n#{raw_line}")
117
+ end
118
+
119
+ if header_information = header_information_line.match(line)
120
+ dmi_record = {}
121
+
122
+ # look up SMB ID
123
+ if smb_to_id.has_key?(header_information[3])
124
+ dmi_record[:type] = DMI.id_lookup(smb_to_id[header_information[3]])
125
+
126
+ else
127
+ dmi_record[:type] = header_information[3].downcase
128
+ Ohai::Log.debug("unrecognized header type; falling back to #{dmi_record[:type]}")
129
+ end
130
+
131
+ dmi[dmi_record[:type]] = Mash.new unless dmi.has_key?(dmi_record[:type])
132
+ dmi[dmi_record[:type]][:all_records] = [] unless dmi[dmi_record[:type]].has_key?(:all_records)
133
+ dmi_record[:position] = dmi[dmi_record[:type]][:all_records].length
134
+ dmi[dmi_record[:type]][:all_records].push(Mash.new)
135
+ dmi[dmi_record[:type]][:all_records][dmi_record[:position]][:record_id] = header_information[1]
136
+ dmi[dmi_record[:type]][:all_records][dmi_record[:position]][:size] = header_information[2]
137
+ dmi[dmi_record[:type]][:all_records][dmi_record[:position]][:application_identifier] = header_information[4]
138
+ field = nil
139
+
140
+ elsif data = data_key_value_line.match(line)
141
+ if dmi_record == nil
142
+ Ohai::Log.debug("unexpected data line found before header; discarding:\n#{line}")
143
+ next
144
+ end
145
+ dmi[dmi_record[:type]][:all_records][dmi_record[:position]][data[1]] = data[2]
146
+ field = data[1]
147
+
148
+ elsif data = data_key_only_line.match(line)
149
+ if dmi_record == nil
150
+ Ohai::Log.debug("unexpected data line found before header; discarding:\n#{line}")
151
+ next
152
+ end
153
+ dmi[dmi_record[:type]][:all_records][dmi_record[:position]][data[1]] = ''
154
+ field = data[1]
155
+
156
+ elsif extended_data = extended_data_line.match(line)
157
+ if dmi_record == nil
158
+ Ohai::Log.debug("unexpected extended data line found before header; discarding:\n#{line}")
159
+ next
160
+ end
161
+ if field == nil
162
+ Ohai::Log.debug("unexpected extended data line found outside data section; discarding:\n#{line}")
163
+ next
164
+ end
165
+ # overwrite "raw" value with a new Mash
166
+ dmi[dmi_record[:type]][:all_records][dmi_record[:position]][field] = Mash.new unless dmi[dmi_record[:type]][:all_records][dmi_record[:position]][field].class.to_s == 'Mash'
167
+ dmi[dmi_record[:type]][:all_records][dmi_record[:position]][field][extended_data[1]] = extended_data[2]
168
+
169
+ else
170
+ Ohai::Log.debug("unrecognized output line; discarding:\n#{line}")
171
+
172
+ end
173
+ end
174
+ end
175
+
176
+ DMI.convenience_keys(dmi)