Skip to content

Commit

Permalink
Refactor update.go to be more readable
Browse files Browse the repository at this point in the history
  • Loading branch information
dharmit committed May 11, 2017
1 parent b4771f6 commit 8361363
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 112 deletions.
1 change: 0 additions & 1 deletion pkg/minikube/constants/constants_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,3 @@ var SupportedVMDrivers = [...]string{

const DefaultVMDriver = "xhyve"
const OC_BINARY_NAME = "oc"
const BINARY_NAME = "minishift"
1 change: 0 additions & 1 deletion pkg/minikube/constants/constants_gendocs.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,3 @@ var SupportedVMDrivers = [...]string{

const DefaultVMDriver = "kvm"
const OC_BINARY_NAME = "oc"
const BINARY_NAME = "minishift"
1 change: 0 additions & 1 deletion pkg/minikube/constants/constants_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,3 @@ var SupportedVMDrivers = [...]string{

const DefaultVMDriver = "kvm"
const OC_BINARY_NAME = "oc"
const BINARY_NAME = "minishift"
1 change: 0 additions & 1 deletion pkg/minikube/constants/constants_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,3 @@ var SupportedVMDrivers = [...]string{

const DefaultVMDriver = "hyperv"
const OC_BINARY_NAME = "oc.exe"
const BINARY_NAME = "minishift.exe"
236 changes: 128 additions & 108 deletions pkg/minikube/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,8 @@ import (
update "github.com/inconshreveable/go-update"
"github.com/kardianos/osext"
"github.com/minishift/minishift/pkg/util/archive"
"github.com/minishift/minishift/pkg/util/os/atexit"
"github.com/spf13/viper"
pb "gopkg.in/cheggaaa/pb.v1"

"github.com/minishift/minishift/pkg/minikube/config"
"github.com/minishift/minishift/pkg/minikube/constants"
githubutils "github.com/minishift/minishift/pkg/util/github"
"github.com/minishift/minishift/pkg/version"
Expand All @@ -63,7 +60,6 @@ func MaybeUpdateFromGithub(output io.Writer) error {

latestVersion, err := getLatestVersionFromGitHub(githubOwner, githubRepo)
if err != nil {
atexit.ExitWithMessage(1, "Cannot get latest version from github.com\nPlease check your internet connection or try again later")
return err
}

Expand Down Expand Up @@ -92,26 +88,49 @@ func MaybeUpdate(output io.Writer, githubOwner, githubRepo string, latestVersion
}

archiveName := fmt.Sprintf("minishift-%s-%s-%s.%s", latestVersion, runtime.GOOS, runtime.GOARCH, extName)
updateLinkPrefix := "https://github.com/" + githubOwner + "/" + githubRepo + "/releases/tag/" + version.VersionPrefix
// updateLinkPrefix := "https://github.com/" + githubOwner + "/" + githubRepo + "/releases/tag/" + version.VersionPrefix
downloadLinkFormat := "https://github.com/" + githubOwner + "/" + githubRepo + "/releases/download/v%s/%s"

fmt.Printf("Updating to version %s\n", latestVersion)
err := updateBinary(latestVersion, archiveName, updateLinkPrefix, downloadLinkFormat)
// err := updateBinary(latestVersion, archiveName, updateLinkPrefix, downloadLinkFormat)

// downloadedAchive is a string that has the path to archive on the disk
downloadedArchive, dir, err := downloadAndSaveArchive(latestVersion, archiveName, downloadLinkFormat)
if err != nil {
return err
}
return nil
}

func shouldCheckURLVersion(filePath string) bool {
if !viper.GetBool(config.WantUpdateNotification) {
return false
defer os.RemoveAll(dir)

if err := downloadAndVerifyChecksum(downloadedArchive, downloadLinkFormat, archiveName, latestVersion); err != nil {
return err
}
lastUpdateTime := getTimeFromFileIfExists(filePath)
if time.Since(lastUpdateTime).Hours() < viper.GetFloat64(config.ReminderWaitPeriodInHours) {
return false

// Extract and replace the downloaded archive in place of current binary

currentBinary, err := osext.Executable()
if err != nil {
glog.Errorf("Cannot find current binary to execute: %s", err)
os.Exit(1)
}

err = extractAndUpdateBinary(currentBinary, downloadedArchive, dir)
if err != nil {
return err
}
return true

env := os.Environ()
args := []string{currentBinary, "version"}
err = syscall.Exec(currentBinary, args, env)
if err != nil {
glog.Errorf("Failed to execute updated binary %s: %s", currentBinary, err)
os.Exit(1)
}
return nil
if err != nil {
return err
}
return nil
}

func getLatestVersionFromGitHub(githubOwner, githubRepo string) (semver.Version, error) {
Expand All @@ -134,14 +153,6 @@ func getLatestVersionFromGitHub(githubOwner, githubRepo string) (semver.Version,
return semver.Version{}, fmt.Errorf("Cannot get release name.")
}

func writeTimeToFile(path string, inputTime time.Time) error {
err := ioutil.WriteFile(path, []byte(inputTime.Format(timeLayout)), 0644)
if err != nil {
return fmt.Errorf("Error writing current update time to file: %s", err)
}
return nil
}

func getTimeFromFileIfExists(path string) time.Time {
lastUpdateCheckTime, err := ioutil.ReadFile(path)
if err != nil {
Expand All @@ -154,42 +165,13 @@ func getTimeFromFileIfExists(path string) time.Time {
return timeInFile
}

func updateBinary(v semver.Version, archiveName, updateLinkPrefix, downloadLinkFormat string) error {
checksum, err := downloadChecksum(v, archiveName, downloadLinkFormat)
if err != nil {
glog.Errorf("Cannot download checksum: %s", err)
os.Exit(1)
}

currentBinary, err := osext.Executable()
if err != nil {
glog.Errorf("Cannot find current binary to execute: %s", err)
os.Exit(1)
}

func downloadAndSaveArchive(v semver.Version, archiveName, downloadLinkFormat string) (string, string, error) {
url := fmt.Sprintf(downloadLinkFormat, v, archiveName)
err = updateBinaryFile(url, checksum)
if err != nil {
return err
}

env := os.Environ()
args := []string{currentBinary, "version"}
err = syscall.Exec(currentBinary, args, env)
if err != nil {
glog.Errorf("Failed to execute updated binary %s: %s", currentBinary, err)
os.Exit(1)
}
return nil
}

func updateBinaryFile(url string, checksum []byte) error {
var binary string
fmt.Println("Downloading updated archive")
httpResp, err := http.Get(url)
if err != nil {
glog.Errorf("Cannot download archive: %s", err)
os.Exit(1)
return "", "", errors.New("Cannot download archive")
}
defer func() { _ = httpResp.Body.Close() }()

Expand All @@ -204,55 +186,45 @@ func updateBinaryFile(url string, checksum []byte) error {
}()
}

// verify checksum
archiveBytes, err := ioutil.ReadAll(updatedArchive)

archiveChecksum, err := checksumFor(crypto.SHA256, archiveBytes)

if !bytes.Equal(archiveChecksum, checksum) {
fmt.Println(fmt.Errorf("Updated file has wrong checksum. Expected: %x, got: %x", archiveChecksum, checksum))
os.Exit(1)
if err != nil {
return "", "", errors.New("Unable to read downloaded archive")
}

// Create a temporary directory inside minishift directory to store archive contents

dir, err := ioutil.TempDir(constants.Minipath, "tmp/download")
if err != nil {
return err
// atexit.ExitWithMessage(1, "Could not create a temporary directory to store archive contents")
return "", "", errors.New("Could not create a temporary directory to store archive contents")
}

defer os.RemoveAll(dir) // clean up

binary = extractAndReplace(runtime.GOOS, dir, archiveBytes)
var downloadedArchive string

binaryBytes, err := os.Open(binary)
if err != nil {
fmt.Println(err)
}
if runtime.GOOS == "windows" {
// Store archive in zip file on Windows
downloadedArchive = filepath.Join(dir, "minishift.zip")
if err := writeArchiveToDisk(downloadedArchive, archiveBytes); err != nil {
return "", "", err
}
} else {
// Store archive in tgz file
downloadedArchive = filepath.Join(dir, "minishift.tgz")

err = update.Apply(binaryBytes, update.Options{
Hash: crypto.SHA256,
// Checksum: checksum,
})
if err != nil {
glog.Errorf("Cannot apply binary update: %s", err)
err := update.RollbackError(err)
if err != nil {
glog.Errorf("Failed to rollback update: %s", err)
if err := writeArchiveToDisk(downloadedArchive, archiveBytes); err != nil {
return "", "", err
}
os.Exit(1)
}
return nil
return downloadedArchive, dir, nil
}

func downloadChecksum(v semver.Version, archiveName, downloadLinkFormat string) ([]byte, error) {
func downloadAndVerifyChecksum(downloadedArchive, downloadLinkFormat, archiveName string, latestVersion semver.Version) error {

fmt.Println("Downloading updated archive checksum to validate updated archive")
u := fmt.Sprintf(downloadLinkFormat, v, archiveName+".sha256")
u := fmt.Sprintf(downloadLinkFormat, latestVersion, archiveName+".sha256")
checksumResp, err := http.Get(u)
if err != nil {
return nil, err
return err
}

defer func() { _ = checksumResp.Body.Close() }()

checksum := checksumResp.Body
Expand All @@ -267,13 +239,31 @@ func downloadChecksum(v semver.Version, archiveName, downloadLinkFormat string)
}
b, err := ioutil.ReadAll(checksum)
if err != nil {
return nil, err
return err
}
if checksumResp.StatusCode != 200 {
return nil, fmt.Errorf("received %d", checksumResp.StatusCode)
return errors.New(fmt.Sprintf("received %d", checksumResp.StatusCode))
}

downloadedChecksum, err := hex.DecodeString(strings.TrimSpace(string(b)))
if err != nil {
return err
}

archiveBytes, err := ioutil.ReadFile(downloadedArchive)
if err != nil {
return errors.New("Unable to read downloaded archive to verify checksum")
}

archiveChecksum, err := checksumFor(crypto.SHA256, archiveBytes)
if err != nil {
return err
}

return hex.DecodeString(strings.TrimSpace(string(b)))
if !bytes.Equal(archiveChecksum, downloadedChecksum) {
return errors.New(fmt.Sprintf("Updated file has wrong checksum. Expected: %x, got: %x", archiveChecksum, checksum))
}
return nil
}

func checksumFor(h crypto.Hash, payload []byte) ([]byte, error) {
Expand All @@ -285,41 +275,71 @@ func checksumFor(h crypto.Hash, payload []byte) ([]byte, error) {
return hash.Sum([]byte{}), nil
}

func extractAndReplace(goos, dir string, archiveBytes []byte) string {
downloadedArchive := filepath.Join(dir, "minishift.tgz")
ungzip := filepath.Join(dir, "minishift.gzip")
func extractAndUpdateBinary(currentBinary, downloadedArchive, dir string) error {
var binary string
extract := filepath.Join(dir, "minishift-extract")
binary := filepath.Join(extract, "minishift")

// Write archive file to disk
err := ioutil.WriteFile(downloadedArchive, archiveBytes, 0644)
if err != nil {
atexit.ExitWithMessage(1, "Cannot convert io.ReadCloser to bytes")
}
// archiveBytes, err := ioutil.ReadFile(downloadedArchive)
// if err != nil {
// return errors.New("Unable to read downloaded archive to verify checksum")
// }

if goos == "windows" {
if runtime.GOOS == "windows" {
// Unzip the downloadedArchive
err = archive.Unzip(downloadedArchive, extract)
err := archive.Unzip(downloadedArchive, extract)
if err != nil {
fmt.Println(err)
atexit.ExitWithMessage(1, "Could not unzip the archive")
return err
}
binary = filepath.Join(extract, "minishift.exe")
} else {
ungzip := filepath.Join(dir, "minishift.gzip")

// Ungzip the archive
err = archive.Ungzip(downloadedArchive, ungzip)
err := archive.Ungzip(downloadedArchive, ungzip)
if err != nil {
fmt.Println(err)
atexit.ExitWithMessage(1, "Could not Ungzip the tarball")

return err
}

// Untar the tarball
err = archive.Untar(ungzip, extract)
if err != nil {
fmt.Println(err)
atexit.ExitWithMessage(1, "Could not Untar the gzip archive")
return err
}
binary = filepath.Join(extract, "minishift")
}

binaryFile, err := os.Open(binary)
if err != nil {
return err
}

// binaryBytes, err := ioutil.ReadAll(binaryFile)

// if err != nil {
// return err
// }

// if err := ioutil.WriteFile(currentBinary, binaryBytes, 0755); err != nil {
// return err
// }

err = update.Apply(binaryFile, update.Options{
Hash: crypto.SHA256,
// Checksum: checksum,
})
if err != nil {
glog.Errorf("Cannot apply binary update: %s", err)
err := update.RollbackError(err)
if err != nil {
glog.Errorf("Failed to rollback update: %s", err)
}
os.Exit(1)
}

return binary
return nil
}

func writeArchiveToDisk(downloadedArchive string, archiveBytes []byte) error {
err := ioutil.WriteFile(downloadedArchive, archiveBytes, 0644)
return err
}

0 comments on commit 8361363

Please sign in to comment.