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