cookbooks/fb_swap/recipes/before_fb_fstab.rb (72 lines of code) (raw):

# # Cookbook Name:: fb_swap # Recipe:: before_fb_fstab # # Copyright (c) 2016-present, Facebook, Inc. # All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'shellwords' # Newly provisioned hosts end up with a swap device in /etc/fstab which # is referenced by UUID (or label, or path). We use data from ohai's # filesystem2 plugin (which is backed by the state of the machine, not what # is in /etc/fstab). We want to create/manage our own units with predictable # names # node.default['fb_fstab']['exclude_base_swap'] = true whyrun_safe_ruby_block 'Validate and calculate swap sizes' do block do FB::FbSwap._validate(node) end end ['device', 'file'].each do |type| next if type == 'device' && FB::FbSwap._device(node).nil? manage_unit = "manage-swap-#{type}.service" whyrun_safe_ruby_block "Add #{type} swap to fstab" do only_if { node['fb_swap']['_calculated']["#{type}_size_bytes"].positive? } block do # ask fb_fstab to create the unit node.default['fb_fstab']['mounts']["swap_#{type}"] = { 'mount_point' => 'swap', 'device' => FB::FbSwap._path(node, type), 'type' => 'swap', # prioritize swap file in case that swap partition is on a spinning disk 'opts' => type == 'file' ? 'pri=10' : 'pri=5', } end end template "/etc/systemd/system/#{manage_unit}" do source "#{manage_unit}.erb" owner 'root' group 'root' mode '0644' notifies :run, 'fb_systemd_reload[system instance]', :immediately notifies :restart, "service[#{manage_unit}]" end # Note: FC022 is masked because the unit name is derived from the type # variable in the loop service manage_unit do # ~FC022 # we can get restarted, but we don't need to enable/start this explicitly # due to the use of BindsTo on the swap unit action :nothing # make the resource disappear if the measured size is the same as the # expected size. This fixes the bootstrap case where manage_unit # is first created and swap is already enabled and correct. not_if do node['fb_swap']['_calculated']["#{type}_size_bytes"] == node['fb_swap']['_calculated']["#{type}_current_size_bytes"] end # Restarting this unit itself is fairly fast but it's tied to the swap unit # by a PartOf relationship. The systemd provider for the service resource # will block because systemctl will block until the service is started. # # The systemd provider for the service resource has no way to pass # --no-block to systemctl, so we have to call it ourselves. restart_command '/usr/bin/systemctl --system --no-block restart ' + Shellwords.escape(manage_unit) end # Override the fb_fstab -> fstab-generator unit with some extra deps # Note that swap units are more limited in what systemd options they # take from the options column. fb_systemd_override "#{type} swap override" do only_if { node['fb_swap']['_calculated']["#{type}_size_bytes"].positive? } override_name 'manage' unit_name lazy { FB::FbSwap._swap_unit(node, type) } content( lazy do { 'Unit' => { 'BindsTo' => manage_unit, 'After' => manage_unit, 'PartOf' => manage_unit, }, # Stopping swap is pathologically slow on Linux today. The general # default for stopping units in systemd is 90s. Here we'll use # 100s per GiB as a heuristic on top of the default. 'Swap' => { 'TimeoutSec' => 90 + 100 * (node['fb_swap']['_calculated']["#{type}_size_bytes"] / 2**30), }, } end, ) end fb_systemd_override "remove #{type} swap override" do not_if { node['fb_swap']['_calculated']["#{type}_size_bytes"].positive? } override_name 'manage' unit_name lazy { FB::FbSwap._swap_unit(node, type) } action :delete end end template '/usr/local/libexec/manage-swap-file' do source 'manage-swap-file.sh.erb' owner 'root' group 'root' # read/execute for root, read only for everyone else. mode '0544' notifies :restart, 'service[manage-swap-file.service]', :immediately end