Install systemd-resolved for NetworkManager

Workaround for cloud-init bug until this fix gets shipped to the
distros:
cb36bf38b8
This commit is contained in:
Max Erenberg 2024-01-13 22:04:54 -05:00
parent 08d3ec2804
commit a903d9ba0c
2 changed files with 86 additions and 32 deletions

View File

@ -39,11 +39,52 @@ func (mgr *OpensuseTumbleweedTemplateManager) DownloadTemplate(version, codename
)
}
func (mgr *OpensuseTumbleweedTemplateManager) InstallNetworkManager(handle *guestfs.Guestfs) error {
args := []string{"zypper", "--non-interactive", "install", "NetworkManager"}
_, err := mgr.logAndRunCommand(handle, args)
func (mgr *OpensuseTumbleweedTemplateManager) addSystemUser(handle *guestfs.Guestfs, name, comment string) error {
matches, err := handle.Grep("^"+name, "/etc/passwd", nil)
if err != nil {
return fmt.Errorf("Could not install NetworkManager: %w", err)
return fmt.Errorf("Could not grep /etc/passwd: %w", err)
}
if len(matches) > 0 {
return nil
}
_, err = mgr.logAndRunCommand(handle, []string{
"useradd",
"--system",
"--no-create-home",
"--home-dir", "/",
"--shell", "/usr/sbin/nologin",
"--comment", comment,
name,
})
if err != nil {
return fmt.Errorf("Could not add user %s: %w", name, err)
}
return nil
}
func (mgr *OpensuseTumbleweedTemplateManager) InstallSystemdResolved(handle *guestfs.Guestfs) error {
// This package contains both systemd-networkd and systemd-resolved
args := []string{"zypper", "--non-interactive", "install", "systemd-network"}
if _, err := mgr.logAndRunCommand(handle, args); err != nil {
return fmt.Errorf("Could not install systemd-network: %w", err)
}
// The systemd-network and systemd-resolve users don't get added for
// some reason, even though the systemd services need to run as them
if err := mgr.addSystemUser(handle, "systemd-resolve", "systemd Resolver"); err != nil {
return err
}
if err := mgr.addSystemUser(handle, "systemd-network", "systemd Network Management"); err != nil {
return err
}
// nsswitch.conf doesn't get updated either
args = []string{
"sed",
"-i",
`s/^hosts:/hosts:\t\tfiles myhostname resolve [!UNAVAIL=return] dns/`,
"/usr/etc/nsswitch.conf",
}
if _, err := mgr.logAndRunCommand(handle, args); err != nil {
return fmt.Errorf("Could not update nsswitch.conf: %w", err)
}
return nil
}

View File

@ -56,14 +56,14 @@ type IDistroSpecificTemplateManager interface {
// (but does not upgrade) the packages for this distro, e.g.
// "sudo apt update".
CommandToUpdatePackageCache() []string
// InstallNetworkManager installs the OS-specific package for
// NetworkManager.
InstallNetworkManager(handle *guestfs.Guestfs) error
// InstallSystemdResolved installs the OS-specific package for
// systemd-resolved.
InstallSystemdResolved(handle *guestfs.Guestfs) error
}
func (mgr *TemplateManager) InstallNetworkManager(handle *guestfs.Guestfs) error {
func (mgr *TemplateManager) InstallSystemdResolved(handle *guestfs.Guestfs) error {
// Individual distros should override this method if necessary
return errors.New("InstallNetworkManager: not implemented for this distro")
return errors.New("InstallSystemdResolved: not implemented for this distro")
}
func (mgr *TemplateManager) DownloadTemplateGeneric(filename, url string) (path string, err error) {
@ -248,9 +248,12 @@ func (mgr *TemplateManager) logAndRunCommand(handle *guestfs.Guestfs, args []str
}
func (mgr *TemplateManager) enableSystemdUnit(handle *guestfs.Guestfs, unit string) error {
_, err := mgr.logAndRunCommand(handle, []string{
"systemctl", "enable", unit,
})
_, err := mgr.logAndRunCommand(handle, []string{"systemctl", "enable", unit})
return err
}
func (mgr *TemplateManager) disableSystemdUnit(handle *guestfs.Guestfs, unit string) error {
_, err := mgr.logAndRunCommand(handle, []string{"systemctl", "disable", unit})
return err
}
@ -440,6 +443,35 @@ func (mgr *TemplateManager) setNetworkManagerOptions(handle *guestfs.Guestfs) er
return fmt.Errorf("Could not create %s: %w", cfgFilePath, err)
}
}
// A bug was introduced in cloud-init commit 5942f40 which causes the DHCP
// server identifier in the dhclient lease file to be ignored. It is fixed by
// https://github.com/canonical/cloud-init/commit/cb36bf38b823f811a3e938ccffc03d7d13190095,
// but as of this writing (2024-01-13), this fix is not present in any official
// distro packages yet.
// As a workaround, we will install systemd-resolved, whose NSS module
// nss-resolve has a higher priority than "dns" for the "hosts" database in
// nsswitch.conf. This allows cloud-init to resolve the "data-server" host name
// (by querying the CloudStack DNS server instead of the ones which we wrote in
// /etc/resolv.conf), so it will not need to read any DHCP lease files.
// We can remove this workaround once the aforementioned fix gets shipped to
// all of the distros which we support.
resolvedIsPresent, err := handle.Is_file("/lib/systemd/systemd-resolved", nil)
if err != nil {
return fmt.Errorf("Could not determine if /lib/systemd/systemd-resolved is a file: %w", err)
}
if !resolvedIsPresent {
if err = mgr.impl.InstallSystemdResolved(handle); err != nil {
return err
}
if err = mgr.enableSystemdUnit(handle, "systemd-resolved"); err != nil {
return err
}
// Make sure that systemd-networkd isn't enabled or else it'll interfere
// with NetworkManager
if err = mgr.disableSystemdUnit(handle, "systemd-networkd"); err != nil {
return err
}
}
return nil
}
@ -466,20 +498,6 @@ func (mgr *TemplateManager) addSystemdNetworkdCloudInitSnippet(handle *guestfs.G
return handle.Write(path, getResource("systemd-networkd-cloud-init"))
}
func (mgr *TemplateManager) installAndEnableNetworkManager(handle *guestfs.Guestfs) error {
isInstalled, err := handle.Is_file("/lib/systemd/system/NetworkManager.service", nil)
if err != nil {
return err
}
if !isInstalled {
err = mgr.impl.InstallNetworkManager(handle)
if err != nil {
return err
}
}
return mgr.enableSystemdUnit(handle, "NetworkManager.service")
}
func (mgr *TemplateManager) setupCommonNetworkConfigs(handle *guestfs.Guestfs) error {
usesNetworkManager, err := mgr.usesNetworkManager(handle)
if err != nil {
@ -502,12 +520,7 @@ func (mgr *TemplateManager) setupCommonNetworkConfigs(handle *guestfs.Guestfs) e
if usesEtcNetworkInterfaces {
return mgr.setDhclientOptions(handle)
}
mgr.logger.Info().Msg("Could not determine network backend, resorting to installing NetworkManager")
err = mgr.installAndEnableNetworkManager(handle)
if err != nil {
return err
}
return mgr.setNetworkManagerOptions(handle)
return errors.New("Could not determine network backend")
}
func (mgr *TemplateManager) setupIpv6Scripts(handle *guestfs.Guestfs) (err error) {