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