github.com/kaixiang/packer@v0.5.2-0.20140114230416-1f5786b0d7f1/post-processor/vagrant/virtualbox.go (about) 1 package vagrant 2 3 import ( 4 "archive/tar" 5 "errors" 6 "fmt" 7 "github.com/mitchellh/packer/packer" 8 "io" 9 "io/ioutil" 10 "log" 11 "os" 12 "path/filepath" 13 "regexp" 14 ) 15 16 type VBoxProvider struct{} 17 18 func (p *VBoxProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) { 19 // Create the metadata 20 metadata = map[string]interface{}{"provider": "virtualbox"} 21 22 // Copy all of the original contents into the temporary directory 23 for _, path := range artifact.Files() { 24 // We treat OVA files specially, we unpack those into the temporary 25 // directory so we can get the resulting disk and OVF. 26 if extension := filepath.Ext(path); extension == ".ova" { 27 ui.Message(fmt.Sprintf("Unpacking OVA: %s", path)) 28 if err = DecompressOva(dir, path); err != nil { 29 return 30 } 31 } else { 32 ui.Message(fmt.Sprintf("Copying from artifact: %s", path)) 33 dstPath := filepath.Join(dir, filepath.Base(path)) 34 if err = CopyContents(dstPath, path); err != nil { 35 return 36 } 37 } 38 39 } 40 41 // Rename the OVF file to box.ovf, as required by Vagrant 42 ui.Message("Renaming the OVF to box.ovf...") 43 if err = p.renameOVF(dir); err != nil { 44 return 45 } 46 47 // Create the Vagrantfile from the template 48 var baseMacAddress string 49 baseMacAddress, err = p.findBaseMacAddress(dir) 50 if err != nil { 51 return 52 } 53 54 vagrantfile = fmt.Sprintf(vboxVagrantfile, baseMacAddress) 55 return 56 } 57 58 func (p *VBoxProvider) findOvf(dir string) (string, error) { 59 log.Println("Looking for OVF in artifact...") 60 file_matches, err := filepath.Glob(filepath.Join(dir, "*.ovf")) 61 if err != nil { 62 return "", err 63 } 64 65 if len(file_matches) > 1 { 66 return "", errors.New("More than one OVF file in VirtualBox artifact.") 67 } 68 69 if len(file_matches) < 1 { 70 return "", errors.New("ovf file couldn't be found") 71 } 72 73 return file_matches[0], err 74 } 75 76 func (p *VBoxProvider) renameOVF(dir string) error { 77 log.Println("Looking for OVF to rename...") 78 ovf, err := p.findOvf(dir) 79 if err != nil { 80 return err 81 } 82 83 log.Printf("Renaming: '%s' => box.ovf", ovf) 84 return os.Rename(ovf, filepath.Join(dir, "box.ovf")) 85 } 86 87 func (p *VBoxProvider) findBaseMacAddress(dir string) (string, error) { 88 log.Println("Looking for OVF for base mac address...") 89 ovf, err := p.findOvf(dir) 90 if err != nil { 91 return "", err 92 } 93 94 f, err := os.Open(ovf) 95 if err != nil { 96 return "", err 97 } 98 defer f.Close() 99 100 data, err := ioutil.ReadAll(f) 101 if err != nil { 102 return "", err 103 } 104 105 re := regexp.MustCompile(`<Adapter slot="0".+?MACAddress="(.+?)"`) 106 matches := re.FindSubmatch(data) 107 if matches == nil { 108 return "", errors.New("can't find base mac address in OVF") 109 } 110 111 log.Printf("Base mac address: %s", string(matches[1])) 112 return string(matches[1]), nil 113 } 114 115 // DecompressOva takes an ova file and decompresses it into the target 116 // directory. 117 func DecompressOva(dir, src string) error { 118 log.Printf("Turning ova to dir: %s => %s", src, dir) 119 srcF, err := os.Open(src) 120 if err != nil { 121 return err 122 } 123 defer srcF.Close() 124 125 tarReader := tar.NewReader(srcF) 126 for { 127 hdr, err := tarReader.Next() 128 if hdr == nil || err == io.EOF { 129 break 130 } 131 132 info := hdr.FileInfo() 133 134 // Shouldn't be any directories, skip them 135 if info.IsDir() { 136 continue 137 } 138 139 // We wrap this in an anonymous function so that the defers 140 // inside are handled more quickly so we can give up file handles. 141 err = func() error { 142 path := filepath.Join(dir, info.Name()) 143 output, err := os.Create(path) 144 if err != nil { 145 return err 146 } 147 defer output.Close() 148 149 os.Chmod(path, info.Mode()) 150 os.Chtimes(path, hdr.AccessTime, hdr.ModTime) 151 _, err = io.Copy(output, tarReader) 152 return err 153 }() 154 if err != nil { 155 return err 156 } 157 } 158 159 return nil 160 } 161 162 var vboxVagrantfile = ` 163 Vagrant.configure("2") do |config| 164 config.vm.base_mac = "%s" 165 end 166 `