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