Merge pull request #3162 from rickard-von-essen/checksum

Allow to specify ISO checksum via URL
This commit is contained in:
Rickard von Essen 2016-02-09 13:11:17 +01:00
commit df6e4c0565
6 changed files with 213 additions and 36 deletions

View File

@ -1,8 +1,14 @@
package common
import (
"bufio"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/mitchellh/packer/template/interpolate"
@ -11,6 +17,7 @@ import (
// ISOConfig contains configuration for downloading ISO images.
type ISOConfig struct {
ISOChecksum string `mapstructure:"iso_checksum"`
ISOChecksumURL string `mapstructure:"iso_checksum_url"`
ISOChecksumType string `mapstructure:"iso_checksum_type"`
ISOUrls []string `mapstructure:"iso_urls"`
TargetPath string `mapstructure:"iso_target_path"`
@ -23,27 +30,6 @@ func (c *ISOConfig) Prepare(ctx *interpolate.Context) ([]string, []error) {
var err error
var warnings []string
if c.ISOChecksumType == "" {
errs = append(
errs, errors.New("The iso_checksum_type must be specified."))
} else {
c.ISOChecksumType = strings.ToLower(c.ISOChecksumType)
if c.ISOChecksumType != "none" {
if c.ISOChecksum == "" {
errs = append(
errs, errors.New("Due to large file sizes, an iso_checksum is required"))
} else {
c.ISOChecksum = strings.ToLower(c.ISOChecksum)
}
if h := HashForType(c.ISOChecksumType); h == nil {
errs = append(
errs,
fmt.Errorf("Unsupported checksum type: %s", c.ISOChecksumType))
}
}
}
if c.RawSingleISOUrl == "" && len(c.ISOUrls) == 0 {
errs = append(
errs, errors.New("One of iso_url or iso_urls must be specified."))
@ -54,6 +40,72 @@ func (c *ISOConfig) Prepare(ctx *interpolate.Context) ([]string, []error) {
c.ISOUrls = []string{c.RawSingleISOUrl}
}
if c.ISOChecksumType == "" {
errs = append(
errs, errors.New("The iso_checksum_type must be specified."))
} else {
c.ISOChecksumType = strings.ToLower(c.ISOChecksumType)
if c.ISOChecksumType != "none" {
if c.ISOChecksum == "" && c.ISOChecksumURL == "" {
errs = append(
errs, errors.New("Due to large file sizes, an iso_checksum is required"))
return warnings, errs
} else {
if h := HashForType(c.ISOChecksumType); h == nil {
errs = append(
errs, fmt.Errorf("Unsupported checksum type: %s", c.ISOChecksumType))
return warnings, errs
}
// If iso_checksum has no value use iso_checksum_url instead.
if c.ISOChecksum == "" {
u, err := url.Parse(c.ISOChecksumURL)
if err != nil {
errs = append(errs,
fmt.Errorf("Error parsing checksum: %s", err))
return warnings, errs
}
switch u.Scheme {
case "http", "https":
res, err := http.Get(c.ISOChecksumURL)
c.ISOChecksum = ""
if err != nil {
errs = append(errs,
fmt.Errorf("Error getting checksum from url: %s", c.ISOChecksumURL))
return warnings, errs
}
defer res.Body.Close()
err = c.parseCheckSumFile(bufio.NewReader(res.Body))
if err != nil {
errs = append(errs, err)
return warnings, errs
}
case "file":
file, err := os.Open(u.Path)
if err != nil {
errs = append(errs, err)
return warnings, errs
}
err = c.parseCheckSumFile(bufio.NewReader(file))
if err != nil {
errs = append(errs, err)
return warnings, errs
}
case "":
break
default:
errs = append(errs,
fmt.Errorf("Error parsing checksum url: %s, scheme not supported: %s", c.ISOChecksumURL, u.Scheme))
return warnings, errs
}
}
}
}
}
c.ISOChecksum = strings.ToLower(c.ISOChecksum)
for i, url := range c.ISOUrls {
c.ISOUrls[i], err = DownloadableURL(url)
if err != nil {
@ -71,3 +123,38 @@ func (c *ISOConfig) Prepare(ctx *interpolate.Context) ([]string, []error) {
return warnings, errs
}
func (c *ISOConfig) parseCheckSumFile(rd *bufio.Reader) error {
for {
line, err := rd.ReadString('\n')
if err != nil {
if err == io.EOF {
return fmt.Errorf("No checksum for \"%s\" found at: %s", filepath.Base(c.ISOUrls[0]), c.ISOChecksumURL)
} else {
return fmt.Errorf("Error getting checksum from url: %s , %s", c.ISOChecksumURL, err.Error())
}
}
parts := strings.Fields(line)
if len(parts) < 2 {
continue
}
if strings.ToLower(parts[0]) == c.ISOChecksumType {
// BSD-style checksum
if parts[1] == fmt.Sprintf("(%s)", filepath.Base(c.ISOUrls[0])) {
c.ISOChecksum = parts[3]
break
}
} else {
// Standard checksum
if parts[1][0] == '*' {
// Binary mode
parts[1] = parts[1][1:]
}
if parts[1] == filepath.Base(c.ISOUrls[0]) {
c.ISOChecksum = parts[0]
break
}
}
}
return nil
}

View File

@ -1,6 +1,8 @@
package common
import (
"fmt"
"io/ioutil"
"reflect"
"testing"
)
@ -8,11 +10,22 @@ import (
func testISOConfig() ISOConfig {
return ISOConfig{
ISOChecksum: "foo",
ISOChecksumURL: "",
ISOChecksumType: "md5",
RawSingleISOUrl: "http://www.packer.io",
RawSingleISOUrl: "http://www.packer.io/the-OS.iso",
}
}
var cs_bsd_style = `
MD5 (other.iso) = bAr
MD5 (the-OS.iso) = baZ
`
var cs_gnu_style = `
bAr0 *the-OS.iso
baZ0 other.iso
`
func TestISOConfigPrepare_ISOChecksum(t *testing.T) {
i := testISOConfig()
@ -42,6 +55,53 @@ func TestISOConfigPrepare_ISOChecksum(t *testing.T) {
}
}
func TestISOConfigPrepare_ISOChecksumURL(t *testing.T) {
i := testISOConfig()
i.ISOChecksumURL = "file:///not_read"
// Test ISOChecksum overrides url
warns, err := i.Prepare(nil)
if len(warns) > 0 && len(err) > 0 {
t.Fatalf("bad: %#v, %#v", warns, err)
}
// Test good - ISOChecksumURL BSD style
i = testISOConfig()
i.ISOChecksum = ""
cs_file, _ := ioutil.TempFile("", "packer-test-")
ioutil.WriteFile(cs_file.Name(), []byte(cs_bsd_style), 0666)
i.ISOChecksumURL = fmt.Sprintf("file://%s", cs_file.Name())
warns, err = i.Prepare(nil)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if i.ISOChecksum != "baz" {
t.Fatalf("should've found \"baz\" got: %s", i.ISOChecksum)
}
// Test good - ISOChecksumURL GNU style
i = testISOConfig()
i.ISOChecksum = ""
cs_file, _ = ioutil.TempFile("", "packer-test-")
ioutil.WriteFile(cs_file.Name(), []byte(cs_gnu_style), 0666)
i.ISOChecksumURL = fmt.Sprintf("file://%s", cs_file.Name())
warns, err = i.Prepare(nil)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if i.ISOChecksum != "bar0" {
t.Fatalf("should've found \"bar0\" got: %s", i.ISOChecksum)
}
}
func TestISOConfigPrepare_ISOChecksumType(t *testing.T) {
i := testISOConfig()
@ -113,7 +173,7 @@ func TestISOConfigPrepare_ISOUrl(t *testing.T) {
// Test iso_url set
i = testISOConfig()
i.RawSingleISOUrl = "http://www.packer.io"
i.RawSingleISOUrl = "http://www.packer.io/the-OS.iso"
warns, err = i.Prepare(nil)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
@ -122,15 +182,15 @@ func TestISOConfigPrepare_ISOUrl(t *testing.T) {
t.Errorf("should not have error: %s", err)
}
expected := []string{"http://www.packer.io"}
expected := []string{"http://www.packer.io/the-OS.iso"}
if !reflect.DeepEqual(i.ISOUrls, expected) {
t.Fatalf("bad: %#v", i.ISOUrls)
}
// Test both set
i = testISOConfig()
i.RawSingleISOUrl = "http://www.packer.io"
i.ISOUrls = []string{"http://www.packer.io"}
i.RawSingleISOUrl = "http://www.packer.io/the-OS.iso"
i.ISOUrls = []string{"http://www.packer.io/the-OS.iso"}
warns, err = i.Prepare(nil)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
@ -143,8 +203,8 @@ func TestISOConfigPrepare_ISOUrl(t *testing.T) {
i = testISOConfig()
i.RawSingleISOUrl = ""
i.ISOUrls = []string{
"http://www.packer.io",
"http://www.hashicorp.com",
"http://www.packer.io/the-OS.iso",
"http://www.hashicorp.com/the-OS.iso",
}
warns, err = i.Prepare(nil)
@ -156,8 +216,8 @@ func TestISOConfigPrepare_ISOUrl(t *testing.T) {
}
expected = []string{
"http://www.packer.io",
"http://www.hashicorp.com",
"http://www.packer.io/the-OS.iso",
"http://www.hashicorp.com/the-OS.iso",
}
if !reflect.DeepEqual(i.ISOUrls, expected) {
t.Fatalf("bad: %#v", i.ISOUrls)

View File

@ -59,7 +59,9 @@ builder.
- `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
files are so large, this is required and Packer will verify it prior to
booting a virtual machine with the ISO attached. The type of the checksum is
specified with `iso_checksum_type`, documented below.
specified with `iso_checksum_type`, documented below. At least one of
`iso_checksum` and `iso_checksum_url` must be defined. This has precedence
over `iso_checksum_url` type.
- `iso_checksum_type` (string) - The type of the checksum specified in
`iso_checksum`. Valid values are "none", "md5", "sha1", "sha256", or
@ -67,6 +69,11 @@ builder.
recommended since ISO files are generally large and corruption does happen
from time to time.
- `iso_checksum_url` (string) - A URL to a GNU or BSD style checksum file
containing a checksum for the OS ISO file. At least one of `iso_checksum`
and `iso_checksum_url` must be defined. This will be ignored if
`iso_checksum` is non empty.
- `iso_url` (string) - A URL to the ISO containing the installation image.
This URL can be either an HTTP URL or a file URL (or path to a file). If
this is an HTTP URL, Packer will download it and cache it between runs.

View File

@ -83,11 +83,20 @@ builder.
- `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
files are so large, this is required and Packer will verify it prior to
booting a virtual machine with the ISO attached. The type of the checksum is
specified with `iso_checksum_type`, documented below.
specified with `iso_checksum_type`, documented below. At least one of
`iso_checksum` and `iso_checksum_url` must be defined. This has precedence
over `iso_checksum_url` type.
- `iso_checksum_type` (string) - The type of the checksum specified in
`iso_checksum`. Valid values are "md5", "sha1", "sha256", or
"sha512" currently.
`iso_checksum`. Valid values are "none", "md5", "sha1", "sha256", or
"sha512" currently. While "none" will skip checksumming, this is not
recommended since ISO files are generally large and corruption does happen
from time to time.
- `iso_checksum_url` (string) - A URL to a GNU or BSD style checksum file
containing a checksum for the OS ISO file. At least one of `iso_checksum`
and `iso_checksum_url` must be defined. This will be ignored if
`iso_checksum` is non empty.
- `iso_url` (string) - A URL to the ISO containing the installation image.
This URL can be either an HTTP URL or a file URL (or path to a file). If

View File

@ -57,7 +57,9 @@ builder.
- `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
files are so large, this is required and Packer will verify it prior to
booting a virtual machine with the ISO attached. The type of the checksum is
specified with `iso_checksum_type`, documented below.
specified with `iso_checksum_type`, documented below. At least one of
`iso_checksum` and `iso_checksum_url` must be defined. This has precedence
over `iso_checksum_url` type.
- `iso_checksum_type` (string) - The type of the checksum specified in
`iso_checksum`. Valid values are "none", "md5", "sha1", "sha256", or
@ -65,6 +67,11 @@ builder.
recommended since ISO files are generally large and corruption does happen
from time to time.
- `iso_checksum_url` (string) - A URL to a GNU or BSD style checksum file
containing a checksum for the OS ISO file. At least one of `iso_checksum`
and `iso_checksum_url` must be defined. This will be ignored if
`iso_checksum` is non empty.
- `iso_url` (string) - A URL to the ISO containing the installation image.
This URL can be either an HTTP URL or a file URL (or path to a file). If
this is an HTTP URL, Packer will download it and cache it between runs.

View File

@ -60,7 +60,9 @@ builder.
- `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
files are so large, this is required and Packer will verify it prior to
booting a virtual machine with the ISO attached. The type of the checksum is
specified with `iso_checksum_type`, documented below.
specified with `iso_checksum_type`, documented below. At least one of
`iso_checksum` and `iso_checksum_url` must be defined. This has precedence
over `iso_checksum_url` type.
- `iso_checksum_type` (string) - The type of the checksum specified in
`iso_checksum`. Valid values are "none", "md5", "sha1", "sha256", or
@ -68,6 +70,11 @@ builder.
recommended since ISO files are generally large and corruption does happen
from time to time.
- `iso_checksum_url` (string) - A URL to a GNU or BSD style checksum file
containing a checksum for the OS ISO file. At least one of `iso_checksum`
and `iso_checksum_url` must be defined. This will be ignored if
`iso_checksum` is non empty.
- `iso_url` (string) - A URL to the ISO containing the installation image.
This URL can be either an HTTP URL or a file URL (or path to a file). If
this is an HTTP URL, Packer will download it and cache it between runs.