]> git.openstreetmap.org Git - chef.git/blob - cookbooks/hardware/recipes/default.rb
Downgrade hp-health package due to startup issues in latest release
[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 ohai_plugin "hardware" do
24   template "ohai.rb.erb"
25 end
26
27 case node[:cpu][:"0"][:vendor_id]
28 when "GenuineIntel"
29   package "intel-microcode"
30 end
31
32 case node[:cpu][:"0"][:vendor_id]
33 when "AuthenticAMD"
34   if node[:lsb][:release].to_f >= 14.04
35     package "amd64-microcode"
36   end
37 end
38
39 if node[:dmi] && node[:dmi][:system]
40   case node[:dmi][:system][:manufacturer]
41   when "empty"
42     manufacturer = node[:dmi][:base_board][:manufacturer]
43     product = node[:dmi][:base_board][:product_name]
44   else
45     manufacturer = node[:dmi][:system][:manufacturer]
46     product = node[:dmi][:system][:product_name]
47   end
48 else
49   manufacturer = "Unknown"
50   product = "Unknown"
51 end
52
53 units = []
54
55 if node[:roles].include?("bytemark") || node[:roles].include?("exonetric")
56   units << "0"
57 end
58
59 case manufacturer
60 when "HP"
61   package "hponcfg"
62
63   # Downgrade hp-health to 10.0.0.1.3-4. as 10.40-1815.49 has issues with reliable startup
64   package "hp-health" do
65     action :install
66     version "10.0.0.1.3-4."
67     notifies :restart, "service[hp-health]"
68   end
69
70   service "hp-health" do
71     action [:enable, :start]
72     supports :status => true, :restart => true, :reload => true
73   end
74
75   units << "1"
76 when "TYAN"
77   units << "0"
78 when "TYAN Computer Corporation"
79   units << "0"
80 when "Supermicro"
81   case product
82   when "H8DGU", "X9SCD", "X7DBU", "X7DW3", "X9DR7/E-(J)LN4F", "X9DR3-F", "X9DRW", "SYS-2028U-TN24R4T+"
83     units << "1"
84   else
85     units << "0"
86   end
87 when "IBM"
88   units << "0"
89 end
90
91 # Remove legacy HP G4 support which breaks modern hp-health 10.4
92 if manufacturer == "HP"
93   %w(/opt/hp/hp-health/bin/hpasmd /usr/lib/libhpasmintrfc.so.3.0 %/usr/lib/libhpasmintrfc.so.3 /usr/lib/libhpasmintrfc.so).each do |filename|
94     file filename do
95       action :delete
96     end
97   end
98
99   directory "/opt/hp/hp-legacy" do
100     action :delete
101     recursive true
102   end
103 end
104
105 units.sort.uniq.each do |unit|
106   if node[:lsb][:release].to_f >= 16.04
107     service "serial-getty@ttyS#{unit}" do
108       action [:enable, :start]
109     end
110   else
111     file "/etc/init/ttySttyS#{unit}.conf" do
112       action :delete
113     end
114
115     template "/etc/init/ttyS#{unit}.conf" do
116       source "tty.conf.erb"
117       owner "root"
118       group "root"
119       mode 0o644
120       variables :unit => unit
121     end
122
123     service "ttyS#{unit}" do
124       provider Chef::Provider::Service::Upstart
125       action [:enable, :start]
126       supports :status => true, :restart => true, :reload => false
127       subscribes :restart, "template[/etc/init/ttyS#{unit}.conf]"
128     end
129   end
130 end
131
132 # if we need a different / special kernel version to make the hardware
133 # work (e.g: https://github.com/openstreetmap/operations/issues/45) then
134 # ensure that we have the package installed. the grub template will
135 # make sure that this is the default on boot.
136 if node[:hardware][:grub][:kernel]
137   kernel_version = node[:hardware][:grub][:kernel]
138
139   package "linux-image-#{kernel_version}-generic"
140   package "linux-image-extra-#{kernel_version}-generic"
141   package "linux-headers-#{kernel_version}-generic"
142
143   boot_device = IO.popen(["df", "/boot"]).readlines.last.split.first
144   boot_uuid = IO.popen(["blkid", "-o", "value", "-s", "UUID", boot_device]).readlines.first.chomp
145   grub_entry = "gnulinux-advanced-#{boot_uuid}>gnulinux-#{kernel_version}-advanced-#{boot_uuid}"
146 else
147   grub_entry = "0"
148 end
149
150 if File.exist?("/etc/default/grub")
151   execute "update-grub" do
152     action :nothing
153     command "/usr/sbin/update-grub"
154   end
155
156   template "/etc/default/grub" do
157     source "grub.erb"
158     owner "root"
159     group "root"
160     mode 0o644
161     variables :units => units, :entry => grub_entry
162     notifies :run, "execute[update-grub]"
163   end
164 end
165
166 execute "update-initramfs" do
167   action :nothing
168   command "update-initramfs -u -k all"
169   user "root"
170   group "root"
171 end
172
173 template "/etc/initramfs-tools/conf.d/mdadm" do
174   source "initramfs-mdadm.erb"
175   owner "root"
176   group "root"
177   mode 0o644
178   notifies :run, "execute[update-initramfs]"
179 end
180
181 package "haveged"
182 service "haveged" do
183   action [:enable, :start]
184 end
185
186 if node[:kernel][:modules].include?("ipmi_si")
187   package "ipmitool"
188 end
189
190 if node[:lsb][:release].to_f >= 12.10
191   package "irqbalance"
192
193   template "/etc/default/irqbalance" do
194     source "irqbalance.erb"
195     owner "root"
196     group "root"
197     mode 0o644
198   end
199
200   service "irqbalance" do
201     action [:start, :enable]
202     supports :status => false, :restart => true, :reload => false
203     subscribes :restart, "template[/etc/default/irqbalance]"
204   end
205 end
206
207 tools_packages = []
208 status_packages = {}
209
210 node[:kernel][:modules].each_key do |modname|
211   case modname
212   when "cciss"
213     tools_packages << "hpssacli"
214     status_packages["cciss-vol-status"] ||= []
215   when "hpsa"
216     tools_packages << "hpssacli"
217     status_packages["cciss-vol-status"] ||= []
218   when "mptsas"
219     tools_packages << "lsiutil"
220     # status_packages["mpt-status"] ||= []
221   when "mpt2sas", "mpt3sas"
222     tools_packages << "sas2ircu"
223     status_packages["sas2ircu-status"] ||= []
224   when "megaraid_mm"
225     tools_packages << "megactl"
226     status_packages["megaraid-status"] ||= []
227   when "megaraid_sas"
228     tools_packages << "megacli"
229     status_packages["megaclisas-status"] ||= []
230   when "aacraid"
231     tools_packages << "arcconf"
232     status_packages["aacraid-status"] ||= []
233   when "arcmsr"
234     tools_packages << "areca"
235   end
236 end
237
238 node[:block_device].each do |name, attributes|
239   next unless attributes[:vendor] == "HP" && attributes[:model] == "LOGICAL VOLUME"
240
241   if name =~ /^cciss!(c[0-9]+)d[0-9]+$/
242     status_packages["cciss-vol-status"] |= ["cciss/#{Regexp.last_match[1]}d0"]
243   else
244     Dir.glob("/sys/block/#{name}/device/scsi_generic/*").each do |sg|
245       status_packages["cciss-vol-status"] |= [File.basename(sg)]
246     end
247   end
248 end
249
250 %w(hpssacli lsiutil sas2ircu megactl megacli arcconf).each do |tools_package|
251   if tools_packages.include?(tools_package)
252     package tools_package
253   else
254     package tools_package do
255       action :purge
256     end
257   end
258 end
259
260 if tools_packages.include?("areca")
261   include_recipe "git"
262
263   git "/opt/areca" do
264     action :sync
265     repository "git://chef.openstreetmap.org/areca.git"
266     user "root"
267     group "root"
268   end
269 else
270   directory "/opt/areca" do
271     action :delete
272     recursive true
273   end
274 end
275
276 ["cciss-vol-status", "mpt-status", "sas2ircu-status", "megaraid-status", "megaclisas-status", "aacraid-status"].each do |status_package|
277   if status_packages.include?(status_package)
278     package status_package
279
280     template "/etc/default/#{status_package}d" do
281       source "raid.default.erb"
282       owner "root"
283       group "root"
284       mode 0o644
285       variables :devices => status_packages[status_package]
286     end
287
288     service "#{status_package}d" do
289       action [:start, :enable]
290       supports :status => false, :restart => true, :reload => false
291       subscribes :restart, "template[/etc/default/#{status_package}d]"
292     end
293   else
294     package status_package do
295       action :purge
296     end
297
298     file "/etc/default/#{status_package}d" do
299       action :delete
300     end
301   end
302 end
303
304 disks = if node[:hardware][:disk]
305           node[:hardware][:disk][:disks]
306         else
307           []
308         end
309
310 intel_ssds = disks.select { |d| d[:vendor] == "INTEL" && d[:model] =~ /^SSD/ }
311
312 nvmes = if node[:hardware][:pci]
313           node[:hardware][:pci].values.select { |pci| pci[:driver] == "nvme" }
314         else
315           []
316         end
317
318 intel_nvmes = nvmes.select { |pci| pci[:vendor_name] == "Intel Corporation" }
319
320 if !intel_ssds.empty? || !intel_nvmes.empty?
321   package "unzip"
322   package "alien"
323
324   remote_file "#{Chef::Config[:file_cache_path]}/DataCenterTool_3_0_0_Linux.zip" do
325     source "https://downloadmirror.intel.com/23931/eng/DataCenterTool_3_0_0_Linux.zip"
326   end
327
328   execute "unzip-DataCenterTool" do
329     command "unzip DataCenterTool_3_0_0_Linux.zip isdct-3.0.0.400-15.x86_64.rpm"
330     cwd Chef::Config[:file_cache_path]
331     user "root"
332     group "root"
333     not_if { File.exist?("#{Chef::Config[:file_cache_path]}/isdct-3.0.0.400-15.x86_64.rpm") }
334   end
335
336   execute "alien-isdct" do
337     command "alien --to-deb isdct-3.0.0.400-15.x86_64.rpm"
338     cwd Chef::Config[:file_cache_path]
339     user "root"
340     group "root"
341     not_if { File.exist?("#{Chef::Config[:file_cache_path]}/isdct_3.0.0.400-16_amd64.deb") }
342   end
343
344   dpkg_package "isdct" do
345     source "#{Chef::Config[:file_cache_path]}/isdct_3.0.0.400-16_amd64.deb"
346   end
347 end
348
349 disks = disks.map do |disk|
350   next if disk[:state] == "spun_down"
351
352   if disk[:smart_device]
353     controller = node[:hardware][:disk][:controllers][disk[:controller]]
354     device = controller[:device].sub("/dev/", "")
355     smart = disk[:smart_device]
356
357     if device.start_with?("cciss/") && smart =~ /^cciss,(\d+)$/
358       array = node[:hardware][:disk][:arrays][disk[:arrays].first]
359       munin = "cciss-3#{array[:wwn]}-#{Regexp.last_match(1)}"
360     elsif smart =~ /^.*,(\d+)$/
361       munin = "#{device}-#{Regexp.last_match(1)}"
362     elsif smart =~ %r{^.*,(\d+)/(\d+)$}
363       munin = "#{device}-#{Regexp.last_match(1)}:#{Regexp.last_match(2)}"
364     end
365   elsif disk[:device]
366     device = disk[:device].sub("/dev/", "")
367     munin = device
368   end
369
370   next if device.nil?
371
372   Hash[
373     :device => device,
374     :smart => smart,
375     :munin => munin,
376     :hddtemp => munin.tr("-:", "_")
377   ]
378 end
379
380 smartd_service = if node[:lsb][:release].to_f >= 16.04
381                    "smartd"
382                  else
383                    "smartmontools"
384                  end
385
386 disks = disks.compact
387
388 if disks.count > 0
389   package "smartmontools"
390
391   template "/usr/local/bin/smartd-mailer" do
392     source "smartd-mailer.erb"
393     owner "root"
394     group "root"
395     mode 0o755
396   end
397
398   template "/etc/smartd.conf" do
399     source "smartd.conf.erb"
400     owner "root"
401     group "root"
402     mode 0o644
403     variables :disks => disks
404   end
405
406   template "/etc/default/smartmontools" do
407     source "smartmontools.erb"
408     owner "root"
409     group "root"
410     mode 0o644
411   end
412
413   service smartd_service do
414     action [:enable, :start]
415     subscribes :reload, "template[/etc/smartd.conf]"
416     subscribes :restart, "template[/etc/default/smartmontools]"
417   end
418
419   # Don't try and do munin monitoring of disks behind
420   # an Areca controller as they only allow one thing to
421   # talk to the controller at a time and smartd will
422   # throw errors if it clashes with munin
423   disks = disks.reject { |disk| disk[:smart] && disk[:smart].start_with?("areca,") }
424
425   disks.each do |disk|
426     munin_plugin "smart_#{disk[:munin]}" do
427       target "smart_"
428       conf "munin.smart.erb"
429       conf_variables :disk => disk
430     end
431   end
432 else
433   service smartd_service do
434     action [:stop, :disable]
435   end
436 end
437
438 if disks.count > 0
439   munin_plugin "hddtemp_smartctl" do
440     conf "munin.hddtemp.erb"
441     conf_variables :disks => disks
442   end
443 else
444   munin_plugin "hddtemp_smartctl" do
445     action :delete
446     conf "munin.hddtemp.erb"
447   end
448 end
449
450 plugins = Dir.glob("/etc/munin/plugins/smart_*").map { |p| File.basename(p) } -
451           disks.map { |d| "smart_#{d[:munin]}" }
452
453 plugins.each do |plugin|
454   munin_plugin plugin do
455     action :delete
456   end
457 end
458
459 if File.exist?("/etc/mdadm/mdadm.conf")
460   mdadm_conf = edit_file "/etc/mdadm/mdadm.conf" do |line|
461     line.gsub!(/^MAILADDR .*$/, "MAILADDR admins@openstreetmap.org")
462
463     line
464   end
465
466   file "/etc/mdadm/mdadm.conf" do
467     owner "root"
468     group "root"
469     mode 0o644
470     content mdadm_conf
471   end
472
473   service "mdadm" do
474     action :nothing
475     subscribes :restart, "file[/etc/mdadm/mdadm.conf]"
476   end
477 end
478
479 template "/etc/modules" do
480   source "modules.erb"
481   owner "root"
482   group "root"
483   mode 0o644
484 end
485
486 if node[:lsb][:release].to_f <= 12.10
487   service "module-init-tools" do
488     provider Chef::Provider::Service::Upstart
489     action :nothing
490     subscribes :start, "template[/etc/modules]"
491   end
492 else
493   service "kmod" do
494     if node[:lsb][:release].to_f >= 15.10
495       provider Chef::Provider::Service::Systemd
496     else
497       provider Chef::Provider::Service::Upstart
498     end
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 0o644
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   Dir.glob("/sys/devices/platform/coretemp.*").each do |coretemp|
524     cpu = File.basename(coretemp).sub("coretemp.", "").to_i
525     chip = format("coretemp-isa-%04d", cpu)
526
527     temps = if File.exist?("#{coretemp}/name")
528               Dir.glob("#{coretemp}/temp*_input").map do |temp|
529                 File.basename(temp).sub("temp", "").sub("_input", "").to_i
530               end.sort
531             else
532               Dir.glob("#{coretemp}/hwmon/hwmon*/temp*_input").map do |temp|
533                 File.basename(temp).sub("temp", "").sub("_input", "").to_i
534               end.sort
535             end
536
537     if temps.first == 1
538       node.default[:hardware][:sensors][chip][:temps][:temp1][:label] = "CPU #{cpu}"
539       temps.shift
540     end
541
542     temps.each_with_index do |temp, index|
543       node.default[:hardware][:sensors][chip][:temps]["temp#{temp}"][:label] = "CPU #{cpu} Core #{index}"
544     end
545   end
546
547   execute "/etc/sensors.d/chef.conf" do
548     action :nothing
549     command "/usr/bin/sensors -s"
550     user "root"
551     group "root"
552   end
553
554   template "/etc/sensors.d/chef.conf" do
555     source "sensors.conf.erb"
556     owner "root"
557     group "root"
558     mode 0o644
559     notifies :run, "execute[/etc/sensors.d/chef.conf]"
560   end
561 end