Skip to content

Commit

Permalink
preflight: Add support for systemd-resolved
Browse files Browse the repository at this point in the history
Recent distributions (Fedora 33, Ubuntu desktop editions, ...) use
systemd-resolved for DNS resolution. NetworkManager is still used
for network interface configuration, but the dnsmasq setup that crc
is doing won't work as systemd-resolved is already listening on port 53,
so we can't start a dnsmasq instance which would listen there as well.

This commit adds support for systemd-resolved on recent fedoras.
This configures split DNS (
https://fedoramagazine.org/systemd-resolved-introduction-to-split-dns/ )
so that resolution of domains under *.testing are sent to the crc VM.
Resolution for all the other DNS names won't be impacted by the
configuration we are doing, and they will be resolved exactly as before
running `crc setup`.

The configuration of split DNS is done through a NM dispatcher file
which will run `resolvectl` commands when the libvirt crc interface
is up. The libvirt crc interface does not have a constant NM UUID across
reboots, so this is the best way I found to persist the split DNS
configuration across reboots.
  • Loading branch information
cfergeau authored and praveenkumar committed Dec 3, 2020
1 parent a410165 commit 8fa1e02
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 6 deletions.
82 changes: 77 additions & 5 deletions pkg/crc/preflight/preflight_checks_network_linux.go
Expand Up @@ -63,9 +63,48 @@ server=/crc.testing/192.168.130.11
crcNetworkManagerConfigPath = filepath.Join(crcNetworkManagerRootPath, "conf.d", "crc-nm-dnsmasq.conf")
crcNetworkManagerConfig = `[main]
dns=dnsmasq
`

crcNetworkManagerDispatcherPath = filepath.Join(crcNetworkManagerRootPath, "dispatcher.d", "pre-up.d", "99-crc.sh")
crcNetworkManagerDispatcherConfig = `#!/bin/sh
# This is a NetworkManager dispatcher script to configure split DNS for
# the 'crc' libvirt network.
# The corresponding crc bridge is recreated each time the system reboots, so
# it cannot be configured permanently through NetworkManager.
# Changing DNS settings with nmcli requires the connection to go down/up,
# so we directly make the change using resolvectl
export LC_ALL=C
if [ "$1" = crc ]; then
resolvectl domain "$1" ~testing
resolvectl dns "$1" 192.168.130.11
resolvectl default-route "$1" false
fi
exit 0
`
)

var systemdResolvedPreflightChecks = [...]Check{
{
configKeySuffix: "check-systemd-resolved-running",
checkDescription: "Checking if the systemd-resolved service is running",
check: checkSystemdResolvedIsRunning,
fixDescription: "systemd-resolved is required on this distribution. Please make sure it is installed and running manually",
flags: NoFix,
},
{
configKeySuffix: "check-crc-nm-dispatcher-file",
checkDescription: fmt.Sprintf("Checking if %s exists", crcNetworkManagerDispatcherPath),
check: checkCrcNetworkManagerDispatcherFile,
fixDescription: "Writing NetworkManager dispatcher file for crc",
fix: fixCrcNetworkManagerDispatcherFile,
cleanupDescription: fmt.Sprintf("Removing %s file", crcNetworkManagerDispatcherPath),
cleanup: removeCrcNetworkManagerDispatcherFile,
},
}

func fixNetworkManagerConfigFile(path string, content string, perms os.FileMode) error {
err := crcos.WriteToFileAsRoot(
fmt.Sprintf("write NetworkManager configuration to %s", path),
Expand Down Expand Up @@ -169,16 +208,49 @@ func checkNetworkManagerInstalled() error {
return nil
}

func checkNetworkManagerIsRunning() error {
logging.Debug("Checking if NetworkManager.service is running")
func checkSystemdServiceRunning(service string) error {
logging.Debugf("Checking if %s is running", service)
sd := systemd.NewHostSystemdCommander()
status, err := sd.Status("NetworkManager")
status, err := sd.Status(service)
if err != nil {
return err
}
if status != states.Running {
return fmt.Errorf("NetworkManager.service is not running")
return fmt.Errorf("%s is not running", service)
}
logging.Debug("NetworkManager.service is already running")
logging.Debugf("%s is already running", service)
return nil
}

func checkNetworkManagerIsRunning() error {
return checkSystemdServiceRunning("NetworkManager.service")
}

func checkSystemdResolvedIsRunning() error {
return checkSystemdServiceRunning("systemd-resolved.service")
}

func checkCrcNetworkManagerDispatcherFile() error {
logging.Debug("Checking NetworkManager dispatcher file for crc network")
err := crcos.FileContentMatches(crcNetworkManagerDispatcherPath, []byte(crcNetworkManagerDispatcherConfig))
if err != nil {
return err
}
logging.Debug("Dispatcher file has the expected content")
return nil
}

func fixCrcNetworkManagerDispatcherFile() error {
logging.Debug("Fixing NetworkManager dispatcher configuration")
err := fixNetworkManagerConfigFile(crcNetworkManagerDispatcherPath, crcNetworkManagerDispatcherConfig, 0755)
if err != nil {
return err
}

logging.Debug("NetworkManager dispatcher configuration fixed")
return nil
}

func removeCrcNetworkManagerDispatcherFile() error {
return removeNetworkManagerConfigFile(crcNetworkManagerDispatcherPath)
}
15 changes: 14 additions & 1 deletion pkg/crc/preflight/preflight_linux.go
Expand Up @@ -175,7 +175,11 @@ func getPreflightChecksForDistro(distro *linux.OsRelease, networkMode network.Mo
fallthrough
case linux.RHEL, linux.CentOS, linux.Fedora:
checks = append(checks, nmPreflightChecks[:]...)
checks = append(checks, dnsmasqPreflightChecks[:]...)
if usesSystemdResolved(distro) {
checks = append(checks, systemdResolvedPreflightChecks[:]...)
} else {
checks = append(checks, dnsmasqPreflightChecks[:]...)
}
case linux.Ubuntu:
break
}
Expand All @@ -191,6 +195,15 @@ func commonChecks() []Check {
return checks
}

func usesSystemdResolved(osRelease *linux.OsRelease) bool {
switch distroID(osRelease) {
case linux.Fedora:
return osRelease.VersionID >= "33"
default:
return false
}
}

func distroID(osRelease *linux.OsRelease) linux.OsType {
if osRelease == nil {
return "unknown"
Expand Down

0 comments on commit 8fa1e02

Please sign in to comment.