Fixes #14698 Use prepared image for WSL2 machine init

This commit introduces a prepared image for setting up the WSL2
environment. This means that the deployment will take considerable
less time to finish (as it does not need to run an update and package
install), but also allows to rely on a cached image to re-init the
environment without the need for an internet connection.

[NO NEW TESTS NEEDED]

Signed-off-by: Gerard Braad <me@gbraad.nl>
This commit is contained in:
Gerard Braad
2022-07-13 05:36:06 +00:00
committed by Matthew Heon
parent a4bae330a5
commit a5827e13cd
2 changed files with 17 additions and 76 deletions

View File

@ -6,29 +6,23 @@ package machine
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"net/http"
"net/url"
"os"
"path/filepath"
"regexp"
"github.com/sirupsen/logrus"
)
const (
githubURL = "http://github.com/fedora-cloud/docker-brew-fedora/"
githubLatestReleaseURL = "https://github.com/containers/podman-wsl-fedora/releases/latest/download/rootfs.tar.xz"
)
var fedoraxzRegex = regexp.MustCompile(`fedora[^\"]+xz`)
type FedoraDownload struct {
Download
}
func NewFedoraDownloader(vmType, vmName, releaseStream string) (DistributionDownload, error) {
imageName, downloadURL, size, err := getFedoraDownload(releaseStream)
downloadURL, size, err := getFedoraDownload(githubLatestReleaseURL)
if err != nil {
return nil, err
}
@ -38,6 +32,8 @@ func NewFedoraDownloader(vmType, vmName, releaseStream string) (DistributionDown
return nil, err
}
imageName := "rootfs.tar.xz"
f := FedoraDownload{
Download: Download{
Arch: getFcosArch(),
@ -69,56 +65,21 @@ func (f FedoraDownload) HasUsableCache() (bool, error) {
return info.Size() == f.Size, nil
}
func truncRead(url string) ([]byte, error) {
resp, err := http.Get(url)
func getFedoraDownload(releaseURL string) (*url.URL, int64, error) {
downloadURL, err := url.Parse(releaseURL)
if err != nil {
return nil, err
return nil, -1, fmt.Errorf("invalid URL generated from discovered Fedora file: %s: %w", releaseURL, err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
logrus.Error(err)
}
}()
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 10*1024*1024))
resp, err := http.Head(releaseURL)
if err != nil {
return nil, err
}
_, _ = io.Copy(io.Discard, resp.Body)
return body, nil
}
func getFedoraDownload(releaseStream string) (string, *url.URL, int64, error) {
dirURL := githubURL + "tree/" + releaseStream + "/" + getFcosArch() + "/"
body, err := truncRead(dirURL)
if err != nil {
return "", nil, -1, err
}
file := fedoraxzRegex.FindString(string(body))
if len(file) == 0 {
return "", nil, -1, fmt.Errorf("could not locate Fedora download at %s", dirURL)
}
rawURL := githubURL + "raw/" + releaseStream + "/" + getFcosArch() + "/"
newLocation := rawURL + file
downloadURL, err := url.Parse(newLocation)
if err != nil {
return "", nil, -1, fmt.Errorf("invalid URL generated from discovered Fedora file: %s: %w", newLocation, err)
}
resp, err := http.Head(newLocation)
if err != nil {
return "", nil, -1, fmt.Errorf("head request failed: %s: %w", newLocation, err)
return nil, -1, fmt.Errorf("head request failed: %s: %w", releaseURL, err)
}
_ = resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", nil, -1, fmt.Errorf("head request failed [%d] on download: %s", resp.StatusCode, newLocation)
return nil, -1, fmt.Errorf("head request failed: %s: %w", releaseURL, err)
}
return file, downloadURL, resp.ContentLength, nil
return downloadURL, resp.ContentLength, nil
}

View File

@ -386,7 +386,7 @@ func downloadDistro(v *MachineVM, opts machine.InitOptions) error {
if _, e := strconv.Atoi(opts.ImagePath); e == nil {
v.ImageStream = opts.ImagePath
dd, err = machine.NewFedoraDownloader(vmtype, v.Name, v.ImageStream)
dd, err = machine.NewFedoraDownloader(vmtype, v.Name, opts.ImagePath)
} else {
v.ImageStream = "custom"
dd, err = machine.NewGenericDownloader(vmtype, v.Name, opts.ImagePath)
@ -449,34 +449,14 @@ func provisionWSLDist(v *MachineVM) (string, error) {
}
dist := toDist(v.Name)
fmt.Println("Importing operating system into WSL (this may take 5+ minutes on a new WSL install)...")
fmt.Println("Importing operating system into WSL (this may take a few minutes on a new WSL install)...")
if err = runCmdPassThrough("wsl", "--import", dist, distTarget, v.ImagePath); err != nil {
return "", fmt.Errorf("the WSL import of guest OS failed: %w", err)
}
fmt.Println("Installing packages (this will take awhile)...")
if err = runCmdPassThrough("wsl", "-d", dist, "dnf", "upgrade", "-y"); err != nil {
return "", fmt.Errorf("package upgrade on guest OS failed: %w", err)
}
fmt.Println("Enabling Copr")
if err = runCmdPassThrough("wsl", "-d", dist, "dnf", "install", "-y", "'dnf-command(copr)'"); err != nil {
return "", fmt.Errorf("enabling copr failed: %w", err)
}
fmt.Println("Enabling podman4 repo")
if err = runCmdPassThrough("wsl", "-d", dist, "dnf", "-y", "copr", "enable", "rhcontainerbot/podman4"); err != nil {
return "", fmt.Errorf("enabling copr failed: %w", err)
}
if err = runCmdPassThrough("wsl", "-d", dist, "dnf", "install",
"podman", "podman-docker", "openssh-server", "procps-ng", "-y"); err != nil {
return "", fmt.Errorf("package installation on guest OS failed: %w", err)
}
// Fixes newuidmap
if err = runCmdPassThrough("wsl", "-d", dist, "dnf", "reinstall", "shadow-utils", "-y"); err != nil {
return "", fmt.Errorf("package reinstallation of shadow-utils on guest OS failed: %w", err)
if err = runCmdPassThrough("wsl", "-d", dist, "rpm", "-q", "--restore", "shadow-utils", "2>/dev/null"); err != nil {
return "", fmt.Errorf("package permissions restore of shadow-utils on guest OS failed: %w", err)
}
// Windows 11 (NT Version = 10, Build 22000) generates harmless but scary messages on every