packer-cn/common/iso_config.go

193 lines
6.4 KiB
Go

//go:generate struct-markdown
package common
import (
"encoding/hex"
"errors"
"fmt"
"log"
"net/url"
"os"
"strings"
getter "github.com/hashicorp/go-getter"
"github.com/hashicorp/packer/template/interpolate"
)
// By default, Packer will symlink, download or copy image files to the Packer
// cache into a "`hash($iso_url+$iso_checksum).$iso_target_extension`" file.
// Packer uses [hashicorp/go-getter](https://github.com/hashicorp/go-getter) in
// file mode in order to perform a download.
//
// go-getter supports the following protocols:
//
// * Local files
// * Git
// * Mercurial
// * HTTP
// * Amazon S3
//
//
// \~> On windows - when referencing a local iso - if packer is running
// without symlinking rights, the iso will be copied to the cache folder. Read
// [Symlinks in Windows 10
// !](https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/)
// for more info.
//
// Examples:
// go-getter can guess the checksum type based on `iso_checksum` len.
//
// ``` json
// {
// "iso_checksum": "946a6077af6f5f95a51f82fdc44051c7aa19f9cfc5f737954845a6050543d7c2",
// "iso_url": "ubuntu.org/.../ubuntu-14.04.1-server-amd64.iso"
// }
// ```
//
// ``` json
// {
// "iso_checksum_type": "file",
// "iso_checksum": "ubuntu.org/..../ubuntu-14.04.1-server-amd64.iso.sum",
// "iso_url": "ubuntu.org/.../ubuntu-14.04.1-server-amd64.iso"
// }
// ```
//
// ``` json
// {
// "iso_checksum_url": "./shasums.txt",
// "iso_url": "ubuntu.org/.../ubuntu-14.04.1-server-amd64.iso"
// }
// ```
//
// ``` json
// {
// "iso_checksum_type": "sha256",
// "iso_checksum_url": "./shasums.txt",
// "iso_url": "ubuntu.org/.../ubuntu-14.04.1-server-amd64.iso"
// }
// ```
//
type ISOConfig struct {
// The checksum for the ISO file or virtual hard drive file. The algorithm
// to use when computing the checksum can be optionally specified with
// `iso_checksum_type`. When `iso_checksum_type` is not set packer will
// guess the checksumming type based on `iso_checksum` length.
// `iso_checksum` can be also be a file or an URL, in which case
// `iso_checksum_type` must be set to `file`; the go-getter will download
// it and use the first hash found.
ISOChecksum string `mapstructure:"iso_checksum" required:"true"`
// An URL to a checksum file containing a checksum for the ISO file. At
// least one of `iso_checksum` and `iso_checksum_url` must be defined.
// `iso_checksum_url` will be ignored if `iso_checksum` is non empty.
ISOChecksumURL string `mapstructure:"iso_checksum_url"`
// The algorithm to be used when computing the checksum of the file
// specified in `iso_checksum`. Currently, valid values are "", "none",
// "md5", "sha1", "sha256", "sha512" or "file". Since the validity of ISO
// and virtual disk files are typically crucial to a successful build,
// Packer performs a check of any supplied media by default. While setting
// "none" will cause Packer to skip this check, corruption of large files
// such as ISOs and virtual hard drives can occur from time to time. As
// such, skipping this check is not recommended. `iso_checksum_type` must
// be set to `file` when `iso_checksum` is an url.
ISOChecksumType string `mapstructure:"iso_checksum_type"`
// A URL to the ISO containing the installation image or virtual hard drive
// (VHD or VHDX) file to clone.
RawSingleISOUrl string `mapstructure:"iso_url" required:"true"`
// Multiple URLs for the ISO to download. Packer will try these in order.
// If anything goes wrong attempting to download or while downloading a
// single URL, it will move on to the next. All URLs must point to the same
// file (same checksum). By default this is empty and `iso_url` is used.
// Only one of `iso_url` or `iso_urls` can be specified.
ISOUrls []string `mapstructure:"iso_urls"`
// The path where the iso should be saved after download. By default will
// go in the packer cache, with a hash of the original filename and
// checksum as its name.
TargetPath string `mapstructure:"iso_target_path"`
// The extension of the iso file after download. This defaults to `iso`.
TargetExtension string `mapstructure:"iso_target_extension"`
}
func (c *ISOConfig) Prepare(ctx *interpolate.Context) (warnings []string, errs []error) {
if len(c.ISOUrls) != 0 && c.RawSingleISOUrl != "" {
errs = append(
errs, errors.New("Only one of iso_url or iso_urls must be specified"))
return
}
if c.RawSingleISOUrl != "" {
// make sure only array is set
c.ISOUrls = append([]string{c.RawSingleISOUrl}, c.ISOUrls...)
c.RawSingleISOUrl = ""
}
if len(c.ISOUrls) == 0 {
errs = append(
errs, errors.New("One of iso_url or iso_urls must be specified"))
return
}
c.ISOChecksumType = strings.ToLower(c.ISOChecksumType)
if c.TargetExtension == "" {
c.TargetExtension = "iso"
}
c.TargetExtension = strings.ToLower(c.TargetExtension)
// Warnings
if c.ISOChecksumType == "none" {
warnings = append(warnings,
"A checksum type of 'none' was specified. Since ISO files are so big,\n"+
"a checksum is highly recommended.")
return warnings, errs
}
if c.ISOChecksumURL != "" {
if c.ISOChecksum != "" {
warnings = append(warnings, "You have provided both an "+
"iso_checksum and an iso_checksum_url. Discarding the "+
"iso_checksum_url and using the checksum.")
} else {
if strings.HasSuffix(strings.ToLower(c.ISOChecksumURL), ".iso") {
errs = append(errs, fmt.Errorf("Error parsing checksum:"+
" .iso is not a valid checksum extension"))
}
// go-getter auto-parses checksum files
c.ISOChecksumType = "file"
c.ISOChecksum = c.ISOChecksumURL
}
}
if c.ISOChecksum == "" {
errs = append(errs, fmt.Errorf("A checksum must be specified"))
}
if c.ISOChecksumType == "file" {
u, err := url.Parse(c.ISOUrls[0])
if err != nil {
errs = append(errs, fmt.Errorf("error parsing URL <%s>: %s",
c.ISOUrls[0], err))
}
wd, err := os.Getwd()
if err != nil {
log.Printf("get working directory: %v", err)
// here we ignore the error in case the
// working directory is not needed.
}
gc := getter.Client{
Dst: "no-op",
Src: u.String(),
Pwd: wd,
Dir: false,
Getters: getter.Getters,
}
cksum, err := gc.ChecksumFromFile(c.ISOChecksumURL, u)
if cksum == nil || err != nil {
errs = append(errs, fmt.Errorf("Couldn't extract checksum from checksum file"))
} else {
c.ISOChecksumType = cksum.Type
c.ISOChecksum = hex.EncodeToString(cksum.Value)
}
}
return warnings, errs
}