github.com/containers/podman/v4@v4.9.4/pkg/machine/wsl/fedora.go (about) 1 //go:build windows 2 // +build windows 3 4 package wsl 5 6 import ( 7 "errors" 8 "fmt" 9 "io" 10 "net/http" 11 "net/url" 12 "os" 13 "path" 14 "path/filepath" 15 "strings" 16 "time" 17 18 "github.com/containers/podman/v4/pkg/machine" 19 "github.com/containers/podman/v4/pkg/machine/define" 20 ) 21 22 const ( 23 githubX86ReleaseURL = "https://github.com/containers/podman-wsl-fedora/releases/latest/download/rootfs.tar.xz" 24 githubArmReleaseURL = "https://github.com/containers/podman-wsl-fedora-arm/releases/latest/download/rootfs.tar.xz" 25 ) 26 27 type FedoraDownload struct { 28 machine.Download 29 } 30 31 func NewFedoraDownloader(vmType machine.VMType, vmName, releaseStream string) (machine.DistributionDownload, error) { 32 downloadURL, version, arch, size, err := getFedoraDownload() 33 if err != nil { 34 return nil, err 35 } 36 37 cacheDir, err := machine.GetCacheDir(vmType) 38 if err != nil { 39 return nil, err 40 } 41 42 imageName := fmt.Sprintf("fedora-podman-%s-%s.tar.xz", arch, version) 43 44 f := FedoraDownload{ 45 Download: machine.Download{ 46 Arch: machine.GetFcosArch(), 47 Artifact: define.None, 48 CacheDir: cacheDir, 49 Format: define.Tar, 50 ImageName: imageName, 51 LocalPath: filepath.Join(cacheDir, imageName), 52 URL: downloadURL, 53 VMName: vmName, 54 Size: size, 55 }, 56 } 57 dataDir, err := machine.GetDataDir(vmType) 58 if err != nil { 59 return nil, err 60 } 61 f.Download.LocalUncompressedFile = f.GetLocalUncompressedFile(dataDir) 62 return f, nil 63 } 64 65 func (f FedoraDownload) Get() *machine.Download { 66 return &f.Download 67 } 68 69 func (f FedoraDownload) HasUsableCache() (bool, error) { 70 info, err := os.Stat(f.LocalPath) 71 if err != nil { 72 if errors.Is(err, os.ErrNotExist) { 73 return false, nil 74 } 75 return false, err 76 } 77 return info.Size() == f.Size, nil 78 } 79 80 func (f FedoraDownload) CleanCache() error { 81 // Set cached image to expire after 2 weeks 82 expire := 14 * 24 * time.Hour 83 return machine.RemoveImageAfterExpire(f.CacheDir, expire) 84 } 85 86 func getFedoraDownload() (*url.URL, string, string, int64, error) { 87 var releaseURL string 88 arch := machine.DetermineMachineArch() 89 switch arch { 90 case "arm64": 91 releaseURL = githubArmReleaseURL 92 case "amd64": 93 releaseURL = githubX86ReleaseURL 94 default: 95 return nil, "", "", -1, fmt.Errorf("CPU architecture %q is not supported", arch) 96 } 97 98 downloadURL, err := url.Parse(releaseURL) 99 if err != nil { 100 return nil, "", "", -1, fmt.Errorf("invalid URL generated from discovered Fedora file: %s: %w", releaseURL, err) 101 } 102 103 resp, err := http.Head(releaseURL) 104 if err != nil { 105 return nil, "", "", -1, fmt.Errorf("head request failed: %s: %w", releaseURL, err) 106 } 107 _ = resp.Body.Close() 108 contentLen := resp.ContentLength 109 110 if resp.StatusCode != http.StatusOK { 111 return nil, "", "", -1, fmt.Errorf("head request failed: %s: %w", releaseURL, err) 112 } 113 114 verURL := *downloadURL 115 verURL.Path = path.Join(path.Dir(downloadURL.Path), "version") 116 117 resp, err = http.Get(verURL.String()) 118 if err != nil { 119 return nil, "", "", -1, fmt.Errorf("get request failed: %s: %w", verURL.String(), err) 120 } 121 122 defer resp.Body.Close() 123 bytes, err := io.ReadAll(&io.LimitedReader{R: resp.Body, N: 1024}) 124 if err != nil { 125 return nil, "", "", -1, fmt.Errorf("failed reading: %s: %w", verURL.String(), err) 126 } 127 128 return downloadURL, strings.TrimSpace(string(bytes)), arch, contentLen, nil 129 }