github.com/raghuse92/packer@v1.3.2/common/iso_config.go (about) 1 package common 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "log" 8 "net/http" 9 "net/url" 10 "os" 11 "path/filepath" 12 "runtime" 13 "strings" 14 15 "github.com/hashicorp/packer/template/interpolate" 16 ) 17 18 // ISOConfig contains configuration for downloading ISO images. 19 type ISOConfig struct { 20 ISOChecksum string `mapstructure:"iso_checksum"` 21 ISOChecksumURL string `mapstructure:"iso_checksum_url"` 22 ISOChecksumType string `mapstructure:"iso_checksum_type"` 23 ISOUrls []string `mapstructure:"iso_urls"` 24 TargetPath string `mapstructure:"iso_target_path"` 25 TargetExtension string `mapstructure:"iso_target_extension"` 26 RawSingleISOUrl string `mapstructure:"iso_url"` 27 } 28 29 func (c *ISOConfig) Prepare(ctx *interpolate.Context) (warnings []string, errs []error) { 30 if c.RawSingleISOUrl == "" && len(c.ISOUrls) == 0 { 31 errs = append( 32 errs, errors.New("One of iso_url or iso_urls must be specified.")) 33 return 34 } else if c.RawSingleISOUrl != "" && len(c.ISOUrls) > 0 { 35 errs = append( 36 errs, errors.New("Only one of iso_url or iso_urls may be specified.")) 37 return 38 } else if c.RawSingleISOUrl != "" { 39 c.ISOUrls = []string{c.RawSingleISOUrl} 40 } 41 42 if c.ISOChecksumType == "" { 43 errs = append( 44 errs, errors.New("The iso_checksum_type must be specified.")) 45 } else { 46 c.ISOChecksumType = strings.ToLower(c.ISOChecksumType) 47 if c.ISOChecksumType != "none" { 48 if c.ISOChecksum == "" && c.ISOChecksumURL == "" { 49 errs = append( 50 errs, errors.New("Due to large file sizes, an iso_checksum is required")) 51 return warnings, errs 52 } else { 53 if h := HashForType(c.ISOChecksumType); h == nil { 54 errs = append( 55 errs, fmt.Errorf("Unsupported checksum type: %s", c.ISOChecksumType)) 56 return warnings, errs 57 } 58 59 // If iso_checksum has no value use iso_checksum_url instead. 60 if c.ISOChecksum == "" { 61 u, err := url.Parse(c.ISOChecksumURL) 62 if err != nil { 63 errs = append(errs, 64 fmt.Errorf("Error parsing checksum: %s", err)) 65 return warnings, errs 66 } 67 switch u.Scheme { 68 case "http", "https": 69 res, err := http.Get(c.ISOChecksumURL) 70 c.ISOChecksum = "" 71 if err != nil { 72 errs = append(errs, 73 fmt.Errorf("Error getting checksum from url: %s", c.ISOChecksumURL)) 74 return warnings, errs 75 } 76 defer res.Body.Close() 77 err = c.parseCheckSumFile(bufio.NewReader(res.Body)) 78 if err != nil { 79 errs = append(errs, err) 80 return warnings, errs 81 } 82 case "file": 83 path := u.Path 84 85 if runtime.GOOS == "windows" && len(path) > 2 && path[0] == '/' && path[2] == ':' { 86 path = strings.TrimLeft(path, "/") 87 } 88 89 file, err := os.Open(path) 90 if err != nil { 91 errs = append(errs, err) 92 return warnings, errs 93 } 94 err = c.parseCheckSumFile(bufio.NewReader(file)) 95 if err != nil { 96 errs = append(errs, err) 97 return warnings, errs 98 } 99 case "": 100 break 101 default: 102 errs = append(errs, 103 fmt.Errorf("Error parsing checksum url: %s, scheme not supported: %s", c.ISOChecksumURL, u.Scheme)) 104 return warnings, errs 105 } 106 } 107 } 108 } 109 } 110 111 c.ISOChecksum = strings.ToLower(c.ISOChecksum) 112 113 for i, url := range c.ISOUrls { 114 url, err := ValidatedURL(url) 115 if err != nil { 116 errs = append( 117 errs, fmt.Errorf("Failed to parse iso_url %d: %s", i+1, err)) 118 } else { 119 c.ISOUrls[i] = url 120 } 121 } 122 123 if c.TargetExtension == "" { 124 c.TargetExtension = "iso" 125 } 126 c.TargetExtension = strings.ToLower(c.TargetExtension) 127 128 // Warnings 129 if c.ISOChecksumType == "none" { 130 warnings = append(warnings, 131 "A checksum type of 'none' was specified. Since ISO files are so big,\n"+ 132 "a checksum is highly recommended.") 133 } 134 135 return warnings, errs 136 } 137 138 func (c *ISOConfig) parseCheckSumFile(rd *bufio.Reader) error { 139 u, err := url.Parse(c.ISOUrls[0]) 140 if err != nil { 141 return err 142 } 143 144 checksumurl, err := url.Parse(c.ISOChecksumURL) 145 if err != nil { 146 return err 147 } 148 149 absPath, err := filepath.Abs(u.Path) 150 if err != nil { 151 log.Printf("Unable to generate absolute path from provided iso_url: %s", err) 152 absPath = "" 153 } 154 155 relpath, err := filepath.Rel(filepath.Dir(checksumurl.Path), absPath) 156 if err != nil { 157 log.Printf("Unable to determine relative pathing; continuing with abspath.") 158 relpath = "" 159 } 160 161 filename := filepath.Base(u.Path) 162 163 errNotFound := fmt.Errorf("No checksum for %q, %q or %q found at: %s", 164 filename, relpath, u.Path, c.ISOChecksumURL) 165 for { 166 line, err := rd.ReadString('\n') 167 if err != nil && line == "" { 168 break 169 } 170 parts := strings.Fields(line) 171 if len(parts) < 2 { 172 continue 173 } 174 options := []string{filename, relpath, "./" + relpath, absPath} 175 if strings.ToLower(parts[0]) == c.ISOChecksumType { 176 // BSD-style checksum 177 for _, match := range options { 178 if parts[1] == fmt.Sprintf("(%s)", match) { 179 c.ISOChecksum = parts[3] 180 return nil 181 } 182 } 183 } else { 184 // Standard checksum 185 if parts[1][0] == '*' { 186 // Binary mode 187 parts[1] = parts[1][1:] 188 } 189 for _, match := range options { 190 if parts[1] == match { 191 c.ISOChecksum = parts[0] 192 return nil 193 } 194 } 195 } 196 } 197 return errNotFound 198 }