From de09668913aecfd821245e433953ab1a8551abf5 Mon Sep 17 00:00:00 2001 From: Max Erenberg Date: Sun, 18 Jun 2023 15:06:45 -0400 Subject: [PATCH] dynamically determine network backend --- Makefile | 2 +- pkg/distros/almalinux.go | 12 +- pkg/distros/debian.go | 13 +- pkg/distros/fedora.go | 12 +- pkg/distros/opensuse_tumbleweed.go | 3 - .../resources/systemd-networkd-cloud-init | 8 ++ pkg/distros/resources/ubuntu-cloud-init | 9 -- pkg/distros/template_manager.go | 132 ++++++++++++++++-- pkg/distros/ubuntu.go | 12 +- scripts/download-deps.sh | 2 + 10 files changed, 143 insertions(+), 62 deletions(-) create mode 100644 pkg/distros/resources/systemd-networkd-cloud-init diff --git a/Makefile b/Makefile index 8de0978..4cbb7eb 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ APPLIANCE_VERSION = 1.46.0 # Export LIBGUESTFS_DEBUG=1 to debug all: - LIBRARY_PATH=$(LIBRARY_PATH) go build + LIBRARY_PATH=$(LIBRARY_PATH) CGO_LDFLAGS="-lguestfs -lvirt -lyajl" go build run: LD_LIBRARY_PATH=$(LIBRARY_PATH) LIBGUESTFS_PATH=$(LIBGUESTFS_PATH) LIBGUESTFS_HV=$(LIBGUESTFS_HV) LIBGUESTFS_BACKEND_SETTINGS=force_tcg ./cloudbuild diff --git a/pkg/distros/almalinux.go b/pkg/distros/almalinux.go index 594d16e..c4ebfd5 100644 --- a/pkg/distros/almalinux.go +++ b/pkg/distros/almalinux.go @@ -68,8 +68,8 @@ func (mgr *AlmaLinuxTemplateManager) DownloadTemplate(version, codename string) return mgr.DownloadTemplateGeneric(filename, url) } -func (mgr *AlmaLinuxTemplateManager) addCloudInitSnippet(handle *guestfs.Guestfs) error { - path := "/etc/cloud/cloud.cfg.d/99_csclub.cfg" +func (mgr *AlmaLinuxTemplateManager) addAlmaLinuxCloudInitSnippet(handle *guestfs.Guestfs) error { + path := "/etc/cloud/cloud.cfg.d/99_csclub_misc.cfg" mgr.logger.Debug().Msg("Writing to " + path) return handle.Write(path, getResource("fedora-cloud-init")) } @@ -92,13 +92,7 @@ func (mgr *AlmaLinuxTemplateManager) transformAlmaLinuxYumRepoBaseUrl(url string } func (mgr *AlmaLinuxTemplateManager) PerformDistroSpecificModifications(handle *guestfs.Guestfs) (err error) { - if err = mgr.setChronyOptions(handle); err != nil { - return - } - if err = mgr.setNetworkManagerOptions(handle); err != nil { - return - } - if err = mgr.addCloudInitSnippet(handle); err != nil { + if err = mgr.addAlmaLinuxCloudInitSnippet(handle); err != nil { return } if err = mgr.replaceYumMirrorUrls(handle, mgr.transformAlmaLinuxYumRepoBaseUrl); err != nil { diff --git a/pkg/distros/debian.go b/pkg/distros/debian.go index 9a67885..0af76d2 100644 --- a/pkg/distros/debian.go +++ b/pkg/distros/debian.go @@ -75,15 +75,6 @@ func (mgr *DebianTemplateManager) CommandToUpdatePackageCache() []string { return debianCommandToUpdatePackageCache() } -func (mgr *DebianTemplateManager) PerformDistroSpecificModifications(handle *guestfs.Guestfs) (err error) { - if err = mgr.setChronyOptions(handle); err != nil { - return - } - if err = mgr.setDhclientOptions(handle); err != nil { - return - } - if err = mgr.replaceDebianMirrorUrls(handle); err != nil { - return - } - return +func (mgr *DebianTemplateManager) PerformDistroSpecificModifications(handle *guestfs.Guestfs) error { + return mgr.replaceDebianMirrorUrls(handle) } diff --git a/pkg/distros/fedora.go b/pkg/distros/fedora.go index 8498601..370a031 100644 --- a/pkg/distros/fedora.go +++ b/pkg/distros/fedora.go @@ -113,8 +113,8 @@ func (mgr *FedoraTemplateManager) DownloadTemplate(version, codename string) (pa return mgr.DownloadTemplateGeneric(filename, url) } -func (mgr *FedoraTemplateManager) addCloudInitSnippet(handle *guestfs.Guestfs) error { - path := "/etc/cloud/cloud.cfg.d/99_csclub.cfg" +func (mgr *FedoraTemplateManager) addFedoraCloudInitSnippet(handle *guestfs.Guestfs) error { + path := "/etc/cloud/cloud.cfg.d/99_csclub_misc.cfg" mgr.logger.Debug().Msg("Writing to " + path) return handle.Write(path, getResource("fedora-cloud-init")) } @@ -137,13 +137,7 @@ func (mgr *FedoraTemplateManager) transformFedoraYumRepoBaseUrl(url string) stri } func (mgr *FedoraTemplateManager) PerformDistroSpecificModifications(handle *guestfs.Guestfs) (err error) { - if err = mgr.setChronyOptions(handle); err != nil { - return - } - if err = mgr.setNetworkManagerOptions(handle); err != nil { - return - } - if err = mgr.addCloudInitSnippet(handle); err != nil { + if err = mgr.addFedoraCloudInitSnippet(handle); err != nil { return } if err = mgr.replaceYumMirrorUrls(handle, mgr.transformFedoraYumRepoBaseUrl); err != nil { diff --git a/pkg/distros/opensuse_tumbleweed.go b/pkg/distros/opensuse_tumbleweed.go index 04ec502..7042d6d 100644 --- a/pkg/distros/opensuse_tumbleweed.go +++ b/pkg/distros/opensuse_tumbleweed.go @@ -97,9 +97,6 @@ func (mgr *OpensuseTumbleweedTemplateManager) CommandToUpdatePackageCache() []st } func (mgr *OpensuseTumbleweedTemplateManager) PerformDistroSpecificModifications(handle *guestfs.Guestfs) (err error) { - if err = mgr.setChronyOptions(handle); err != nil { - return - } if err = mgr.maskSystemdUnit(handle, "wickedd-dhcp6.service"); err != nil { return } diff --git a/pkg/distros/resources/systemd-networkd-cloud-init b/pkg/distros/resources/systemd-networkd-cloud-init new file mode 100644 index 0000000..f584158 --- /dev/null +++ b/pkg/distros/resources/systemd-networkd-cloud-init @@ -0,0 +1,8 @@ +network: + version: 2 + ethernets: + id0: + match: + name: e* + dhcp4: true + accept-ra: false diff --git a/pkg/distros/resources/ubuntu-cloud-init b/pkg/distros/resources/ubuntu-cloud-init index 5a13e97..992b775 100644 --- a/pkg/distros/resources/ubuntu-cloud-init +++ b/pkg/distros/resources/ubuntu-cloud-init @@ -1,11 +1,2 @@ -network: - version: 2 - ethernets: - id0: - match: - name: e* - dhcp4: true - accept-ra: false - apt_preserve_sources_list: true manage_etc_hosts: true diff --git a/pkg/distros/template_manager.go b/pkg/distros/template_manager.go index 2c4b0e5..2903548 100644 --- a/pkg/distros/template_manager.go +++ b/pkg/distros/template_manager.go @@ -106,12 +106,18 @@ func fedoraCommandToUpdatePackageCache() []string { } func (mgr *TemplateManager) performDistroAgnosticModifications(handle *guestfs.Guestfs) (err error) { + if err = mgr.setupCommonNetworkConfigs(handle); err != nil { + return + } if err = mgr.setupIpv6Scripts(handle); err != nil { return } if err = mgr.setResolvConf(handle); err != nil { return } + if err = mgr.setupCommonNTPConfigs(handle); err != nil { + return + } if err = mgr.setMotd(handle); err != nil { return } @@ -242,6 +248,33 @@ func (mgr *TemplateManager) maskSystemdUnit(handle *guestfs.Guestfs, unit string return handle.Ln_sf("/dev/null", "/etc/systemd/system/"+unit) } +func systemdServiceIsEnabled(handle *guestfs.Guestfs, unit string) (bool, error) { + linkName := "" + for _, dirPrefix := range []string{"/etc", "/lib"} { + linkName = dirPrefix + "/systemd/system/multi-user.target.wants/" + unit + isSymlink, err := handle.Is_symlink(linkName) + if err != nil { + return false, fmt.Errorf("could not determine if %s is a symlink: %w", linkName, err) + } + if isSymlink { + break + } + } + if linkName == "" { + return false, nil + } + target, err := handle.Readlink(linkName) + if err != nil { + return false, fmt.Errorf("could not read link at %s: %w", linkName, err) + } + for _, dirPrefix := range []string{"/etc", "/lib"} { + if target == dirPrefix+"/systemd/system/"+unit { + return true, nil + } + } + return false, nil +} + // setChronyOptions sets custom NTP server URLs in a chrony config file. func (mgr *TemplateManager) setChronyOptions(handle *guestfs.Guestfs) (err error) { possiblePaths := []string{"/etc/chrony.conf", "/etc/chrony/chrony.conf"} @@ -315,8 +348,7 @@ func (mgr *TemplateManager) setChronyOptions(handle *guestfs.Guestfs) (err error // Otherwise, assume we need to modify chrony.conf directly // e.g. Fedora if newLines == nil { - mgr.logger.Warn().Msg("could not find chrony.conf, skipping") - return + return errors.New("could not find chrony.conf") } serverDirectiveExists := false for _, line := range newLines { @@ -334,6 +366,45 @@ func (mgr *TemplateManager) setChronyOptions(handle *guestfs.Guestfs) (err error return handle.Write(path, []byte(newContent)) } +func (mgr *TemplateManager) setTimesyncdConf(handle *guestfs.Guestfs) (err error) { + mgr.logger.Debug().Msg("Writing custom timesyncd.conf") + if err = handle.Mkdir_p("/etc/systemd/timesyncd.conf.d"); err != nil { + return + } + return handle.Write("/etc/systemd/timesyncd.conf.d/csclub.conf", getResource("timesyncd.conf")) +} + +func usesChrony(handle *guestfs.Guestfs) (bool, error) { + // The systemd service for chrony is called on chrony.service on e.g. Debian, + // but is called chronyd.service on e.g. Fedora + chronyIsEnabled, err := systemdServiceIsEnabled(handle, "chrony.service") + if err != nil { + return false, err + } + if chronyIsEnabled { + return true, nil + } + return systemdServiceIsEnabled(handle, "chronyd.service") +} + +func (mgr *TemplateManager) setupCommonNTPConfigs(handle *guestfs.Guestfs) error { + usesChrony, err := usesChrony(handle) + if err != nil { + return err + } + if usesChrony { + return mgr.setChronyOptions(handle) + } + usesSystemdTimesyncd, err := systemdServiceIsEnabled(handle, "systemd-timesyncd.service") + if err != nil { + return err + } + if usesSystemdTimesyncd { + return mgr.setTimesyncdConf(handle) + } + return errors.New("could not determine NTP backend") +} + func (mgr *TemplateManager) setNetworkManagerOptions(handle *guestfs.Guestfs) (err error) { if err = handle.Mkdir_p("/etc/NetworkManager/conf.d"); err != nil { return @@ -344,7 +415,54 @@ func (mgr *TemplateManager) setNetworkManagerOptions(handle *guestfs.Guestfs) (e } func usesNetworkManager(handle *guestfs.Guestfs) (bool, error) { - return handle.Is_file("/usr/sbin/NetworkManager", nil) + return systemdServiceIsEnabled(handle, "NetworkManager.service") +} + +func usesEtcNetworkInterfaces(handle *guestfs.Guestfs) (bool, error) { + configPath := "/etc/network/interfaces" + configExists, err := handle.Is_file(configPath, nil) + if err != nil { + return false, fmt.Errorf("Could not determine if "+configPath+" is a file: %w", err) + } + if !configExists { + return false, nil + } + return systemdServiceIsEnabled(handle, "networking.service") +} + +func (mgr *TemplateManager) addSystemdNetworkdCloudInitSnippet(handle *guestfs.Guestfs) error { + // Use 98 so that each distro can use 99 for extra customization + path := "/etc/cloud/cloud.cfg.d/98_csclub_network.cfg" + mgr.logger.Debug().Msg("Writing to " + path) + return handle.Write(path, getResource("systemd-networkd-cloud-init")) +} + +func (mgr *TemplateManager) setupCommonNetworkConfigs(handle *guestfs.Guestfs) error { + usesNetworkManager, err := usesNetworkManager(handle) + if err != nil { + return err + } + if usesNetworkManager { + return mgr.setNetworkManagerOptions(handle) + } + usesSystemdNetworkd, err := systemdServiceIsEnabled(handle, "systemd-networkd.service") + if err != nil { + return err + } + if usesSystemdNetworkd { + return mgr.addSystemdNetworkdCloudInitSnippet(handle) + } + usesEtcNetworkInterfaces, err := usesEtcNetworkInterfaces(handle) + if err != nil { + return err + } + if usesEtcNetworkInterfaces { + return mgr.setDhclientOptions(handle) + } + // The only other network backend used by one of our supported distros is + // Sysconfig, which is currently only used by OpenSUSE Tumbleweed. + // That case is handled separately in opensuse_tumbleweed.go. + return nil } func (mgr *TemplateManager) setupIpv6Scripts(handle *guestfs.Guestfs) (err error) { @@ -703,14 +821,6 @@ func (mgr *TemplateManager) updateSshdConfig(handle *guestfs.Guestfs) error { return handle.Aug_set("/files/etc/ssh/sshd_config/PrintLastLog", "no") } -func (mgr *TemplateManager) setTimesyncdConf(handle *guestfs.Guestfs) (err error) { - mgr.logger.Debug().Msg("Writing custom timesyncd.conf") - if err = handle.Mkdir_p("/etc/systemd/timesyncd.conf.d"); err != nil { - return - } - return handle.Write("/etc/systemd/timesyncd.conf.d/csclub.conf", getResource("timesyncd.conf")) -} - func (mgr *TemplateManager) setJournaldConf(handle *guestfs.Guestfs) (err error) { mgr.logger.Debug().Msg("Writing custom journald.conf") if err = handle.Mkdir_p("/etc/systemd/journald.conf.d"); err != nil { diff --git a/pkg/distros/ubuntu.go b/pkg/distros/ubuntu.go index 66a7bb5..631c355 100644 --- a/pkg/distros/ubuntu.go +++ b/pkg/distros/ubuntu.go @@ -79,8 +79,8 @@ func (mgr *UbuntuTemplateManager) DownloadTemplate(version, codename string) (pa return mgr.DownloadTemplateGeneric(filename, url) } -func (mgr *UbuntuTemplateManager) addCloudInitSnippet(handle *guestfs.Guestfs) error { - path := "/etc/cloud/cloud.cfg.d/99_csclub.cfg" +func (mgr *UbuntuTemplateManager) addUbuntuCloudInitSnippet(handle *guestfs.Guestfs) error { + path := "/etc/cloud/cloud.cfg.d/99_csclub_misc.cfg" mgr.logger.Debug().Msg("Writing to " + path) return handle.Write(path, getResource("ubuntu-cloud-init")) } @@ -109,16 +109,10 @@ func (mgr *UbuntuTemplateManager) CommandToUpdatePackageCache() []string { } func (mgr *UbuntuTemplateManager) PerformDistroSpecificModifications(handle *guestfs.Guestfs) (err error) { - if err = mgr.setTimesyncdConf(handle); err != nil { - return - } - if err = mgr.setDhclientOptions(handle); err != nil { - return - } if err = mgr.replaceDebianMirrorUrls(handle); err != nil { return } - if err = mgr.addCloudInitSnippet(handle); err != nil { + if err = mgr.addUbuntuCloudInitSnippet(handle); err != nil { return } mgr.disableNoisyMotdMessages(handle) diff --git a/scripts/download-deps.sh b/scripts/download-deps.sh index 1998ce8..5340aab 100755 --- a/scripts/download-deps.sh +++ b/scripts/download-deps.sh @@ -27,6 +27,7 @@ libvirt_dependencies=( libvdeplug2 libvirglrenderer1 libvirt0 + libvirt-dev libxencall1 libxendevicemodel1 libxenevtchn1 @@ -37,6 +38,7 @@ libvirt_dependencies=( libxentoolcore1 libxentoollog1 libyajl2 + libyajl-dev qemu-system-x86 seabios )