From: Yolanda Robla Date: Mon, 18 Mar 2019 09:21:59 +0000 (+0100) Subject: Add step to download deployment image X-Git-Tag: akraino_r1~24^2 X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=commitdiff_plain;h=095b266d0e6b0ab9851db1c20b6c803038d8c852;p=kni%2Finstaller.git Add step to download deployment image Change-Id: I8d2ec365c198dc8323e35d02e78c2f710ea746b9 --- diff --git a/Makefile b/Makefile index e94f8fb..3a119fd 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,10 @@ ifndef MASTER_MEMORY_MB override MASTER_MEMORY_MB = "11192" endif +ifndef RELEASES_URL +override RELEASES_URL = "https://releases-rhcos.svc.ci.openshift.org/storage/releases/" +endif + all: watch binary: @@ -40,7 +44,7 @@ deploy: images: @echo "Launching image generation" - @./bin/$(GONAME) images --build_path $(BUILDDIR) --version $(RHCOS_VERSION) + @./bin/$(GONAME) images --build_path $(BUILDDIR) --version $(RHCOS_VERSION) --releases_url $(RELEASES_URL) help: @echo "Please use \`make ' where is one of" diff --git a/cmd/images.go b/cmd/images.go index f042e66..2763d2f 100644 --- a/cmd/images.go +++ b/cmd/images.go @@ -16,16 +16,34 @@ package cmd import ( "bytes" + "context" + "encoding/json" "fmt" "io" "io/ioutil" "log" + "net/http" "os" "os/exec" + "time" "github.com/spf13/cobra" ) +type metadata struct { + AMIs []struct { + HVM string `json:"hvm"` + Name string `json:"name"` + } `json:"amis"` + Images struct { + QEMU struct { + Path string `json:"path"` + SHA256 string `json:"sha256"` + } `json:"qemu"` + } `json:"images"` + OSTreeVersion string `json:"ostree-version"` +} + // UmountDirectory will umount the ISO directory func UmountDirectory(mountPath string) { cmd := exec.Command("sudo", "umount", mountPath) @@ -138,6 +156,119 @@ coreos-assembler buildextend-installer } +// GenerateDeploymentImage will download latest qcow2, convert to raw and compress +func GenerateDeploymentImage(buildPath string, releasesURL string, version string) { + // first download the json file + log.Println("Checking the latest builds") + jsonURL := fmt.Sprintf("%s/%s/builds.json", releasesURL, version) + + req, err := http.NewRequest("GET", jsonURL, nil) + if err != nil { + log.Fatal(fmt.Sprintf("Error downloading builds metadata: %s", err)) + os.Exit(1) + } + client := &http.Client{} + + ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second) + defer cancel() + resp, err := client.Do(req.WithContext(ctx)) + if err != nil { + log.Fatal(fmt.Sprintf("Error downloading builds metadata: %s", err)) + os.Exit(1) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + log.Fatal(fmt.Sprintf("Incorrect HTTP response: %s", resp.Status)) + os.Exit(1) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatal(fmt.Sprintf("Failed to read HTTP response: %s", err)) + os.Exit(1) + } + + var builds struct { + Builds []string `json:"builds"` + } + if err := json.Unmarshal(body, &builds); err != nil { + log.Fatal(fmt.Sprintf("Failed to parse HTTP response: %s", err)) + os.Exit(1) + } + + if len(builds.Builds) == 0 { + log.Fatal("No builds found") + os.Exit(1) + } + + finalBuild := builds.Builds[0] + + // now retrieve the image path for this build + url := fmt.Sprintf("%s/%s/%s/meta.json", releasesURL, version, finalBuild) + log.Println(fmt.Sprintf("Checking RHCOS metadata from %s", url)) + req, err = http.NewRequest("GET", url, nil) + if err != nil { + log.Fatal(fmt.Sprintf("Error fetching metadata: %s", err)) + os.Exit(1) + } + + client = &http.Client{} + resp, err = client.Do(req.WithContext(ctx)) + if err != nil { + log.Fatal(fmt.Sprintf("Error fetching metadata: %s", err)) + os.Exit(1) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + log.Fatal(fmt.Sprintf("Incorrect HTTP response: %s", resp.Status)) + os.Exit(1) + } + + body, err = ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatal(fmt.Sprintf("Failed to read HTTP response: %s", err)) + os.Exit(1) + } + + var meta metadata + if err := json.Unmarshal(body, &meta); err != nil { + log.Fatal(fmt.Sprintf("Failed to parse HTTP response: %s", err)) + os.Exit(1) + } + + finalQcow2 := fmt.Sprintf("%s/%s/%s/%s", releasesURL, version, meta.OSTreeVersion, meta.Images.QEMU.Path) + log.Println(fmt.Sprintf("Downloading image from: %s", finalQcow2)) + + // now download and uncompress the image + localQcow2 := fmt.Sprintf("%s/rhcos-qemu.qcow2.gz", buildPath) + cmd := exec.Command("curl", "--compressed", "-L", finalQcow2, "-o", localQcow2) + out, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(fmt.Sprintf("Error downloading qcow2: %s - %s", err, string(out))) + os.Exit(1) + } + + // now convert the image and compress it + localRaw := fmt.Sprintf("%s/rhcos-qemu.raw", buildPath) + cmd = exec.Command("qemu-img", "convert", localQcow2, localRaw) + out, err = cmd.CombinedOutput() + if err != nil { + log.Fatal(fmt.Sprintf("Error converting image: %s - %s", err, string(out))) + os.Exit(1) + } + + // and now compress it + cmd = exec.Command("gzip", localRaw) + out, err = cmd.CombinedOutput() + if err != nil { + log.Fatal(fmt.Sprintf("Error compressing image: %s - %s", err, string(out))) + os.Exit(1) + } + log.Println(fmt.Sprintf("Final deployment image is at: %s/rhcos-qemu.raw.gz", buildPath)) +} + // imagesCmd represents the images command var imagesCmd = &cobra.Command{ Use: "images", @@ -163,6 +294,13 @@ var imagesCmd = &cobra.Command{ os.Exit(1) } + releasesURL, _ := cmd.Flags().GetString("releases_url") + + if version == "ootpa" { + log.Fatal("Currently Ootpa not being supported") + os.Exit(1) + } + GenerateDeploymentImage(buildPath, releasesURL, version) GenerateInstallerImages(buildPath) }, } @@ -172,4 +310,6 @@ func init() { imagesCmd.Flags().StringP("build_path", "", "", "Directory to use as build path. If that not exists, the installer will generate a default directory") imagesCmd.Flags().StringP("version", "", "", "Version of the images being generated (maipo, ootpa)") + imagesCmd.Flags().StringP("releases_url", "", "", "URL where to download the latest release of RHCOS") + imagesCmd.MarkFlagRequired("releases_url") }