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