]> git.openstreetmap.org Git - chef.git/blob - cookbooks/hardware/recipes/default.rb
Allow pinning kernel versions to work around hardware / driver issues
[chef.git] / cookbooks / hardware / recipes / default.rb
1 #
2 # Cookbook Name:: hardware
3 # Recipe:: default
4 #
5 # Copyright 2012, OpenStreetMap Foundation
6 #
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
10 #
11 #     http://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18 #
19
20 include_recipe "tools"
21 include_recipe "munin"
22
23 case node[:cpu][:"0"][:vendor_id]
24 when "GenuineIntel"
25   package "intel-microcode"
26 end
27
28 case node[:cpu][:"0"][:vendor_id]
29 when "AuthenticAMD"
30   if node[:lsb][:release].to_f >= 14.04
31     package "amd64-microcode"
32   end
33 end
34
35 if node[:dmi] && node[:dmi][:system]
36   case node[:dmi][:system][:manufacturer]
37   when "empty"
38     manufacturer = node[:dmi][:base_board][:manufacturer]
39     product = node[:dmi][:base_board][:product_name]
40   else
41     manufacturer = node[:dmi][:system][:manufacturer]
42     product = node[:dmi][:system][:product_name]
43   end
44 else
45   manufacturer = "Unknown"
46   product = "Unknown"
47 end
48
49 case manufacturer
50 when "HP"
51   package "hponcfg"
52   package "hp-health"
53   unit = "1"
54   speed = "115200"
55 when "TYAN"
56   unit = "0"
57   speed = "115200"
58 when "TYAN Computer Corporation"
59   unit = "0"
60   speed = "115200"
61 when "Supermicro"
62   case product
63   when "H8DGU", "X9SCD", "X7DBU", "X7DW3", "X9DR7/E-(J)LN4F", "X9DR3-F", "X9DRW"
64     unit = "1"
65     speed = "115200"
66   else
67     unit = "0"
68     speed = "115200"
69   end
70 when "IBM"
71   unit = "0"
72   speed = "115200"
73 end
74
75 if manufacturer == "HP" && node[:lsb][:release].to_f > 11.10
76   include_recipe "git"
77
78   git "/opt/hp/hp-legacy" do
79     action :sync
80     repository "git://chef.openstreetmap.org/hp-legacy.git"
81     user "root"
82     group "root"
83   end
84
85   link "/opt/hp/hp-health/bin/hpasmd" do
86     to "/opt/hp/hp-legacy/hpasmd"
87   end
88
89   link "/usr/lib/libhpasmintrfc.so.3.0" do
90     to "/opt/hp/hp-legacy/libhpasmintrfc.so.3.0"
91   end
92
93   link "/usr/lib/libhpasmintrfc.so.3" do
94     to "libhpasmintrfc.so.3.0"
95   end
96
97   link "/usr/lib/libhpasmintrfc.so" do
98     to "libhpasmintrfc.so.3.0"
99   end
100 end
101
102 unless unit.nil?
103   file "/etc/init/ttySttyS#{unit}.conf" do
104     action :delete
105   end
106
107   template "/etc/init/ttyS#{unit}.conf" do
108     source "tty.conf.erb"
109     owner "root"
110     group "root"
111     mode 0644
112     variables :unit => unit, :speed => speed
113   end
114
115   service "ttyS#{unit}" do
116     provider Chef::Provider::Service::Upstart
117     action [:enable, :start]
118     supports :status => true, :restart => true, :reload => false
119     subscribes :restart, "template[/etc/init/ttyS#{unit}.conf]"
120   end
121 end
122
123 # if we need a different / special kernel version to make the hardware
124 # work (e.g: https://github.com/openstreetmap/operations/issues/45) then
125 # ensure that we have the package installed. the grub template will
126 # make sure that this is the default on boot.
127 unless node[:hardware][:grub][:kernel] == :latest
128   package "linux-image-#{node[:hardware][:grub][:kernel]}-generic"
129   package "linux-image-extra-#{node[:hardware][:grub][:kernel]}-generic"
130   package "linux-headers-#{node[:hardware][:grub][:kernel]}-generic"
131 end
132
133 if File.exist?("/etc/default/grub")
134   execute "update-grub" do
135     action :nothing
136     command "/usr/sbin/update-grub"
137   end
138
139   template "/etc/default/grub" do
140     source "grub.erb"
141     owner "root"
142     group "root"
143     mode 0644
144     variables :unit => unit, :speed => speed
145     notifies :run, "execute[update-grub]"
146   end
147 end
148
149 execute "update-initramfs" do
150   action :nothing
151   command "update-initramfs -u -k all"
152   user "root"
153   group "root"
154 end
155
156 template "/etc/initramfs-tools/conf.d/mdadm" do
157   source "initramfs-mdadm.erb"
158   owner "root"
159   group "root"
160   mode 0644
161   notifies :run, "execute[update-initramfs]"
162 end
163
164 package "haveged"
165 service "haveged" do
166   action [:enable, :start]
167 end
168
169 if node[:kernel][:modules].include?("ipmi_si")
170   package "ipmitool"
171 end
172
173 if node[:lsb][:release].to_f >= 12.10
174   package "irqbalance"
175
176   template "/etc/default/irqbalance" do
177     source "irqbalance.erb"
178     owner "root"
179     group "root"
180     mode 0644
181   end
182
183   service "irqbalance" do
184     action [:start, :enable]
185     supports :status => false, :restart => true, :reload => false
186     subscribes :restart, "template[/etc/default/irqbalance]"
187   end
188 end
189
190 tools_packages = []
191 status_packages = {}
192
193 node[:kernel][:modules].each_key do |modname|
194   case modname
195   when "cciss"
196     tools_packages << "hpacucli"
197     status_packages["cciss-vol-status"] ||= []
198   when "hpsa"
199     tools_packages << "hpacucli"
200     status_packages["cciss-vol-status"] ||= []
201   when "mptsas"
202     tools_packages << "lsiutil"
203     # status_packages["mpt-status"] ||= []
204   when "mpt2sas", "mpt3sas"
205     tools_packages << "sas2ircu"
206     status_packages["sas2ircu-status"] ||= []
207   when "megaraid_mm"
208     tools_packages << "megactl"
209     status_packages["megaraid-status"] ||= []
210   when "megaraid_sas"
211     tools_packages << "megacli"
212     status_packages["megaclisas-status"] ||= []
213   when "aacraid"
214     tools_packages << "arcconf"
215     status_packages["aacraid-status"] ||= []
216   when "arcmsr"
217     tools_packages << "areca"
218   end
219 end
220
221 node[:block_device].each do |name, attributes|
222   next unless attributes[:vendor] == "HP" && attributes[:model] == "LOGICAL VOLUME"
223
224   if name =~ /^cciss!(c[0-9]+)d[0-9]+$/
225     status_packages["cciss-vol-status"] |= ["cciss/#{Regexp.last_match[1]}d0"]
226   else
227     Dir.glob("/sys/block/#{name}/device/scsi_generic/*").each do |sg|
228       status_packages["cciss-vol-status"] |= [File.basename(sg)]
229     end
230   end
231 end
232
233 %w(hpacucli lsiutil sas2ircu megactl megacli arcconf).each do |tools_package|
234   if tools_packages.include?(tools_package)
235     package tools_package
236   else
237     package tools_package do
238       action :purge
239     end
240   end
241 end
242
243 if tools_packages.include?("areca")
244   include_recipe "git"
245
246   git "/opt/areca" do
247     action :sync
248     repository "git://chef.openstreetmap.org/areca.git"
249     user "root"
250     group "root"
251   end
252 else
253   directory "/opt/areca" do
254     action :delete
255     recursive true
256   end
257 end
258
259 ["cciss-vol-status", "mpt-status", "sas2ircu-status", "megaraid-status", "megaclisas-status", "aacraid-status"].each do |status_package|
260   if status_packages.include?(status_package)
261     package status_package
262
263     template "/etc/default/#{status_package}d" do
264       source "raid.default.erb"
265       owner "root"
266       group "root"
267       mode 0644
268       variables :devices => status_packages[status_package]
269     end
270
271     service "#{status_package}d" do
272       action [:start, :enable]
273       supports :status => false, :restart => true, :reload => false
274       subscribes :restart, "template[/etc/default/#{status_package}d]"
275     end
276   else
277     package status_package do
278       action :purge
279     end
280
281     file "/etc/default/#{status_package}d" do
282       action :delete
283     end
284   end
285 end
286
287 disks = []
288
289 node[:block_device].each do |name, attributes|
290   disks << { :device => name } if attributes[:vendor] == "ATA"
291 end
292
293 if status_packages["cciss-vol-status"] && File.exist?("/usr/sbin/cciss_vol_status")
294   status_packages["cciss-vol-status"].each do |device|
295     IO.popen(["cciss_vol_status", "-V", "/dev/#{device}"]).each do |line|
296       disks << { :device => device, :driver => "cciss", :id => Regexp.last_match[1].to_i - 1 } if line =~ / bay ([0-9]+) +HP /
297     end
298   end
299 end
300
301 if status_packages["megaclisas-status"]
302   controller = 0
303
304   Dir.glob("/sys/class/scsi_host/host*") do |host|
305     driver = File.new("#{host}/proc_name").read.chomp
306
307     next unless driver == "megaraid_sas"
308
309     bus = host.sub("/sys/class/scsi_host/host", "")
310     device = File.basename(Dir.glob("/sys/bus/scsi/devices/#{bus}:*/scsi_generic/*").first)
311
312     IO.popen(["megacli", "-PDList", "-a#{controller}", "-NoLog"]).each do |line|
313       disks << { :device => device, :driver => "megaraid",  :id => Regexp.last_match[1] } if line =~ /^Device Id: ([0-9]+)$/
314
315       disks.pop if line =~ /^Firmware state: Hotspare, Spun down$/
316     end
317
318     controller += 1
319   end
320 end
321
322 if tools_packages.include?("lsiutil")
323   Dir.glob("/sys/class/scsi_host/host*") do |host|
324     driver = File.new("#{host}/proc_name").read.chomp
325
326     next unless driver == "mptsas"
327
328     bus = host.sub("/sys/class/scsi_host/host", "")
329
330     Dir.glob("/sys/bus/scsi/devices/#{bus}:0:*/scsi_generic/*").each do |sg|
331       disks << { :device => File.basename(sg) }
332     end
333   end
334 end
335
336 if status_packages["sas2ircu-status"]
337   Dir.glob("/sys/class/scsi_host/host*") do |host|
338     driver = File.new("#{host}/proc_name").read.chomp
339
340     next unless driver == "mpt2sas" || driver == "mpt3sas"
341
342     bus = host.sub("/sys/class/scsi_host/host", "")
343
344     Dir.glob("/sys/bus/scsi/devices/#{bus}:0:*/scsi_generic/*").each do |sg|
345       next if File.directory?("#{sg}/../../block")
346
347       disks << { :device => File.basename(sg) }
348     end
349   end
350 end
351
352 if status_packages["aacraid-status"]
353   Dir.glob("/sys/class/scsi_host/host*") do |host|
354     driver = File.new("#{host}/proc_name").read.chomp
355
356     next unless driver == "aacraid"
357
358     bus = host.sub("/sys/class/scsi_host/host", "")
359
360     Dir.glob("/sys/bus/scsi/devices/#{bus}:1:*/scsi_generic/*").each do |sg|
361       disks << { :device => File.basename(sg) }
362     end
363   end
364 end
365
366 if tools_packages.include?("areca") && File.exist?("/opt/areca/x86_64/cli64")
367   device = IO.popen(["lsscsi", "-g"]).grep(%r{Areca +RAID controller .*/dev/(sg[0-9]+)}) do
368     Regexp.last_match[1]
369   end.first
370
371   IO.popen(["/opt/areca/x86_64/cli64", "disk", "info"]).each do |line|
372     next if line =~ /N\.A\./
373
374     if line =~ /^ +[0-9]+ +0*([0-9]+) +(?:Slot#|SLOT )0*([0-9]+) +/
375       enc = Regexp.last_match[1]
376       slot = Regexp.last_match[2]
377
378       disks << { :device => device, :driver => "areca", :id => "#{slot}/#{enc}" }
379     elsif line =~ /^ +([0-9]+) +[0-9]+ +/
380       disks << { :device => device, :driver => "areca", :id => Regexp.last_match[1] }
381     end
382   end
383 end
384
385 disks.each do |disk|
386   if disk[:device] =~ %r{^cciss/(.*)$}
387     id = File.read("/sys/bus/cciss/devices/#{Regexp.last_match[1]}/unique_id").chomp
388
389     disk[:munin] = "cciss-3#{id.downcase}"
390   else
391     disk[:munin] = disk[:device]
392   end
393
394   if disk[:id]
395     disk[:munin] = "#{disk[:munin]}-#{disk[:id].to_s.tr('/', ':')}"
396   end
397
398   disk[:hddtemp] = disk[:munin].tr("-:", "_")
399 end
400
401 if disks.count > 0
402   package "smartmontools"
403
404   template "/etc/smartd.conf" do
405     source "smartd.conf.erb"
406     owner "root"
407     group "root"
408     mode 0644
409     variables :disks => disks
410     notifies :reload, "service[smartmontools]"
411   end
412
413   template "/etc/default/smartmontools" do
414     source "smartmontools.erb"
415     owner "root"
416     group "root"
417     mode 0644
418     notifies :restart, "service[smartmontools]"
419   end
420
421   service "smartmontools" do
422     action [:enable, :start]
423     supports :status => true, :restart => true, :reload => true
424   end
425
426   # Don't try and do munin monitoring of disks behind
427   # an Areca controller as they only allow one thing to
428   # talk to the controller at a time and smartd will
429   # throw errors if it clashes with munin
430   disks = disks.reject { |disk| disk[:driver] == "areca" }
431
432   disks.each do |disk|
433     munin_plugin "smart_#{disk[:munin]}" do
434       target "smart_"
435       conf "munin.smart.erb"
436       conf_variables :disk => disk
437     end
438   end
439
440   munin_plugin "hddtemp_smartctl" do
441     conf "munin.hddtemp.erb"
442     conf_variables :disks => disks
443   end
444 else
445   service "smartmontools" do
446     action [:stop, :disable]
447   end
448
449   munin_plugin "hddtemp_smartctl" do
450     action :delete
451   end
452 end
453
454 plugins = Dir.glob("/etc/munin/plugins/smart_*").map { |p| File.basename(p) } -
455           disks.map { |d| "smart_#{d[:munin]}" }
456
457 plugins.each do |plugin|
458   munin_plugin plugin do
459     action :delete
460   end
461 end
462
463 if File.exist?("/etc/mdadm/mdadm.conf")
464   mdadm_conf = edit_file "/etc/mdadm/mdadm.conf" do |line|
465     line.gsub!(/^MAILADDR .*$/, "MAILADDR admins@openstreetmap.org")
466
467     line
468   end
469
470   file "/etc/mdadm/mdadm.conf" do
471     owner "root"
472     group "root"
473     mode 0644
474     content mdadm_conf
475   end
476
477   service "mdadm" do
478     action :nothing
479     subscribes :restart, "file[/etc/mdadm/mdadm.conf]"
480   end
481 end
482
483 template "/etc/modules" do
484   source "modules.erb"
485   owner "root"
486   group "root"
487   mode 0644
488 end
489
490 if node[:lsb][:release].to_f <= 12.10
491   service "module-init-tools" do
492     provider Chef::Provider::Service::Upstart
493     action :nothing
494     subscribes :start, "template[/etc/modules]"
495   end
496 else
497   service "kmod" do
498     provider Chef::Provider::Service::Upstart
499     action :nothing
500     subscribes :start, "template[/etc/modules]"
501   end
502 end
503
504 if node[:hardware][:watchdog]
505   package "watchdog"
506
507   template "/etc/default/watchdog" do
508     source "watchdog.erb"
509     owner "root"
510     group "root"
511     mode 0644
512     variables :module => node[:hardware][:watchdog]
513   end
514
515   service "watchdog" do
516     action [:enable, :start]
517   end
518 end
519
520 unless Dir.glob("/sys/class/hwmon/hwmon*").empty?
521   package "lm-sensors"
522
523   execute "/etc/sensors.d/chef.conf" do
524     action :nothing
525     command "/usr/bin/sensors -s"
526     user "root"
527     group "root"
528   end
529
530   template "/etc/sensors.d/chef.conf" do
531     source "sensors.conf.erb"
532     owner "root"
533     group "root"
534     mode 0644
535     notifies :run, "execute[/etc/sensors.d/chef.conf]"
536   end
537 end