Commit 520a2706 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

builder/vmware: Validate MD5

parent 4b46181f
...@@ -49,10 +49,9 @@ type config struct { ...@@ -49,10 +49,9 @@ type config struct {
RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"` RawSSHWaitTimeout string `mapstructure:"ssh_wait_timeout"`
} }
func (b *Builder) Prepare(raw interface{}) (err error) { func (b *Builder) Prepare(raw interface{}) error {
err = mapstructure.Decode(raw, &b.config) if err := mapstructure.Decode(raw, &b.config); err != nil {
if err != nil { return err
return
} }
if b.config.DiskName == "" { if b.config.DiskName == "" {
...@@ -88,6 +87,7 @@ func (b *Builder) Prepare(raw interface{}) (err error) { ...@@ -88,6 +87,7 @@ func (b *Builder) Prepare(raw interface{}) (err error) {
} }
// Accumulate any errors // Accumulate any errors
var err error
errs := make([]error, 0) errs := make([]error, 0)
if b.config.HTTPPortMin > b.config.HTTPPortMax { if b.config.HTTPPortMin > b.config.HTTPPortMax {
...@@ -96,6 +96,8 @@ func (b *Builder) Prepare(raw interface{}) (err error) { ...@@ -96,6 +96,8 @@ func (b *Builder) Prepare(raw interface{}) (err error) {
if b.config.ISOMD5 == "" { if b.config.ISOMD5 == "" {
errs = append(errs, errors.New("Due to large file sizes, an iso_md5 is required")) errs = append(errs, errors.New("Due to large file sizes, an iso_md5 is required"))
} else {
b.config.ISOMD5 = strings.ToLower(b.config.ISOMD5)
} }
if b.config.ISOUrl == "" { if b.config.ISOUrl == "" {
......
...@@ -10,7 +10,7 @@ import ( ...@@ -10,7 +10,7 @@ import (
func testConfig() map[string]interface{} { func testConfig() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"iso_md5": "foo", "iso_md5": "foo",
"iso_url": "http://www.packer.io", "iso_url": "http://www.packer.io",
"ssh_username": "foo", "ssh_username": "foo",
} }
...@@ -108,11 +108,15 @@ func TestBuilderPrepare_ISOMD5(t *testing.T) { ...@@ -108,11 +108,15 @@ func TestBuilderPrepare_ISOMD5(t *testing.T) {
} }
// Test good // Test good
config["iso_md5"] = "foo" config["iso_md5"] = "FOo"
err = b.Prepare(config) err = b.Prepare(config)
if err != nil { if err != nil {
t.Fatalf("should not have error: %s", err) t.Fatalf("should not have error: %s", err)
} }
if b.config.ISOMD5 != "foo" {
t.Fatalf("should've lowercased: %s", b.config.ISOMD5)
}
} }
func TestBuilderPrepare_ISOUrl(t *testing.T) { func TestBuilderPrepare_ISOUrl(t *testing.T) {
......
package vmware package vmware
import ( import (
"crypto/md5"
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
...@@ -9,6 +10,7 @@ import ( ...@@ -9,6 +10,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"strings"
"time" "time"
) )
...@@ -32,43 +34,59 @@ func (s stepDownloadISO) Run(state map[string]interface{}) multistep.StepAction ...@@ -32,43 +34,59 @@ func (s stepDownloadISO) Run(state map[string]interface{}) multistep.StepAction
cachePath := cache.Lock(config.ISOUrl) cachePath := cache.Lock(config.ISOUrl)
defer cache.Unlock(config.ISOUrl) defer cache.Unlock(config.ISOUrl)
url, err := url.Parse(config.ISOUrl) err := s.checkMD5(cachePath, config.ISOMD5)
haveFile := err == nil
if err != nil { if err != nil {
ui.Error(fmt.Sprintf("Error parsing iso_url: %s", err)) if !os.IsNotExist(err) {
return multistep.ActionHalt ui.Say(fmt.Sprintf("Error validating MD5 of ISO: %s", err))
return multistep.ActionHalt
}
} }
// Start the download in a goroutine so that we cancel it and such. if !haveFile {
var progress uint url, err := url.Parse(config.ISOUrl)
downloadComplete := make(chan bool, 1) if err != nil {
go func() { ui.Error(fmt.Sprintf("Error parsing iso_url: %s", err))
ui.Say("Copying or downloading ISO. Progress will be shown periodically.") return multistep.ActionHalt
cachePath, err = s.downloadUrl(cachePath, url, &progress) }
downloadComplete <- true
}()
progressTimer := time.NewTicker(15 * time.Second)
defer progressTimer.Stop()
DownloadWaitLoop: // Start the download in a goroutine so that we cancel it and such.
for { var progress uint
select { downloadComplete := make(chan bool, 1)
case <-downloadComplete: go func() {
log.Println("Download of ISO completed.") ui.Say("Copying or downloading ISO. Progress will be shown periodically.")
break DownloadWaitLoop cachePath, err = s.downloadUrl(cachePath, url, &progress)
case <-progressTimer.C: downloadComplete <- true
ui.Say(fmt.Sprintf("Download progress: %d%%", progress)) }()
case <-time.After(1 * time.Second):
if _, ok := state[multistep.StateCancelled]; ok { progressTimer := time.NewTicker(15 * time.Second)
ui.Say("Interrupt received. Cancelling download...") defer progressTimer.Stop()
return multistep.ActionHalt
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
}
} }
} }
}
if err != nil { if err != nil {
ui.Error(fmt.Sprintf("Error downloading ISO: %s", err)) ui.Error(fmt.Sprintf("Error downloading ISO: %s", err))
return multistep.ActionHalt 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
}
} }
log.Printf("Path to ISO on disk: %s", cachePath) log.Printf("Path to ISO on disk: %s", cachePath)
...@@ -79,6 +97,22 @@ DownloadWaitLoop: ...@@ -79,6 +97,22 @@ DownloadWaitLoop:
func (stepDownloadISO) Cleanup(map[string]interface{}) {} 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(string(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) { func (stepDownloadISO) downloadUrl(path string, url *url.URL, progress *uint) (string, error) {
if url.Scheme == "file" { if url.Scheme == "file" {
// If it is just a file URL, then we already have the ISO // If it is just a file URL, then we already have the ISO
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment