]> git.openstreetmap.org Git - chef.git/blob - cookbooks/hardware/templates/default/ohai.rb.erb
f78ce979e628a17d6e4c4228127746f412d756bc
[chef.git] / cookbooks / hardware / templates / default / ohai.rb.erb
1 Ohai.plugin(:Hardware) do
2   provides "hardware"
3
4   def read_sysctl_link(file)
5     File.basename(File.readlink(file))
6   rescue Errno::ENOENT
7   end
8
9   def read_sysctl_file(file)
10     IO.read(file).strip
11   rescue Errno::ENOENT, Errno::EINVAL
12   end
13
14   def pci_devices
15     device = nil
16
17     IO.popen(["lspci", "-Dkvmm"]).each_with_object(Mash.new) do |line, devices|
18       if line =~ /^Slot:\s+((\h{4}):(\h{2}):(\h{2}).(\h))\s*$/
19         device = {
20           :slot => Regexp.last_match(1),
21           :domain => Regexp.last_match(2),
22           :bus => Regexp.last_match(3),
23           :device => Regexp.last_match(4),
24           :function => Regexp.last_match(5)
25         }
26       elsif device && line =~ /^([A-Z]+):\s+(.*)\s*$/i
27         case Regexp.last_match(1)
28         when "Class" then device[:class_name] = Regexp.last_match(2)
29         when "Vendor" then device[:vendor_name] = Regexp.last_match(2)
30         when "Device" then device[:device_name] = Regexp.last_match(2)
31         when "SVendor" then device[:subsystem_vendor_name] = Regexp.last_match(2)
32         when "SDevice" then device[:subsystem_device_name] = Regexp.last_match(2)
33         when "PhySlot" then device[:physical_slot] = Regexp.last_match(2)
34         when "Rev" then device[:revision] = Regexp.last_match(2)
35         when "ProgIf" then device[:programming_interface] = Regexp.last_match(2)
36         when "Driver" then device[:driver] = Regexp.last_match(2)
37         when "Module" then device[:modules] = Array(device[:modules]) << Regexp.last_match(2)
38         end
39       elsif device && line =~ /^\s*$/
40         devices[device[:slot]] = device
41         device = nil
42       end
43     end
44   end
45
46   def network_devices
47     Dir.glob("/sys/class/net/*").each_with_object(Mash.new) do |device, devices|
48       name = File.basename(device)
49
50       devices[name] = {
51         :device => read_sysctl_link("#{device}/device"),
52         :duplex => read_sysctl_file("#{device}/duplex"),
53         :speed => read_sysctl_file("#{device}/speed")
54       }.delete_if { |_, v| v.nil? }
55     end
56   end
57
58   def memory_devices
59     device = nil
60
61     IO.popen(["dmidecode", "-t", "memory"]).each_with_object([]) do |line, devices|
62       if line =~ /^Memory Device\s*$/
63         device = {}
64       elsif device && line =~ /^\s+([A-Z ]+):\s+(.*)\s*$/i
65         device[Regexp.last_match(1).tr(" ", "_").downcase.to_sym] = Regexp.last_match(2).strip
66       elsif device && line =~ /^\s*$/
67         devices << device
68         device = nil
69       end
70     end
71   end
72
73   def disk_devices
74     disk = Mash.new
75
76     disk[:controllers] = []
77     disk[:arrays] = []
78     disk[:disks] = []
79
80     find_hp_disks(disk) if File.exist?("/usr/sbin/hpssacli")
81
82     disk
83   end
84
85   def find_hp_disks(devices)
86     controllers = []
87     disks = []
88
89     controller = nil
90     array = nil
91     disk = nil
92
93     IO.popen(%w(hpssacli controller all show config detail)).each do |line|
94       if line =~ /^Smart Array (\S+) /
95         controller = {
96           :id => devices[:controllers].count,
97           :model => Regexp.last_match(1),
98           :arrays => [],
99           :disks => []
100         }
101
102         devices[:controllers] << controller
103
104         controllers << controller
105
106         array = nil
107         disk = nil
108       elsif controller && line =~ /^   (\S.*):\s+(.*)$/
109         case Regexp.last_match(1)
110         when "Serial Number" then controller[:serial_number] = Regexp.last_match(2)
111         when "Hardware Revision" then controller[:hardware_version] = Regexp.last_match(2)
112         when "Firmware Version" then controller[:firmware_version] = Regexp.last_match(2)
113         when "PCI Address (Domain:Bus:Device.Function)" then controller[:pci_slot] = Regexp.last_match(2)
114         end
115       elsif controller && line =~ /^      Logical Drive: (\d+)$/
116         array = {
117           :id => devices[:arrays].count,
118           :controller => controller[:id],
119           :number => Regexp.last_match(1),
120           :disks => []
121         }
122
123         devices[:arrays] << array
124         controller[:arrays] << array[:id]
125
126         disk = nil
127       elsif controller && line =~ /^      physicaldrive (\S+) /
128         disks << Regexp.last_match(1)
129       elsif array && line =~ /^      physicaldrive (\S+)$/
130         disk = {
131           :id => devices[:disks].count,
132           :controller => controller[:id],
133           :array => array[:id],
134           :location => Regexp.last_match(1),
135           :smart_device => "cciss,#{disks.find_index(Regexp.last_match(1))}"
136         }
137
138         devices[:disks] << disk
139         controller[:disks] << disk[:id]
140         array[:disks] << disk[:id]
141       elsif disk && line =~ /^         (\S[^:]+):\s+(.*)$/
142         case Regexp.last_match(1)
143         when "Interface Type" then disk[:interface] = Regexp.last_match(2)
144         when "Size" then disk[:size] = Regexp.last_match(2)
145         when "Rotational Speed" then disk[:rpm] = Regexp.last_match(2)
146         when "Firmware Revision" then disk[:firmware_version] = Regexp.last_match(2)
147         when "Serial Number" then disk[:serial_number] = Regexp.last_match(2)
148         when "Model" then disk[:model] = Regexp.last_match(2).squeeze(" ").strip.sub(/^ATA /, "")
149         end
150       elsif array && line =~ /^         (\S[^:]+):\s+(.*)$/
151         case Regexp.last_match(1)
152         when "Size" then array[:size] = Regexp.last_match(2)
153         when "Fault Tolerance" then array[:raid_level] = Regexp.last_match(2)
154         when "Disk Name" then array[:device] = Regexp.last_match(2).strip
155         when "Mount Points" then array[:mount_point] = Regexp.last_match(2).split.first
156         when "Unique Identifier" then array[:wwn] = Regexp.last_match(2)
157         end
158       end
159     end
160
161     controllers.each do |controller|
162       if device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/cciss*").first
163         controller[:device] = File.basename(device).sub(/^cciss(\d+)$/, "/dev/cciss/c\\1d0")
164       elsif device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target0:0:0/0:0:0:0/scsi_generic/sg*").first
165         controller[:device] = "/dev/#{File.basename(device)}"
166       end
167     end
168   end
169
170   collect_data(:default) do
171     hardware Mash.new
172
173     hardware[:pci] = pci_devices
174     hardware[:network] = network_devices
175     hardware[:memory] = memory_devices
176   end
177 end