github.com/rothwerx/packer@v0.9.0/builder/virtualbox/common/driver_4_2.go (about) 1 package common 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "os/exec" 8 "regexp" 9 "strings" 10 "time" 11 ) 12 13 type VBox42Driver struct { 14 // This is the path to the "VBoxManage" application. 15 VBoxManagePath string 16 } 17 18 func (d *VBox42Driver) CreateSATAController(vmName string, name string) error { 19 version, err := d.Version() 20 if err != nil { 21 return err 22 } 23 24 portCountArg := "--sataportcount" 25 if strings.HasPrefix(version, "4.3") || strings.HasPrefix(version, "5.") { 26 portCountArg = "--portcount" 27 } 28 29 command := []string{ 30 "storagectl", vmName, 31 "--name", name, 32 "--add", "sata", 33 portCountArg, "1", 34 } 35 36 return d.VBoxManage(command...) 37 } 38 39 func (d *VBox42Driver) CreateSCSIController(vmName string, name string) error { 40 41 command := []string{ 42 "storagectl", vmName, 43 "--name", name, 44 "--add", "scsi", 45 "--controller", "LSILogic", 46 } 47 48 return d.VBoxManage(command...) 49 } 50 51 func (d *VBox42Driver) Delete(name string) error { 52 return d.VBoxManage("unregistervm", name, "--delete") 53 } 54 55 func (d *VBox42Driver) Iso() (string, error) { 56 var stdout bytes.Buffer 57 58 cmd := exec.Command(d.VBoxManagePath, "list", "systemproperties") 59 cmd.Stdout = &stdout 60 if err := cmd.Run(); err != nil { 61 return "", err 62 } 63 64 DefaultGuestAdditionsRe := regexp.MustCompile("Default Guest Additions ISO:(.+)") 65 66 for _, line := range strings.Split(stdout.String(), "\n") { 67 // Need to trim off CR character when running in windows 68 // Trimming whitespaces at this point helps to filter out empty value 69 line = strings.TrimRight(line, " \r") 70 71 matches := DefaultGuestAdditionsRe.FindStringSubmatch(line) 72 if matches == nil { 73 continue 74 } 75 76 isoname := strings.Trim(matches[1], " \r\n") 77 log.Printf("Found Default Guest Additions ISO: %s", isoname) 78 79 return isoname, nil 80 } 81 82 return "", fmt.Errorf("Cannot find \"Default Guest Additions ISO\" in vboxmanage output (or it is empty)") 83 } 84 85 func (d *VBox42Driver) Import(name string, path string, flags []string) error { 86 args := []string{ 87 "import", path, 88 "--vsys", "0", 89 "--vmname", name, 90 } 91 args = append(args, flags...) 92 93 return d.VBoxManage(args...) 94 } 95 96 func (d *VBox42Driver) IsRunning(name string) (bool, error) { 97 var stdout bytes.Buffer 98 99 cmd := exec.Command(d.VBoxManagePath, "showvminfo", name, "--machinereadable") 100 cmd.Stdout = &stdout 101 if err := cmd.Run(); err != nil { 102 return false, err 103 } 104 105 for _, line := range strings.Split(stdout.String(), "\n") { 106 // Need to trim off CR character when running in windows 107 line = strings.TrimRight(line, "\r") 108 109 if line == `VMState="running"` { 110 return true, nil 111 } 112 113 // We consider "stopping" to still be running. We wait for it to 114 // be completely stopped or some other state. 115 if line == `VMState="stopping"` { 116 return true, nil 117 } 118 119 // We consider "paused" to still be running. We wait for it to 120 // be completely stopped or some other state. 121 if line == `VMState="paused"` { 122 return true, nil 123 } 124 } 125 126 return false, nil 127 } 128 129 func (d *VBox42Driver) Stop(name string) error { 130 if err := d.VBoxManage("controlvm", name, "poweroff"); err != nil { 131 return err 132 } 133 134 // We sleep here for a little bit to let the session "unlock" 135 time.Sleep(2 * time.Second) 136 137 return nil 138 } 139 140 func (d *VBox42Driver) SuppressMessages() error { 141 extraData := map[string]string{ 142 "GUI/RegistrationData": "triesLeft=0", 143 "GUI/SuppressMessages": "confirmInputCapture,remindAboutAutoCapture,remindAboutMouseIntegrationOff,remindAboutMouseIntegrationOn,remindAboutWrongColorDepth", 144 "GUI/UpdateDate": fmt.Sprintf("1 d, %d-01-01, stable", time.Now().Year()+1), 145 "GUI/UpdateCheckCount": "60", 146 } 147 148 for k, v := range extraData { 149 if err := d.VBoxManage("setextradata", "global", k, v); err != nil { 150 return err 151 } 152 } 153 154 return nil 155 } 156 157 func (d *VBox42Driver) VBoxManage(args ...string) error { 158 var stdout, stderr bytes.Buffer 159 160 log.Printf("Executing VBoxManage: %#v", args) 161 cmd := exec.Command(d.VBoxManagePath, args...) 162 cmd.Stdout = &stdout 163 cmd.Stderr = &stderr 164 err := cmd.Run() 165 166 stdoutString := strings.TrimSpace(stdout.String()) 167 stderrString := strings.TrimSpace(stderr.String()) 168 169 if _, ok := err.(*exec.ExitError); ok { 170 err = fmt.Errorf("VBoxManage error: %s", stderrString) 171 } 172 173 if err == nil { 174 // Sometimes VBoxManage gives us an error with a zero exit code, 175 // so we also regexp match an error string. 176 m, _ := regexp.MatchString("VBoxManage([.a-z]+?): error:", stderrString) 177 if m { 178 err = fmt.Errorf("VBoxManage error: %s", stderrString) 179 } 180 } 181 182 log.Printf("stdout: %s", stdoutString) 183 log.Printf("stderr: %s", stderrString) 184 185 return err 186 } 187 188 func (d *VBox42Driver) Verify() error { 189 return nil 190 } 191 192 func (d *VBox42Driver) Version() (string, error) { 193 var stdout bytes.Buffer 194 195 cmd := exec.Command(d.VBoxManagePath, "--version") 196 cmd.Stdout = &stdout 197 if err := cmd.Run(); err != nil { 198 return "", err 199 } 200 201 versionOutput := strings.TrimSpace(stdout.String()) 202 log.Printf("VBoxManage --version output: %s", versionOutput) 203 204 // If the "--version" output contains vboxdrv, then this is indicative 205 // of problems with the VirtualBox setup and we shouldn't really continue, 206 // whether or not we can read the version. 207 if strings.Contains(versionOutput, "vboxdrv") { 208 return "", fmt.Errorf("VirtualBox is not properly setup: %s", versionOutput) 209 } 210 211 versionRe := regexp.MustCompile("^([.0-9]+)(?:_(?:RC|OSEr)[0-9]+)?") 212 matches := versionRe.FindAllStringSubmatch(versionOutput, 1) 213 if matches == nil || len(matches[0]) != 2 { 214 return "", fmt.Errorf("No version found: %s", versionOutput) 215 } 216 217 log.Printf("VirtualBox version: %s", matches[0][1]) 218 return matches[0][1], nil 219 }