github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/common/iso_config.go (about)

     1  package common
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/mitchellh/packer/template/interpolate"
    14  )
    15  
    16  // ISOConfig contains configuration for downloading ISO images.
    17  type ISOConfig struct {
    18  	ISOChecksum     string   `mapstructure:"iso_checksum"`
    19  	ISOChecksumURL  string   `mapstructure:"iso_checksum_url"`
    20  	ISOChecksumType string   `mapstructure:"iso_checksum_type"`
    21  	ISOUrls         []string `mapstructure:"iso_urls"`
    22  	TargetPath      string   `mapstructure:"iso_target_path"`
    23  	RawSingleISOUrl string   `mapstructure:"iso_url"`
    24  }
    25  
    26  func (c *ISOConfig) Prepare(ctx *interpolate.Context) (warnings []string, errs []error) {
    27  	if c.RawSingleISOUrl == "" && len(c.ISOUrls) == 0 {
    28  		errs = append(
    29  			errs, errors.New("One of iso_url or iso_urls must be specified."))
    30  		return
    31  	} else if c.RawSingleISOUrl != "" && len(c.ISOUrls) > 0 {
    32  		errs = append(
    33  			errs, errors.New("Only one of iso_url or iso_urls may be specified."))
    34  		return
    35  	} else if c.RawSingleISOUrl != "" {
    36  		c.ISOUrls = []string{c.RawSingleISOUrl}
    37  	}
    38  
    39  	if c.ISOChecksumType == "" {
    40  		errs = append(
    41  			errs, errors.New("The iso_checksum_type must be specified."))
    42  	} else {
    43  		c.ISOChecksumType = strings.ToLower(c.ISOChecksumType)
    44  		if c.ISOChecksumType != "none" {
    45  			if c.ISOChecksum == "" && c.ISOChecksumURL == "" {
    46  				errs = append(
    47  					errs, errors.New("Due to large file sizes, an iso_checksum is required"))
    48  				return warnings, errs
    49  			} else {
    50  				if h := HashForType(c.ISOChecksumType); h == nil {
    51  					errs = append(
    52  						errs, fmt.Errorf("Unsupported checksum type: %s", c.ISOChecksumType))
    53  					return warnings, errs
    54  				}
    55  
    56  				// If iso_checksum has no value use iso_checksum_url instead.
    57  				if c.ISOChecksum == "" {
    58  					u, err := url.Parse(c.ISOChecksumURL)
    59  					if err != nil {
    60  						errs = append(errs,
    61  							fmt.Errorf("Error parsing checksum: %s", err))
    62  						return warnings, errs
    63  					}
    64  					switch u.Scheme {
    65  					case "http", "https":
    66  						res, err := http.Get(c.ISOChecksumURL)
    67  						c.ISOChecksum = ""
    68  						if err != nil {
    69  							errs = append(errs,
    70  								fmt.Errorf("Error getting checksum from url: %s", c.ISOChecksumURL))
    71  							return warnings, errs
    72  						}
    73  						defer res.Body.Close()
    74  						err = c.parseCheckSumFile(bufio.NewReader(res.Body))
    75  						if err != nil {
    76  							errs = append(errs, err)
    77  							return warnings, errs
    78  						}
    79  					case "file":
    80  						file, err := os.Open(u.Path)
    81  						if err != nil {
    82  							errs = append(errs, err)
    83  							return warnings, errs
    84  						}
    85  						err = c.parseCheckSumFile(bufio.NewReader(file))
    86  						if err != nil {
    87  							errs = append(errs, err)
    88  							return warnings, errs
    89  						}
    90  
    91  					case "":
    92  						break
    93  					default:
    94  						errs = append(errs,
    95  							fmt.Errorf("Error parsing checksum url: %s, scheme not supported: %s", c.ISOChecksumURL, u.Scheme))
    96  						return warnings, errs
    97  					}
    98  				}
    99  			}
   100  		}
   101  	}
   102  
   103  	c.ISOChecksum = strings.ToLower(c.ISOChecksum)
   104  
   105  	for i, url := range c.ISOUrls {
   106  		url, err := DownloadableURL(url)
   107  		if err != nil {
   108  			errs = append(
   109  				errs, fmt.Errorf("Failed to parse iso_url %d: %s", i+1, err))
   110  		} else {
   111  			c.ISOUrls[i] = url
   112  		}
   113  	}
   114  
   115  	// Warnings
   116  	if c.ISOChecksumType == "none" {
   117  		warnings = append(warnings,
   118  			"A checksum type of 'none' was specified. Since ISO files are so big,\n"+
   119  				"a checksum is highly recommended.")
   120  	}
   121  
   122  	return warnings, errs
   123  }
   124  
   125  func (c *ISOConfig) parseCheckSumFile(rd *bufio.Reader) error {
   126  	errNotFound := fmt.Errorf("No checksum for %q found at: %s", filepath.Base(c.ISOUrls[0]), c.ISOChecksumURL)
   127  	for {
   128  		line, err := rd.ReadString('\n')
   129  		if err != nil && line == "" {
   130  			break
   131  		}
   132  		parts := strings.Fields(line)
   133  		if len(parts) < 2 {
   134  			continue
   135  		}
   136  		if strings.ToLower(parts[0]) == c.ISOChecksumType {
   137  			// BSD-style checksum
   138  			if parts[1] == fmt.Sprintf("(%s)", filepath.Base(c.ISOUrls[0])) {
   139  				c.ISOChecksum = parts[3]
   140  				return nil
   141  			}
   142  		} else {
   143  			// Standard checksum
   144  			if parts[1][0] == '*' {
   145  				// Binary mode
   146  				parts[1] = parts[1][1:]
   147  			}
   148  			if parts[1] == filepath.Base(c.ISOUrls[0]) {
   149  				c.ISOChecksum = parts[0]
   150  				return nil
   151  			}
   152  		}
   153  	}
   154  	return errNotFound
   155  }