127 lines
3.9 KiB
Go
127 lines
3.9 KiB
Go
package distros
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"regexp"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
"libguestfs.org/guestfs"
|
|
|
|
"git.csclub.uwaterloo.ca/cloud/cloudbuild/pkg/config"
|
|
)
|
|
|
|
type DebianTemplateManager struct {
|
|
TemplateManager
|
|
}
|
|
|
|
// NewDebianTemplateManager returns a DebianTemplateManager with the given
|
|
// config values.
|
|
func NewDebianTemplateManager(cfg *config.Config) *DebianTemplateManager {
|
|
logger := log.With().Str("distro", "debian").Logger()
|
|
debianTemplateManager := DebianTemplateManager{
|
|
TemplateManager{
|
|
cfg: cfg,
|
|
logger: &logger,
|
|
impl: nil,
|
|
},
|
|
}
|
|
debianTemplateManager.TemplateManager.impl = &debianTemplateManager
|
|
return &debianTemplateManager
|
|
}
|
|
|
|
func (mgr *DebianTemplateManager) GetLatestVersion() (version string, codename string, err error) {
|
|
// We're only interested in the major version (integer part)
|
|
versionPattern := regexp.MustCompile(`^Version: (\d+)(?:\.\d+)?$`)
|
|
codenamePattern := regexp.MustCompile("^Codename: ([a-z-]+)$")
|
|
resp, err := http.Get("https://mirror.csclub.uwaterloo.ca/debian/dists/stable/InRelease")
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
scanner := bufio.NewScanner(resp.Body)
|
|
for scanner.Scan() {
|
|
if version == "" {
|
|
submatches := versionPattern.FindStringSubmatch(scanner.Text())
|
|
if submatches != nil {
|
|
version = submatches[1]
|
|
}
|
|
}
|
|
if codename == "" {
|
|
submatches := codenamePattern.FindStringSubmatch(scanner.Text())
|
|
if submatches != nil {
|
|
codename = submatches[1]
|
|
}
|
|
}
|
|
if version != "" && codename != "" {
|
|
break
|
|
}
|
|
}
|
|
if version == "" {
|
|
err = errors.New("Could not determine latest version of Debian")
|
|
}
|
|
return
|
|
}
|
|
|
|
func (mgr *DebianTemplateManager) DownloadTemplate(version, codename string) (path string, err error) {
|
|
filename := fmt.Sprintf("debian-%s-genericcloud-amd64.qcow2", version)
|
|
url := fmt.Sprintf("https://cloud.debian.org/images/cloud/%s/latest/%s", codename, filename)
|
|
return mgr.DownloadTemplateGeneric(filename, url)
|
|
}
|
|
|
|
func (mgr *DebianTemplateManager) replaceFailsafeMirrorsInCloudCfg(handle *guestfs.Guestfs) error {
|
|
// In Debian 12 (bookworm), /etc/cloud/cloud.cfg has the following snippet:
|
|
//
|
|
// system_info:
|
|
// package_mirrors:
|
|
// - arches: [default]
|
|
// failsafe:
|
|
// primary: https://deb.debian.org/debian
|
|
// security: https://deb.debian.org/debian-security
|
|
//
|
|
// Since we can't override the system_info settings, we need to overwrite this file.
|
|
filePaths := []string{"/etc/cloud/cloud.cfg"}
|
|
// To be safe, we check other config files under /etc/cloud/cloud.cfg.d as well.
|
|
extraFilePaths, err := handle.Glob_expand("/etc/cloud/cloud.cfg.d/*.cfg", nil)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not expand glob /etc/cloud/cloud.cfg.d/*.cfg: %w", err)
|
|
}
|
|
filePaths = append(filePaths, extraFilePaths...)
|
|
debMirrorUrlRegex := regexp.MustCompile(`https?://deb\.debian\.org`)
|
|
replacement := []byte("http://" + mgr.cfg.MirrorHost)
|
|
for _, filePath := range filePaths {
|
|
mgr.logger.Debug().Str("file", filePath).Msg("Checking for deb.debian.org URLs")
|
|
content, err := handle.Read_file(filePath)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not read %s: %w", filePath, err)
|
|
}
|
|
newContent := debMirrorUrlRegex.ReplaceAll(content, replacement)
|
|
if bytes.Equal(content, newContent) {
|
|
continue
|
|
}
|
|
mgr.logger.Debug().Str("file", filePath).Msg("Replacing deb.debian.org URLs")
|
|
err = handle.Write(filePath, newContent)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not write to %s: %w", filePath, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (mgr *DebianTemplateManager) CommandToUpdatePackageCache() []string {
|
|
return debianCommandToUpdatePackageCache()
|
|
}
|
|
|
|
func (mgr *DebianTemplateManager) PerformDistroSpecificModifications(handle *guestfs.Guestfs) error {
|
|
if err := mgr.replaceFailsafeMirrorsInCloudCfg(handle); err != nil {
|
|
return err
|
|
}
|
|
if err := mgr.replaceDebianMirrorUrls(handle); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|