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