diff --git a/builder/virtualbox/step_download_iso.go b/builder/virtualbox/step_download_iso.go index f7491eab9..a0fadbf56 100644 --- a/builder/virtualbox/step_download_iso.go +++ b/builder/virtualbox/step_download_iso.go @@ -5,13 +5,9 @@ import ( "encoding/hex" "fmt" "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/builder/common" "github.com/mitchellh/packer/packer" - "io" "log" - "net/http" - "net/url" - "os" - "strings" "time" ) @@ -31,62 +27,52 @@ func (s stepDownloadISO) Run(state map[string]interface{}) multistep.StepAction config := state["config"].(*config) ui := state["ui"].(packer.Ui) + checksum, err := hex.DecodeString(config.ISOMD5) + if err != nil { + ui.Error(fmt.Sprintf("Error parsing checksum: %s", err)) + return multistep.ActionHalt + } + log.Printf("Acquiring lock to download the ISO.") cachePath := cache.Lock(config.ISOUrl) defer cache.Unlock(config.ISOUrl) - err := s.checkMD5(cachePath, config.ISOMD5) - haveFile := err == nil - if err != nil { - if !os.IsNotExist(err) { - ui.Say(fmt.Sprintf("Error validating MD5 of ISO: %s", err)) - return multistep.ActionHalt - } + downloadConfig := &common.DownloadConfig{ + Url: config.ISOUrl, + TargetPath: cachePath, + CopyFile: false, + Hash: md5.New(), + Checksum: checksum, } - if !haveFile { - url, err := url.Parse(config.ISOUrl) - if err != nil { - ui.Error(fmt.Sprintf("Error parsing iso_url: %s", err)) - return multistep.ActionHalt - } + download := common.NewDownloadClient(downloadConfig) - // Start the download in a goroutine so that we cancel it and such. - var progress uint - downloadComplete := make(chan bool, 1) - go func() { - ui.Say("Copying or downloading ISO. Progress will be shown periodically.") - cachePath, err = s.downloadUrl(cachePath, url, &progress) - downloadComplete <- true - }() + downloadCompleteCh := make(chan error, 1) + go func() { + ui.Say("Copying or downloading ISO. Progress will be reported periodically.") + cachePath, err = download.Get() + downloadCompleteCh <- err + }() - progressTimer := time.NewTicker(15 * time.Second) - defer progressTimer.Stop() + progressTicker := time.NewTicker(5 * time.Second) + defer progressTicker.Stop() - DownloadWaitLoop: - for { - select { - case <-downloadComplete: - log.Println("Download of ISO completed.") - break DownloadWaitLoop - case <-progressTimer.C: - ui.Say(fmt.Sprintf("Download progress: %d%%", progress)) - case <-time.After(1 * time.Second): - if _, ok := state[multistep.StateCancelled]; ok { - ui.Say("Interrupt received. Cancelling download...") - return multistep.ActionHalt - } +DownloadWaitLoop: + for { + select { + case err := <-downloadCompleteCh: + if err != nil { + ui.Error(fmt.Sprintf("Error downloading ISO: %s", err)) } - } - if err != nil { - ui.Error(fmt.Sprintf("Error downloading ISO: %s", err)) - return multistep.ActionHalt - } - - if err = s.checkMD5(cachePath, config.ISOMD5); err != nil { - ui.Say(fmt.Sprintf("Error validating MD5 of ISO: %s", err)) - return multistep.ActionHalt + break DownloadWaitLoop + case <-progressTicker.C: + ui.Say(fmt.Sprintf("Download progress: %d%%", download.PercentProgress())) + case <-time.After(1 * time.Second): + if _, ok := state[multistep.StateCancelled]; ok { + ui.Say("Interrupt received. Cancelling download...") + return multistep.ActionHalt + } } } @@ -97,61 +83,3 @@ func (s stepDownloadISO) Run(state map[string]interface{}) multistep.StepAction } func (stepDownloadISO) Cleanup(map[string]interface{}) {} - -func (stepDownloadISO) checkMD5(path string, expected string) error { - f, err := os.Open(path) - if err != nil { - return err - } - - hash := md5.New() - io.Copy(hash, f) - result := strings.ToLower(hex.EncodeToString(hash.Sum(nil))) - if result != expected { - return fmt.Errorf("result != expected: %s != %s", result, expected) - } - - return nil -} - -func (stepDownloadISO) downloadUrl(path string, url *url.URL, progress *uint) (string, error) { - if url.Scheme == "file" { - // If it is just a file URL, then we already have the ISO - return url.Path, nil - } - - // Otherwise, it is an HTTP URL, and we must download it. - f, err := os.Create(path) - if err != nil { - return "", err - } - defer f.Close() - - log.Printf("Beginning download of ISO: %s", url.String()) - resp, err := http.Get(url.String()) - if err != nil { - return "", err - } - - var buffer [4096]byte - var totalRead int64 - for { - n, err := resp.Body.Read(buffer[:]) - if err != nil && err != io.EOF { - return "", err - } - - totalRead += int64(n) - *progress = uint((float64(totalRead) / float64(resp.ContentLength)) * 100) - - if _, werr := f.Write(buffer[:n]); werr != nil { - return "", werr - } - - if err == io.EOF { - break - } - } - - return path, nil -}