Add step to download deployment image 80/480/6
authorYolanda Robla <yroblamo@redhat.com>
Mon, 18 Mar 2019 09:21:59 +0000 (10:21 +0100)
committerYolanda Robla <yroblamo@redhat.com>
Mon, 18 Mar 2019 15:08:29 +0000 (16:08 +0100)
Change-Id: I8d2ec365c198dc8323e35d02e78c2f710ea746b9

Makefile
cmd/images.go

index e94f8fb..3a119fd 100644 (file)
--- 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 <target>' where <target> is one of"
index f042e66..2763d2f 100644 (file)
@@ -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")
 }