File: //usr/local/qcloud/python/lib/python3.7/site-packages/cloudinit/net/freebsd.py
# This file is part of cloud-init. See LICENSE file for license information.
import re
from cloudinit import log as logging
from cloudinit import net
from cloudinit import util
from cloudinit.distros import rhel_util
from cloudinit.distros.parsers.resolv_conf import ResolvConf
from . import renderer
LOG = logging.getLogger(__name__)
class Renderer(renderer.Renderer):
resolv_conf_fn = 'etc/resolv.conf'
rc_conf_fn = 'etc/rc.conf'
def __init__(self, config=None):
if not config:
config = {}
self.dhcp_interfaces = []
self._postcmds = config.get('postcmds', True)
def _update_rc_conf(self, settings, target=None):
fn = util.target_path(target, self.rc_conf_fn)
rhel_util.update_sysconfig_file(fn, settings)
def _write_ifconfig_entries(self, settings, target=None):
ifname_by_mac = net.get_interfaces_by_mac()
for interface in settings.iter_interfaces():
device_name = interface.get("name")
device_mac = interface.get("mac_address")
if device_name and re.match(r'^lo\d+$', device_name):
continue
if device_mac not in ifname_by_mac:
LOG.info('Cannot find any device with MAC %s', device_mac)
elif device_mac and device_name:
cur_name = ifname_by_mac[device_mac]
if cur_name != device_name:
LOG.info('netif service will rename interface %s to %s',
cur_name, device_name)
self._update_rc_conf(
{'ifconfig_%s_name' % cur_name: device_name},
target=target)
else:
device_name = ifname_by_mac[device_mac]
LOG.info('Configuring interface %s', device_name)
ifconfig = 'DHCP' # default
for subnet in interface.get("subnets", []):
if ifconfig != 'DHCP':
LOG.info('The FreeBSD provider only set the first subnet.')
break
if subnet.get('type') == 'static':
if not subnet.get('netmask'):
LOG.debug(
'Skipping IP %s, because there is no netmask',
subnet.get('address'))
continue
LOG.debug('Configuring dev %s with %s / %s', device_name,
subnet.get('address'), subnet.get('netmask'))
# Configure an ipv4 address.
ifconfig = (
subnet.get('address') + ' netmask ' +
subnet.get('netmask'))
if ifconfig == 'DHCP':
self.dhcp_interfaces.append(device_name)
self._update_rc_conf(
{'ifconfig_' + device_name: ifconfig},
target=target)
def _write_route_entries(self, settings, target=None):
routes = list(settings.iter_routes())
for interface in settings.iter_interfaces():
subnets = interface.get("subnets", [])
for subnet in subnets:
if subnet.get('type') != 'static':
continue
gateway = subnet.get('gateway')
if gateway and len(gateway.split('.')) == 4:
routes.append({
'network': '0.0.0.0',
'netmask': '0.0.0.0',
'gateway': gateway})
routes += subnet.get('routes', [])
route_cpt = 0
for route in routes:
network = route.get('network')
if not network:
LOG.debug('Skipping a bad route entry')
continue
netmask = route.get('netmask')
gateway = route.get('gateway')
route_cmd = "-route %s/%s %s" % (network, netmask, gateway)
if network == '0.0.0.0':
self._update_rc_conf(
{'defaultrouter': gateway}, target=target)
else:
self._update_rc_conf(
{'route_net%d' % route_cpt: route_cmd}, target=target)
route_cpt += 1
def _write_resolve_conf(self, settings, target=None):
nameservers = settings.dns_nameservers
searchdomains = settings.dns_searchdomains
for interface in settings.iter_interfaces():
for subnet in interface.get("subnets", []):
if 'dns_nameservers' in subnet:
nameservers.extend(subnet['dns_nameservers'])
if 'dns_search' in subnet:
searchdomains.extend(subnet['dns_search'])
# Try to read the /etc/resolv.conf or just start from scratch if that
# fails.
try:
resolvconf = ResolvConf(util.load_file(util.target_path(
target, self.resolv_conf_fn)))
resolvconf.parse()
except IOError:
util.logexc(LOG, "Failed to parse %s, use new empty file",
util.target_path(target, self.resolv_conf_fn))
resolvconf = ResolvConf('')
resolvconf.parse()
# Add some nameservers
for server in nameservers:
try:
resolvconf.add_nameserver(server)
except ValueError:
util.logexc(LOG, "Failed to add nameserver %s", server)
# And add any searchdomains.
for domain in searchdomains:
try:
resolvconf.add_search_domain(domain)
except ValueError:
util.logexc(LOG, "Failed to add search domain %s", domain)
util.write_file(
util.target_path(target, self.resolv_conf_fn),
str(resolvconf), 0o644)
def _write_network(self, settings, target=None):
self._write_ifconfig_entries(settings, target=target)
self._write_route_entries(settings, target=target)
self._write_resolve_conf(settings, target=target)
self.start_services(run=self._postcmds)
def render_network_state(self, network_state, templates=None, target=None):
self._write_network(network_state, target=target)
def start_services(self, run=False):
if not run:
LOG.debug("freebsd generate postcmd disabled")
return
util.subp(['service', 'netif', 'restart'], capture=True)
# On FreeBSD 10, the restart of routing and dhclient is likely to fail
# because
# - routing: it cannot remove the loopback route, but it will still set
# up the default route as expected.
# - dhclient: it cannot stop the dhclient started by the netif service.
# In both case, the situation is ok, and we can proceed.
util.subp(['service', 'routing', 'restart'], capture=True, rcs=[0, 1])
for dhcp_interface in self.dhcp_interfaces:
util.subp(['service', 'dhclient', 'restart', dhcp_interface],
rcs=[0, 1],
capture=True)
def available(target=None):
return util.is_FreeBSD()