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