github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/machine/fedora.go (about) 1 //go:build amd64 || arm64 2 // +build amd64 arm64 3 4 package machine 5 6 import ( 7 "fmt" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "net/url" 12 "os" 13 "path/filepath" 14 "regexp" 15 16 "github.com/pkg/errors" 17 "github.com/sirupsen/logrus" 18 ) 19 20 const ( 21 githubURL = "http://github.com/fedora-cloud/docker-brew-fedora/" 22 ) 23 24 var fedoraxzRegex = regexp.MustCompile(`fedora[^\"]+xz`) 25 26 type FedoraDownload struct { 27 Download 28 } 29 30 func NewFedoraDownloader(vmType, vmName, releaseStream string) (DistributionDownload, error) { 31 imageName, downloadURL, size, err := getFedoraDownload(releaseStream) 32 if err != nil { 33 return nil, err 34 } 35 36 dataDir, err := GetDataDir(vmType) 37 if err != nil { 38 return nil, err 39 } 40 41 f := FedoraDownload{ 42 Download: Download{ 43 Arch: getFcosArch(), 44 Artifact: artifact, 45 Format: Format, 46 ImageName: imageName, 47 LocalPath: filepath.Join(dataDir, imageName), 48 URL: downloadURL, 49 VMName: vmName, 50 Size: size, 51 }, 52 } 53 f.Download.LocalUncompressedFile = f.getLocalUncompressedName() 54 return f, nil 55 } 56 57 func (f FedoraDownload) Get() *Download { 58 return &f.Download 59 } 60 61 func (f FedoraDownload) HasUsableCache() (bool, error) { 62 info, err := os.Stat(f.LocalPath) 63 if err != nil { 64 if errors.Is(err, os.ErrNotExist) { 65 return false, nil 66 } 67 return false, err 68 } 69 return info.Size() == f.Size, nil 70 } 71 72 func truncRead(url string) ([]byte, error) { 73 resp, err := http.Get(url) 74 if err != nil { 75 return nil, err 76 } 77 78 defer func() { 79 if err := resp.Body.Close(); err != nil { 80 logrus.Error(err) 81 } 82 }() 83 84 body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 10*1024*1024)) 85 if err != nil { 86 return nil, err 87 } 88 89 _, _ = io.Copy(io.Discard, resp.Body) 90 91 return body, nil 92 } 93 94 func getFedoraDownload(releaseStream string) (string, *url.URL, int64, error) { 95 dirURL := githubURL + "tree/" + releaseStream + "/" + getFcosArch() + "/" 96 body, err := truncRead(dirURL) 97 if err != nil { 98 return "", nil, -1, err 99 } 100 101 file := fedoraxzRegex.FindString(string(body)) 102 if len(file) == 0 { 103 return "", nil, -1, fmt.Errorf("could not locate Fedora download at %s", dirURL) 104 } 105 106 rawURL := githubURL + "raw/" + releaseStream + "/" + getFcosArch() + "/" 107 newLocation := rawURL + file 108 downloadURL, err := url.Parse(newLocation) 109 if err != nil { 110 return "", nil, -1, errors.Wrapf(err, "invalid URL generated from discovered Fedora file: %s", newLocation) 111 } 112 113 resp, err := http.Head(newLocation) 114 if err != nil { 115 return "", nil, -1, errors.Wrapf(err, "head request failed: %s", newLocation) 116 } 117 _ = resp.Body.Close() 118 119 if resp.StatusCode != http.StatusOK { 120 return "", nil, -1, fmt.Errorf("head request failed [%d] on download: %s", resp.StatusCode, newLocation) 121 } 122 123 return file, downloadURL, resp.ContentLength, nil 124 }