]> git.openstreetmap.org Git - chef.git/blob - cookbooks/hardware/recipes/default.rb
Use volume for nested podman container storage
[chef.git] / cookbooks / hardware / recipes / default.rb
1 #
2 # Cookbook:: 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 #     https://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 "apt"
21 include_recipe "git"
22 include_recipe "prometheus"
23 include_recipe "sysfs"
24 include_recipe "tools"
25
26 ohai_plugin "hardware" do
27   template "ohai.rb.erb"
28 end
29
30 if platform?("debian")
31   package "firmware-linux"
32 end
33
34 if node[:cpu] && node[:cpu][:"0"] && node[:cpu][:"0"][:vendor_id]
35   case node[:cpu][:"0"][:vendor_id]
36   when "GenuineIntel"
37     package "intel-microcode"
38   when "AuthenticAMD"
39     package "amd64-microcode"
40   end
41 end
42
43 if node[:dmi] && node[:dmi][:system]
44   case node[:dmi][:system][:manufacturer]
45   when "empty"
46     manufacturer = node[:dmi][:base_board][:manufacturer]
47     product = node[:dmi][:base_board][:product_name]
48   else
49     manufacturer = node[:dmi][:system][:manufacturer]
50     product = node[:dmi][:system][:product_name]
51   end
52 else
53   manufacturer = "Unknown"
54   product = "Unknown"
55 end
56
57 units = []
58
59 if node[:roles].include?("bytemark")
60   units << "0"
61 end
62
63 case manufacturer
64 when "HP", "HPE"
65   include_recipe "apt::management-component-pack"
66
67   package "hponcfg"
68
69   execute "update-ilo" do
70     action :nothing
71     command "/usr/sbin/hponcfg -f /etc/ilo-defaults.xml"
72     not_if { kitchen? }
73   end
74
75   template "/etc/ilo-defaults.xml" do
76     source "ilo-defaults.xml.erb"
77     owner "root"
78     group "root"
79     mode "644"
80     notifies :run, "execute[update-ilo]"
81   end
82
83   unless product.end_with?("G6", "G7") # iLO4+ Only
84     execute "update-ilo-network" do
85       action :nothing
86       command "/usr/sbin/hponcfg -f /etc/ilo-network.xml"
87       not_if { kitchen? }
88     end
89
90     template "/etc/ilo-network.xml" do
91       source "ilo-network.xml.erb"
92       owner "root"
93       group "root"
94       mode "644"
95       notifies :run, "execute[update-ilo-network]"
96     end
97   end
98
99   package "hp-health" do
100     action :install
101     notifies :restart, "service[hp-health]"
102     only_if { platform?("ubuntu") && node[:lsb][:release].to_f < 22.04 }
103   end
104
105   service "hp-health" do
106     action [:enable, :start]
107     supports :status => true, :restart => true
108     only_if { platform?("ubuntu") && node[:lsb][:release].to_f < 22.04 }
109   end
110
111   if product.end_with?("Gen8", "Gen9")
112     package "hp-ams" do
113       action :install
114       notifies :restart, "service[hp-ams]"
115     end
116
117     service "hp-ams" do
118       action [:enable, :start]
119       supports :status => true, :restart => true
120     end
121   elsif product.end_with?("Gen10") || product.end_with?("Gen10 Plus")
122     package "amsd" do
123       action :install
124       notifies :restart, "service[amsd]"
125       only_if { node[:hostname] != "quetzal" } # amsd is broken on quetzal, no SAS controller
126     end
127
128     service "amsd" do
129       action [:enable, :start]
130       supports :status => true, :restart => true
131       only_if { node[:hostname] != "quetzal" } # amsd is broken on quetzal, no SAS controller
132     end
133   end
134
135   units << if product.end_with?("Gen10") || product.end_with?("Gen10 Plus")
136              "0"
137            else
138              "1"
139            end
140 when "TYAN"
141   units << "0"
142 when "TYAN Computer Corporation"
143   units << "0"
144 when "Supermicro"
145   units << "1"
146 when "IBM"
147   units << "0"
148 when "VMware, Inc."
149   package "open-vm-tools"
150
151   # Remove timeSync plugin completely
152   # https://github.com/vmware/open-vm-tools/issues/302
153   file "/usr/lib/open-vm-tools/plugins/vmsvc/libtimeSync.so" do
154     action :delete
155     notifies :restart, "service[open-vm-tools]"
156   end
157
158   # Attempt to tell Host we are not interested in timeSync
159   execute "vmware-toolbox-cmd-timesync-disable" do
160     command "/usr/bin/vmware-toolbox-cmd timesync disable"
161     ignore_failure true
162   end
163
164   service "open-vm-tools" do
165     action [:enable, :start]
166     supports :status => true, :restart => true
167   end
168 end
169
170 units.sort.uniq.each do |unit|
171   service "serial-getty@ttyS#{unit}" do
172     action [:enable, :start]
173     not_if { kitchen? }
174   end
175 end
176
177 # if we need a different / special kernel version to make the hardware
178 # work (e.g: https://github.com/openstreetmap/operations/issues/45) then
179 # ensure that we have the package installed. the grub template will
180 # make sure that this is the default on boot.
181 if node[:hardware][:grub][:kernel]
182   kernel_version = node[:hardware][:grub][:kernel]
183
184   package "linux-image-#{kernel_version}-generic"
185   package "linux-image-extra-#{kernel_version}-generic"
186   package "linux-headers-#{kernel_version}-generic"
187   package "linux-tools-#{kernel_version}-generic"
188
189   boot_device = IO.popen(["df", "/boot"]).readlines.last.split.first
190   boot_uuid = IO.popen(["blkid", "-o", "value", "-s", "UUID", boot_device]).readlines.first.chomp
191   grub_entry = "gnulinux-advanced-#{boot_uuid}>gnulinux-#{kernel_version}-advanced-#{boot_uuid}"
192 else
193   grub_entry = "0"
194 end
195
196 if File.exist?("/etc/default/grub")
197   execute "update-grub" do
198     action :nothing
199     command "/usr/sbin/update-grub"
200     not_if { kitchen? }
201   end
202
203   template "/etc/default/grub" do
204     source "grub.erb"
205     owner "root"
206     group "root"
207     mode "644"
208     variables :units => units, :entry => grub_entry
209     notifies :run, "execute[update-grub]"
210   end
211 end
212
213 package "initramfs-tools"
214
215 execute "update-initramfs" do
216   action :nothing
217   command "update-initramfs -u -k all"
218   user "root"
219   group "root"
220 end
221
222 template "/etc/initramfs-tools/conf.d/mdadm" do
223   source "initramfs-mdadm.erb"
224   owner "root"
225   group "root"
226   mode "644"
227   notifies :run, "execute[update-initramfs]"
228 end
229
230 # haveged is only required on older kernels
231 # /dev/random is not blocking anymore in 5.15+
232 if Chef::Util.compare_versions(node[:kernel][:release], [5, 15]).negative?
233   package "haveged"
234   service "haveged" do
235     action [:enable, :start]
236   end
237 else
238   service "haveged" do
239     action [:stop, :disable]
240   end
241   package "haveged" do
242     action :remove
243   end
244 end
245
246 watchdog_module = %w[hpwdt sp5100_tco].find do |module_name|
247   node[:hardware][:pci]&.any? { |_, pci| pci[:modules]&.any?(module_name) }
248 end
249
250 if node[:kernel][:modules].include?("ipmi_si")
251   package "ipmitool"
252   package "freeipmi-tools"
253
254   template "/etc/prometheus/ipmi_local.yml" do
255     source "ipmi_local.yml.erb"
256     owner "root"
257     group "root"
258     mode "644"
259   end
260
261   prometheus_exporter "ipmi" do
262     port 9290
263     user "root"
264     private_devices false
265     protect_clock false
266     system_call_filter ["@system-service", "@raw-io"]
267     options "--config.file=/etc/prometheus/ipmi_local.yml"
268     subscribes :restart, "template[/etc/prometheus/ipmi_local.yml]"
269   end
270
271   watchdog_module ||= "ipmi_watchdog"
272 end
273
274 package "irqbalance"
275
276 service "irqbalance" do
277   action [:start, :enable]
278   supports :status => false, :restart => true, :reload => false
279 end
280
281 package "lldpd"
282
283 service "lldpd" do
284   action [:start, :enable]
285   supports :status => true, :restart => true, :reload => true
286 end
287
288 ohai_plugin "lldp" do
289   template "lldp.rb.erb"
290 end
291
292 package %w[
293   rasdaemon
294   ruby-sqlite3
295 ]
296
297 service "rasdaemon" do
298   action [:enable, :start]
299 end
300
301 prometheus_exporter "rasdaemon" do
302   port 9797
303   user "root"
304 end
305
306 tools_packages = []
307
308 if node[:virtualization][:role] != "guest" ||
309    (node[:virtualization][:system] != "lxc" &&
310     node[:virtualization][:system] != "lxd" &&
311     node[:virtualization][:system] != "openvz")
312
313   node[:kernel][:modules].each_key do |modname|
314     case modname
315     when "hpsa"
316       tools_packages << "ssacli"
317     when "mpt3sas"
318       tools_packages << "sas2ircu"
319     when "megaraid_sas"
320       tools_packages << "megacli"
321     end
322   end
323 end
324
325 include_recipe "apt::hwraid" unless tools_packages.empty?
326
327 %w[ssacli lsiutil sas2ircu megactl megacli arcconf].each do |tools_package|
328   if tools_packages.include?(tools_package)
329     package tools_package
330   else
331     package tools_package do
332       action :purge
333     end
334   end
335 end
336
337 disks = if node[:hardware][:disk]
338           node[:hardware][:disk][:disks]
339         else
340           []
341         end
342
343 intel_ssds = disks.select { |d| d[:vendor] == "INTEL" && d[:model] =~ /^SSD/ }
344
345 nvmes = if node[:hardware][:pci]
346           node[:hardware][:pci].values.select { |pci| pci[:driver] == "nvme" }
347         else
348           []
349         end
350
351 unless nvmes.empty?
352   package "nvme-cli"
353 end
354
355 intel_nvmes = nvmes.select { |pci| pci[:vendor_name] == "Intel Corporation" }
356
357 if !intel_ssds.empty? || !intel_nvmes.empty?
358   package "unzip"
359
360   sst_tool_version = "3-1"
361   sst_package_version = "3.1.346-0"
362
363   remote_file "#{Chef::Config[:file_cache_path]}/sst-cli-linux-deb--#{sst_tool_version}.zip" do
364     source "https://sdmsdfwdriver.blob.core.windows.net/files/kba-gcc/drivers-downloads/ka-00085/sst--#{sst_tool_version}/sst-cli-linux-deb--#{sst_tool_version}.zip"
365   end
366
367   archive_file "#{Chef::Config[:file_cache_path]}/sst-cli-linux-deb--#{sst_tool_version}.zip" do
368     destination Chef::Config[:file_cache_path]
369     owner "root"
370     group "root"
371     overwrite true
372     subscribes :create, "remote_file[#{Chef::Config[:file_cache_path]}/sst-cli-linux-deb--#{sst_tool_version}.zip]"
373   end
374
375   dpkg_package "sst" do
376     version sst_package_version
377     source "#{Chef::Config[:file_cache_path]}/sst-cli-linux-deb--#{sst_tool_version}/sst_#{sst_package_version}_amd64.deb"
378   end
379
380   dpkg_package "intelmas" do
381     action :purge
382   end
383 end
384
385 disks = disks.map do |disk|
386   next if disk[:state] == "spun_down" || %w[unconfigured failed].any?(disk[:status])
387
388   if disk[:smart_device]
389     controller = node[:hardware][:disk][:controllers][disk[:controller]]
390
391     if controller && controller[:device]
392       device = controller[:device].sub("/dev/", "")
393       smart = disk[:smart_device]
394     elsif disk[:device]
395       device = disk[:device].sub("/dev/", "")
396       smart = disk[:smart_device]
397     end
398   elsif disk[:device] =~ %r{^/dev/(nvme\d+)n\d+$}
399     device = Regexp.last_match(1)
400   elsif disk[:device]
401     device = disk[:device].sub("/dev/", "")
402   end
403
404   next if device.nil?
405
406   Hash[
407     :device => device,
408     :smart => smart
409   ]
410 end
411
412 disks = disks.compact.uniq
413
414 if disks.any?
415   package "smartmontools"
416
417   template "/etc/cron.daily/update-smart-drivedb" do
418     source "update-smart-drivedb.erb"
419     owner "root"
420     group "root"
421     mode "755"
422   end
423
424   template "/usr/local/bin/smartd-mailer" do
425     source "smartd-mailer.erb"
426     owner "root"
427     group "root"
428     mode "755"
429   end
430
431   template "/etc/smartd.conf" do
432     source "smartd.conf.erb"
433     owner "root"
434     group "root"
435     mode "644"
436     variables :disks => disks
437   end
438
439   template "/etc/default/smartmontools" do
440     source "smartmontools.erb"
441     owner "root"
442     group "root"
443     mode "644"
444   end
445
446   service "smartmontools" do
447     action [:enable, :start]
448     subscribes :reload, "template[/etc/smartd.conf]"
449     subscribes :restart, "template[/etc/default/smartmontools]"
450   end
451
452   template "/etc/prometheus/collectors/smart.devices" do
453     source "smart.devices.erb"
454     owner "root"
455     group "root"
456     mode "644"
457     variables :disks => disks
458   end
459
460   prometheus_collector "smart" do
461     interval "15m"
462     user "root"
463     capability_bounding_set %w[CAP_DAC_OVERRIDE CAP_SYS_ADMIN CAP_SYS_RAWIO]
464     private_devices false
465     private_users false
466     protect_clock false
467   end
468 else
469   service "smartd" do
470     action [:stop, :disable]
471   end
472 end
473
474 if File.exist?("/etc/mdadm/mdadm.conf")
475   mdadm_conf = edit_file "/etc/mdadm/mdadm.conf" do |line|
476     line.gsub!(/^MAILADDR .*$/, "MAILADDR admins@openstreetmap.org")
477
478     line
479   end
480
481   file "/etc/mdadm/mdadm.conf" do
482     owner "root"
483     group "root"
484     mode "644"
485     content mdadm_conf
486   end
487
488   service "mdmonitor" do
489     action :nothing
490     subscribes :restart, "file[/etc/mdadm/mdadm.conf]"
491   end
492 end
493
494 file "/etc/modules" do
495   action :delete
496 end
497
498 node[:hardware][:modules].each do |module_name|
499   kernel_module module_name do
500     action :install
501     not_if { kitchen? }
502   end
503 end
504
505 node[:hardware][:blacklisted_modules].each do |module_name|
506   kernel_module module_name do
507     action :blacklist
508   end
509 end
510
511 if watchdog_module
512   kernel_module watchdog_module do
513     action :install
514   end
515
516   directory "/etc/systemd/system.conf.d" do
517     owner "root"
518     group "root"
519     mode "755"
520   end
521
522   template "/etc/systemd/system.conf.d/watchdog.conf" do
523     source "watchdog.conf.erb"
524     owner "root"
525     group "root"
526     mode "644"
527   end
528
529   execute "systemctl-reload" do
530     action :nothing
531     command "systemctl daemon-reload"
532     user "root"
533     group "root"
534     subscribes :run, "template[/etc/systemd/system.conf.d/watchdog.conf]"
535   end
536 end
537
538 unless Dir.glob("/sys/class/hwmon/hwmon*").empty?
539   package "lm-sensors"
540
541   Dir.glob("/sys/devices/platform/coretemp.*").each do |coretemp|
542     cpu = File.basename(coretemp).sub("coretemp.", "").to_i
543     chip = format("coretemp-isa-%04d", cpu)
544
545     temps = if File.exist?("#{coretemp}/name")
546               Dir.glob("#{coretemp}/temp*_input").map do |temp|
547                 File.basename(temp).sub("temp", "").sub("_input", "").to_i
548               end.sort
549             else
550               Dir.glob("#{coretemp}/hwmon/hwmon*/temp*_input").map do |temp|
551                 File.basename(temp).sub("temp", "").sub("_input", "").to_i
552               end.sort
553             end
554
555     if temps.first == 1
556       node.default[:hardware][:sensors][chip][:temps][:temp1][:label] = "CPU #{cpu}"
557       temps.shift
558     end
559
560     temps.each_with_index do |temp, index|
561       node.default[:hardware][:sensors][chip][:temps]["temp#{temp}"][:label] = "CPU #{cpu} Core #{index}"
562     end
563   end
564
565   execute "/etc/sensors.d/chef.conf" do
566     action :nothing
567     command "/usr/bin/sensors -s"
568     user "root"
569     group "root"
570   end
571
572   template "/etc/sensors.d/chef.conf" do
573     source "sensors.conf.erb"
574     owner "root"
575     group "root"
576     mode "644"
577     notifies :run, "execute[/etc/sensors.d/chef.conf]"
578   end
579 end
580
581 if node[:hardware][:shm_size]
582   execute "remount-dev-shm" do
583     action :nothing
584     command "/bin/mount -o remount /dev/shm"
585     user "root"
586     group "root"
587   end
588
589   mount "/dev/shm" do
590     action :enable
591     device "tmpfs"
592     fstype "tmpfs"
593     options "rw,nosuid,nodev,size=#{node[:hardware][:shm_size]}"
594     notifies :run, "execute[remount-dev-shm]"
595   end
596 end
597
598 prometheus_collector "ohai" do
599   interval "15m"
600   user "root"
601   proc_subset "all"
602   capability_bounding_set %w[CAP_DAC_OVERRIDE CAP_SYS_ADMIN CAP_SYS_RAWIO]
603   private_devices false
604   private_users false
605   protect_clock false
606   protect_kernel_modules false
607 end