diff --git a/builder/common/download.go b/builder/common/download.go index d5d97d1c0..661fe86b2 100644 --- a/builder/common/download.go +++ b/builder/common/download.go @@ -2,6 +2,7 @@ package common import ( "bytes" + "crypto/md5" "encoding/hex" "errors" "fmt" @@ -46,6 +47,17 @@ type DownloadClient struct { downloader Downloader } +// HashForType returns the Hash implementation for the given string +// type, or nil if the type is not supported. +func HashForType(t string) hash.Hash { + switch t { + case "md5": + return md5.New() + default: + return nil + } +} + // NewDownloadClient returns a new DownloadClient for the given // configuration. func NewDownloadClient(c *DownloadConfig) *DownloadClient { diff --git a/builder/common/download_test.go b/builder/common/download_test.go index 3e2a59ddf..2ba7f6b9a 100644 --- a/builder/common/download_test.go +++ b/builder/common/download_test.go @@ -40,3 +40,22 @@ func TestDownloadClient_VerifyChecksum(t *testing.T) { t.Fatal("didn't verify") } } + +func TestHashForType(t *testing.T) { + if h := HashForType("md5"); h == nil { + t.Fatalf("md5 hash is nil") + } else { + h.Write([]byte("foo")) + result := h.Sum(nil) + + expected := "acbd18db4cc2f85cedef654fccc4a4d8" + actual := hex.EncodeToString(result) + if actual != expected { + t.Fatalf("bad hash: %s", actual) + } + } + + if HashForType("fake") != nil { + t.Fatalf("fake hash is not nil") + } +} diff --git a/builder/virtualbox/builder.go b/builder/virtualbox/builder.go index 21cb4296d..c19b51b91 100644 --- a/builder/virtualbox/builder.go +++ b/builder/virtualbox/builder.go @@ -38,7 +38,8 @@ type config struct { HTTPDir string `mapstructure:"http_directory"` HTTPPortMin uint `mapstructure:"http_port_min"` HTTPPortMax uint `mapstructure:"http_port_max"` - ISOMD5 string `mapstructure:"iso_md5"` + ISOChecksum string `mapstructure:"iso_checksum"` + ISOChecksumType string `mapstructure:"iso_checksum_type"` ISOUrl string `mapstructure:"iso_url"` OutputDir string `mapstructure:"output_directory"` ShutdownCommand string `mapstructure:"shutdown_command"` @@ -155,10 +156,21 @@ func (b *Builder) Prepare(raws ...interface{}) error { errs = append(errs, errors.New("http_port_min must be less than http_port_max")) } - if b.config.ISOMD5 == "" { - errs = append(errs, errors.New("Due to large file sizes, an iso_md5 is required")) + if b.config.ISOChecksum == "" { + errs = append(errs, errors.New("Due to large file sizes, an iso_checksum is required")) } else { - b.config.ISOMD5 = strings.ToLower(b.config.ISOMD5) + b.config.ISOChecksum = strings.ToLower(b.config.ISOChecksum) + } + + if b.config.ISOChecksumType == "" { + errs = append(errs, errors.New("The iso_checksum_type must be specified.")) + } else { + b.config.ISOChecksumType = strings.ToLower(b.config.ISOChecksumType) + if h := common.HashForType(b.config.ISOChecksumType); h == nil { + errs = append( + errs, + fmt.Errorf("Unsupported checksum type: %s", b.config.ISOChecksumType)) + } } if b.config.ISOUrl == "" { diff --git a/builder/virtualbox/builder_test.go b/builder/virtualbox/builder_test.go index 7a08ebf04..aed68ac46 100644 --- a/builder/virtualbox/builder_test.go +++ b/builder/virtualbox/builder_test.go @@ -10,9 +10,10 @@ import ( func testConfig() map[string]interface{} { return map[string]interface{}{ - "iso_md5": "foo", - "iso_url": "http://www.google.com/", - "ssh_username": "foo", + "iso_checksum": "foo", + "iso_checksum_type": "md5", + "iso_url": "http://www.google.com/", + "ssh_username": "foo", packer.BuildNameConfigKey: "foo", } @@ -283,26 +284,56 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) { } } -func TestBuilderPrepare_ISOMD5(t *testing.T) { +func TestBuilderPrepare_ISOChecksum(t *testing.T) { var b Builder config := testConfig() // Test bad - config["iso_md5"] = "" + config["iso_checksum"] = "" err := b.Prepare(config) if err == nil { t.Fatal("should have error") } // Test good - config["iso_md5"] = "FOo" + config["iso_checksum"] = "FOo" err = b.Prepare(config) if err != nil { t.Fatalf("should not have error: %s", err) } - if b.config.ISOMD5 != "foo" { - t.Fatalf("should've lowercased: %s", b.config.ISOMD5) + if b.config.ISOChecksum != "foo" { + t.Fatalf("should've lowercased: %s", b.config.ISOChecksum) + } +} + +func TestBuilderPrepare_ISOChecksumType(t *testing.T) { + var b Builder + config := testConfig() + + // Test bad + config["iso_checksum_type"] = "" + err := b.Prepare(config) + if err == nil { + t.Fatal("should have error") + } + + // Test good + config["iso_checksum_type"] = "mD5" + err = b.Prepare(config) + if err != nil { + t.Fatalf("should not have error: %s", err) + } + + if b.config.ISOChecksumType != "md5" { + t.Fatalf("should've lowercased: %s", b.config.ISOChecksumType) + } + + // Test unknown + config["iso_checksum_type"] = "fake" + err = b.Prepare(config) + if err == nil { + t.Fatal("should have error") } } diff --git a/builder/virtualbox/step_download_iso.go b/builder/virtualbox/step_download_iso.go index bcb75acf1..62a3a8d21 100644 --- a/builder/virtualbox/step_download_iso.go +++ b/builder/virtualbox/step_download_iso.go @@ -1,7 +1,6 @@ package virtualbox import ( - "crypto/md5" "encoding/hex" "fmt" "github.com/mitchellh/multistep" @@ -33,7 +32,7 @@ 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) + checksum, err := hex.DecodeString(config.ISOChecksum) if err != nil { state["error"] = fmt.Errorf("Error parsing checksum: %s", err) return multistep.ActionHalt @@ -47,7 +46,7 @@ func (s *stepDownloadISO) Run(state map[string]interface{}) multistep.StepAction Url: config.ISOUrl, TargetPath: cachePath, CopyFile: false, - Hash: md5.New(), + Hash: common.HashForType(config.ISOChecksumType), Checksum: checksum, }