cookbooks/fb_networkd/resources/default.rb (281 lines of code) (raw):
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
#
# Copyright (c) 2021-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.
#
default_action :manage
action :manage do
ohai_ifaces = node['network']['interfaces'].to_hash.keys
# Set up execute resources to reconfigure network settings so that they can be
# notified by and subscribed to from other recipes.
interfaces = (node['fb_networkd']['networks'].keys +
node['fb_networkd']['devices'].keys +
node['fb_networkd']['links'].keys).uniq
interfaces.each do |iface|
next if iface == 'lo'
execute "networkctl reconfigure #{iface}" do
command "/bin/networkctl reconfigure #{iface}"
action :nothing
end
# For existing interfaces filled out by the network plugin, the execute
# block was already set up in the fb_networkd recipe. If we haven't set it
# up yet, add it here.
unless ohai_ifaces.include?(iface)
execute "udevadm trigger #{iface}" do
command "/bin/udevadm trigger --action=add /sys/class/net/#{iface}"
action :nothing
end
end
end
managed_networks = []
managed_links = []
managed_netdevs = []
config_glob = ::File.join(
FB::Networkd::BASE_CONFIG_PATH, '*.{network,netdev,link}'
)
Dir.glob(config_glob).each do |path|
if ::File.basename(path).include?('-fb_networkd-')
if path.end_with?('.network')
managed_networks << path
elsif path.end_with?('.link')
managed_links << path
elsif path.end_with?('.netdev')
managed_netdevs << path
end
else
Chef::Log.warn("fb_networkd: Unmanaged network config #{path} found")
end
end
node['fb_networkd']['networks'].each do |name, defconf|
conf = defconf.dup
conf['name'] = name
unless conf['priority']
if conf['name'] == node['fb_networkd']['primary_interface']
conf['priority'] =
FB::Networkd::DEFAULT_PRIMARY_INTERFACE_NETWORK_PRIORITY
else
conf['priority'] = FB::Networkd::DEFAULT_NETWORK_PRIORITY
end
end
unless conf['config']
fail "fb_networkd: Cannot set up network config on #{conf['name']} " +
"without the 'config' attribute"
end
unless conf['config']['Match']
conf['config']['Match'] = {}
end
conf['config']['Match']['Name'] = conf['name']
conffile = ::File.join(
FB::Networkd::BASE_CONFIG_PATH,
"#{conf['priority']}-fb_networkd-#{conf['name']}.network",
)
# This file is actively managed and already exists on the host so remove it
# from the "manageds" array.
remove_conflicts = false
if managed_networks.include?(conffile)
managed_networks.delete(conffile)
remove_conflicts = true
end
# If this config was previously managed under a different name (e.g.
# different priority) then set up a file resource to allow it to be deleted
# when the new config is set up or if the "new" config already exists.
conflicting_networks = managed_networks.grep(
/-fb_networkd-#{conf['name']}.network$/,
)
conflicting_networks ||= []
conflicting_networks.each do |path|
managed_networks.delete(path)
file path do
only_if do
node.interface_change_allowed?(conf['name']) && remove_conflicts
end
owner node.root_user
group node.root_group
mode '0644'
action :delete
notifies :run, 'execute[networkctl reload]', :immediately
notifies :run, "execute[networkctl reconfigure #{conf['name']}]"
end
if !node.interface_change_allowed?(conf['name']) && remove_conflicts
FB::Helpers._request_nw_changes_permission(run_context, new_resource)
end
end
fb_helpers_gated_template conffile do # ~FB031
allow_changes node.interface_change_allowed?(conf['name'])
source 'networkd.conf.erb'
owner node.root_user
group node.root_group
mode '0644'
variables(
:config => conf['config'],
)
notifies :run, 'execute[networkctl reload]', :immediately
notifies :run, "execute[networkctl reconfigure #{conf['name']}]"
end
end
node['fb_networkd']['links'].each do |name, defconf|
conf = defconf.dup
conf['name'] = name
unless conf['priority']
if conf['name'] == node['fb_networkd']['primary_interface']
conf['priority'] = FB::Networkd::DEFAULT_PRIMARY_INTERFACE_LINK_PRIORITY
else
conf['priority'] = FB::Networkd::DEFAULT_LINK_PRIORITY
end
end
unless conf['config']
fail "fb_networkd: Cannot set up link config on #{conf['name']} " +
"without the 'config' attribute"
end
unless conf['config']['Match']
conf['config']['Match'] = {}
end
conf['config']['Match']['OriginalName'] = conf['name']
conffile = ::File.join(
FB::Networkd::BASE_CONFIG_PATH,
"#{conf['priority']}-fb_networkd-#{conf['name']}.link",
)
# This file is actively managed and already exists on the host so remove it
# from the "manageds" array.
remove_conflicts = false
if managed_links.include?(conffile)
managed_links.delete(conffile)
remove_conflicts = true
end
# If this config was previously managed under a different name (e.g.
# different priority) then set up a file resource to allow it to be deleted
# when the new config is set up or if the "new" config already exists.
conflicting_links = managed_links.grep(
/-fb_networkd-#{conf['name']}.link$/,
)
conflicting_links ||= []
conflicting_links.each do |path|
managed_links.delete(path)
file path do
only_if do
node.interface_change_allowed?(conf['name']) && remove_conflicts
end
owner node.root_user
group node.root_group
mode '0644'
action :delete
notifies :run, "execute[udevadm trigger #{conf['name']}]"
end
if !node.interface_change_allowed?(conf['name']) && remove_conflicts
FB::Helpers._request_nw_changes_permission(run_context, new_resource)
end
end
fb_helpers_gated_template conffile do # ~FB031
allow_changes node.interface_change_allowed?(conf['name'])
source 'networkd.conf.erb'
owner node.root_user
group node.root_group
mode '0644'
variables(
:config => conf['config'],
)
notifies :run, "execute[udevadm trigger #{conf['name']}]"
end
end
node['fb_networkd']['devices'].each do |name, defconf|
conf = defconf.dup
conf['name'] = name
unless conf['priority']
if conf['name'] == node['fb_networkd']['primary_interface']
conf['priority'] =
FB::Networkd::DEFAULT_PRIMARY_INTERFACE_DEVICE_PRIORITY
else
conf['priority'] = FB::Networkd::DEFAULT_DEVICE_PRIORITY
end
end
unless conf['config']
fail "fb_networkd: Cannot set up netdev config on #{conf['name']} " +
"without the 'config' attribute"
end
# Unlike network and link configurations which expect `[Match]` to be filled
# out, netdev configurations require the `[NetDev]` section's `Name`
# property.
unless conf['config']['NetDev']
conf['config']['NetDev'] = {}
end
conf['config']['NetDev']['Name'] = conf['name']
conffile = ::File.join(
FB::Networkd::BASE_CONFIG_PATH,
"#{conf['priority']}-fb_networkd-#{conf['name']}.netdev",
)
# This file is actively managed and already exists on the host so remove it
# from the "manageds" array.
remove_conflicts = false
if managed_netdevs.include?(conffile)
managed_netdevs.delete(conffile)
remove_conflicts = true
end
# If this config was previously managed under a different name (e.g.
# different priority) then set up a file resource to allow it to be deleted
# when the new config is set up or if the "new" config already exists.
conflicting_netdevs = managed_netdevs.grep(
/-fb_networkd-#{conf['name']}.netdev$/,
)
conflicting_netdevs ||= []
conflicting_netdevs.each do |path|
managed_netdevs.delete(path)
file path do
only_if do
node.interface_change_allowed?(conf['name']) && remove_conflicts
end
owner node.root_user
group node.root_group
mode '0644'
action :delete
notifies :run, 'execute[networkctl reload]', :immediately
notifies :run, "execute[networkctl reconfigure #{conf['name']}]"
end
if !node.interface_change_allowed?(conf['name']) && remove_conflicts
FB::Helpers._request_nw_changes_permission(run_context, new_resource)
end
end
fb_helpers_gated_template conffile do # ~FB031
allow_changes node.interface_change_allowed?(conf['name'])
source 'networkd.conf.erb'
owner node.root_user
group node.root_group
mode '0644'
variables(
:config => conf['config'],
)
notifies :run, 'execute[networkctl reload]', :immediately
notifies :run, "execute[networkctl reconfigure #{conf['name']}]"
end
end
# For each managed file, check if we can make network changes on the
# inteface. If we can, then take down the interface (except links) and delete
# the file.
managed_networks.each do |path|
iface = path[/-fb_networkd-(.*?).network/m, 1]
if iface
execute "networkctl down #{iface}" do
only_if { node.interface_change_allowed?(iface) }
command "/bin/networkctl down #{iface}"
ignore_failure true # if the interface was not up, already down, etc.
action :nothing
end
file path do # ~FC022
only_if { node.interface_change_allowed?(iface) }
action :delete
notifies :run, "execute[networkctl down #{iface}]", :immediately
notifies :run, 'execute[networkctl reload]'
end
unless node.interface_change_allowed?(iface)
FB::Helpers._request_nw_changes_permission(run_context, new_resource)
end
end
end
managed_links.each do |path|
iface = path[/-fb_networkd-(.*?).link/m, 1]
if iface
execute "udevadm trigger #{iface}" do
only_if { node.interface_change_allowed?(iface) }
command "/bin/udevadm trigger --action=add /sys/class/net/#{iface}"
ignore_failure true # if the device is already down, etc.
action :nothing
end
file path do # ~FC022
only_if { node.interface_change_allowed?(iface) }
action :delete
notifies :run, "execute[udevadm trigger #{iface}]"
end
unless node.interface_change_allowed?(iface)
FB::Helpers._request_nw_changes_permission(run_context, new_resource)
end
end
end
managed_netdevs.each do |path|
iface = path[/-fb_networkd-(.*?).netdev/m, 1]
if iface
execute "networkctl delete #{iface}" do
only_if { node.interface_change_allowed?(iface) }
command "/bin/networkctl delete #{iface}"
ignore_failure true # if the interface was not up, already down, etc.
action :nothing
end
file path do # ~FC022
only_if { node.interface_change_allowed?(iface) }
action :delete
notifies :run, "execute[networkctl delete #{iface}]", :immediately
notifies :run, 'execute[networkctl reload]'
end
unless node.interface_change_allowed?(iface)
FB::Helpers._request_nw_changes_permission(run_context, new_resource)
end
end
end
end