1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
package e2e
import (
"os"
"path/filepath"
"strings"
"encoding/json"
"fmt"
"io"
"net/http"
"runtime"
"github.com/opencontainers/go-digest"
"github.com/coreos/stream-metadata-go/fedoracoreos"
"github.com/coreos/stream-metadata-go/stream"
"github.com/sirupsen/logrus"
)
type FcosDownload struct {
DataDir string
}
type fcosDownloadInfo struct {
Location string
Sha256Sum string
}
func NewFcosDownloader(dataDir string) (*FcosDownload, error) {
return &FcosDownload{
DataDir: dataDir,
}, nil
}
func imageName(info *fcosDownloadInfo) string {
urlSplit := strings.Split(info.Location, "/")
return urlSplit[len(urlSplit)-1]
}
func (downloader *FcosDownload) DownloadImage() (string, error) {
info, err := getFCOSDownload()
if err != nil {
return "", err
}
compressedImage := filepath.Join(downloader.DataDir, imageName(info))
uncompressedImage := strings.TrimSuffix(filepath.Join(filepath.Dir(compressedImage), imageName(info)), ".xz")
// check if the latest image is already present
ok, err := downloader.updateAvailable(info, compressedImage)
if err != nil {
return "", err
}
if !ok {
if err := DownloadVMImage(info.Location, compressedImage); err != nil {
return "", err
}
}
if _, err := os.Stat(uncompressedImage); err == nil {
return uncompressedImage, nil
}
if err := Decompress(compressedImage, uncompressedImage); err != nil {
return "", err
}
return uncompressedImage, nil
}
func (downloader *FcosDownload) updateAvailable(info *fcosDownloadInfo, compressedImage string) (bool, error) {
// check the sha of the local image if it exists
// get the sha of the remote image
// == dont bother to pull
if _, err := os.Stat(compressedImage); os.IsNotExist(err) {
return false, nil
}
fd, err := os.Open(compressedImage)
if err != nil {
return false, err
}
defer fd.Close()
sum, err := digest.SHA256.FromReader(fd)
if err != nil {
return false, err
}
if sum.Encoded() == info.Sha256Sum {
return true, nil
}
return false, nil
}
// as of 2024-05-28, these are the 4 architectures available in
// curl https://builds.coreos.fedoraproject.org/streams/next.json
func coreosArch() string {
switch runtime.GOARCH {
case "amd64":
return "x86_64"
case "arm64":
return "aarch64"
case "ppc64le":
return "ppc64le"
case "s390x":
return "s390x"
}
panic(fmt.Sprintf("unknown arch: %s", runtime.GOOS))
}
// This should get Exported and stay put as it will apply to all fcos downloads
// getFCOS parses fedoraCoreOS's stream and returns the image download URL and the release version
func getFCOSDownload() (*fcosDownloadInfo, error) {
streamurl := fedoracoreos.GetStreamURL(fedoracoreos.StreamNext)
resp, err := http.Get(streamurl.String())
if err != nil {
return nil, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
defer func() {
if err := resp.Body.Close(); err != nil {
logrus.Error(err)
}
}()
var fcosstable stream.Stream
if err := json.Unmarshal(body, &fcosstable); err != nil {
return nil, err
}
arch, ok := fcosstable.Architectures[coreosArch()]
if !ok {
return nil, fmt.Errorf("unable to pull VM image: no targetArch in stream")
}
artifacts := arch.Artifacts
if artifacts == nil {
return nil, fmt.Errorf("unable to pull VM image: no artifact in stream")
}
qemu, ok := artifacts["qemu"]
if !ok {
return nil, fmt.Errorf("unable to pull VM image: no qemu artifact in stream")
}
formats := qemu.Formats
if formats == nil {
return nil, fmt.Errorf("unable to pull VM image: no formats in stream")
}
qcow, ok := formats["qcow2.xz"]
if !ok {
return nil, fmt.Errorf("unable to pull VM image: no qcow2.xz format in stream")
}
disk := qcow.Disk
if disk == nil {
return nil, fmt.Errorf("unable to pull VM image: no disk in stream")
}
return &fcosDownloadInfo{
Location: disk.Location,
Sha256Sum: disk.Sha256,
}, nil
}
|