2019-01-11 17:06:15 -05:00
|
|
|
package vagrant
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
2019-10-24 13:06:46 -04:00
|
|
|
"time"
|
2019-01-25 15:32:44 -05:00
|
|
|
|
|
|
|
"github.com/hashicorp/go-version"
|
2019-01-11 17:06:15 -05:00
|
|
|
)
|
|
|
|
|
2019-01-25 15:32:44 -05:00
|
|
|
const VAGRANT_MIN_VERSION = ">= 2.0.2"
|
|
|
|
|
2019-01-11 17:06:15 -05:00
|
|
|
type Vagrant_2_2_Driver struct {
|
|
|
|
vagrantBinary string
|
2019-02-07 17:35:01 -05:00
|
|
|
VagrantCWD string
|
2019-01-11 17:06:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Calls "vagrant init"
|
|
|
|
func (d *Vagrant_2_2_Driver) Init(args []string) error {
|
|
|
|
_, _, err := d.vagrantCmd(append([]string{"init"}, args...)...)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls "vagrant add"
|
|
|
|
func (d *Vagrant_2_2_Driver) Add(args []string) error {
|
|
|
|
// vagrant box add partyvm ubuntu-14.04.vmware.box
|
|
|
|
_, _, err := d.vagrantCmd(append([]string{"box", "add"}, args...)...)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls "vagrant up"
|
|
|
|
func (d *Vagrant_2_2_Driver) Up(args []string) (string, string, error) {
|
|
|
|
stdout, stderr, err := d.vagrantCmd(append([]string{"up"}, args...)...)
|
|
|
|
return stdout, stderr, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls "vagrant halt"
|
2019-01-25 15:32:44 -05:00
|
|
|
func (d *Vagrant_2_2_Driver) Halt(id string) error {
|
|
|
|
args := []string{"halt"}
|
|
|
|
if id != "" {
|
|
|
|
args = append(args, id)
|
|
|
|
}
|
|
|
|
_, _, err := d.vagrantCmd(args...)
|
2019-01-11 17:06:15 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls "vagrant suspend"
|
2019-01-25 15:32:44 -05:00
|
|
|
func (d *Vagrant_2_2_Driver) Suspend(id string) error {
|
|
|
|
args := []string{"suspend"}
|
|
|
|
if id != "" {
|
|
|
|
args = append(args, id)
|
|
|
|
}
|
|
|
|
_, _, err := d.vagrantCmd(args...)
|
2019-01-11 17:06:15 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls "vagrant destroy"
|
2019-01-25 15:32:44 -05:00
|
|
|
func (d *Vagrant_2_2_Driver) Destroy(id string) error {
|
|
|
|
args := []string{"destroy", "-f"}
|
|
|
|
if id != "" {
|
|
|
|
args = append(args, id)
|
|
|
|
}
|
|
|
|
_, _, err := d.vagrantCmd(args...)
|
2019-01-11 17:06:15 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calls "vagrant package"
|
|
|
|
func (d *Vagrant_2_2_Driver) Package(args []string) error {
|
2019-05-09 19:36:32 -04:00
|
|
|
// Ideally we'd pass vagrantCWD into the package command but
|
2019-05-13 04:43:09 -04:00
|
|
|
// we have to change directory into the vagrant cwd instead in order to
|
2019-05-09 19:36:32 -04:00
|
|
|
// work around an upstream bug with the vagrant-libvirt plugin.
|
|
|
|
// We can stop doing this when
|
|
|
|
// https://github.com/vagrant-libvirt/vagrant-libvirt/issues/765
|
|
|
|
// is fixed.
|
|
|
|
oldDir, _ := os.Getwd()
|
|
|
|
os.Chdir(d.VagrantCWD)
|
|
|
|
defer os.Chdir(oldDir)
|
|
|
|
args = append(args, "--output", "package.box")
|
2019-01-25 15:32:44 -05:00
|
|
|
_, _, err := d.vagrantCmd(append([]string{"package"}, args...)...)
|
2019-01-11 17:06:15 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify makes sure that Vagrant exists at the given path
|
|
|
|
func (d *Vagrant_2_2_Driver) Verify() error {
|
|
|
|
vagrantPath, err := exec.LookPath(d.vagrantBinary)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Can't find Vagrant binary!")
|
|
|
|
}
|
|
|
|
_, err = os.Stat(vagrantPath)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Can't find Vagrant binary.")
|
|
|
|
}
|
2019-01-25 15:32:44 -05:00
|
|
|
|
|
|
|
constraints, err := version.NewConstraint(VAGRANT_MIN_VERSION)
|
2019-09-17 08:39:23 -04:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error parsing vagrant minimum version: %v", err)
|
|
|
|
}
|
2019-01-25 15:32:44 -05:00
|
|
|
vers, err := d.Version()
|
2019-09-17 08:39:23 -04:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error getting virtualbox version: %v", err)
|
|
|
|
}
|
2019-01-25 15:32:44 -05:00
|
|
|
v, err := version.NewVersion(vers)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error figuring out Vagrant version.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !constraints.Check(v) {
|
|
|
|
return fmt.Errorf("installed Vagrant version must be >=2.0.2")
|
|
|
|
}
|
|
|
|
|
2019-01-11 17:06:15 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type VagrantSSHConfig struct {
|
|
|
|
Hostname string
|
|
|
|
User string
|
|
|
|
Port string
|
|
|
|
UserKnownHostsFile string
|
|
|
|
StrictHostKeyChecking bool
|
|
|
|
PasswordAuthentication bool
|
|
|
|
IdentityFile string
|
|
|
|
IdentitiesOnly bool
|
|
|
|
LogLevel string
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseSSHConfig(lines []string, value string) string {
|
|
|
|
out := ""
|
|
|
|
for _, line := range lines {
|
|
|
|
if index := strings.Index(line, value); index != -1 {
|
|
|
|
out = line[index+len(value):]
|
|
|
|
}
|
|
|
|
}
|
2019-03-15 21:00:27 -04:00
|
|
|
return strings.Trim(out, "\r\n")
|
2019-01-11 17:06:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func yesno(yn string) bool {
|
|
|
|
if yn == "no" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-01-25 15:32:44 -05:00
|
|
|
func (d *Vagrant_2_2_Driver) SSHConfig(id string) (*VagrantSSHConfig, error) {
|
2019-01-11 17:06:15 -05:00
|
|
|
// vagrant ssh-config --host 8df7860
|
2019-01-25 15:32:44 -05:00
|
|
|
args := []string{"ssh-config"}
|
|
|
|
if id != "" {
|
|
|
|
args = append(args, id)
|
|
|
|
}
|
|
|
|
stdout, _, err := d.vagrantCmd(args...)
|
2019-01-11 17:06:15 -05:00
|
|
|
sshConf := &VagrantSSHConfig{}
|
|
|
|
|
|
|
|
lines := strings.Split(stdout, "\n")
|
|
|
|
sshConf.Hostname = parseSSHConfig(lines, "HostName ")
|
|
|
|
sshConf.User = parseSSHConfig(lines, "User ")
|
|
|
|
sshConf.Port = parseSSHConfig(lines, "Port ")
|
|
|
|
sshConf.UserKnownHostsFile = parseSSHConfig(lines, "UserKnownHostsFile ")
|
|
|
|
sshConf.IdentityFile = parseSSHConfig(lines, "IdentityFile ")
|
|
|
|
sshConf.LogLevel = parseSSHConfig(lines, "LogLevel ")
|
|
|
|
|
|
|
|
// handle the booleans
|
|
|
|
sshConf.StrictHostKeyChecking = yesno(parseSSHConfig(lines, "StrictHostKeyChecking "))
|
|
|
|
sshConf.PasswordAuthentication = yesno(parseSSHConfig(lines, "PasswordAuthentication "))
|
|
|
|
sshConf.IdentitiesOnly = yesno((parseSSHConfig(lines, "IdentitiesOnly ")))
|
|
|
|
|
|
|
|
return sshConf, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Version reads the version of VirtualBox that is installed.
|
|
|
|
func (d *Vagrant_2_2_Driver) Version() (string, error) {
|
2019-01-25 15:32:44 -05:00
|
|
|
stdoutString, _, err := d.vagrantCmd([]string{"--version"}...)
|
2019-01-11 17:06:15 -05:00
|
|
|
// Example stdout:
|
|
|
|
|
|
|
|
// Installed Version: 2.2.3
|
|
|
|
//
|
|
|
|
// Vagrant was unable to check for the latest version of Vagrant.
|
|
|
|
// Please check manually at https://www.vagrantup.com
|
|
|
|
|
|
|
|
// Use regex to find version
|
|
|
|
reg := regexp.MustCompile(`(\d+\.)?(\d+\.)?(\*|\d+)`)
|
|
|
|
version := reg.FindString(stdoutString)
|
|
|
|
if version == "" {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return version, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Vagrant_2_2_Driver) vagrantCmd(args ...string) (string, string, error) {
|
|
|
|
var stdout, stderr bytes.Buffer
|
|
|
|
|
|
|
|
log.Printf("Calling Vagrant CLI: %#v", args)
|
|
|
|
cmd := exec.Command(d.vagrantBinary, args...)
|
2019-02-07 17:35:01 -05:00
|
|
|
cmd.Env = append(os.Environ(), fmt.Sprintf("VAGRANT_CWD=%s", d.VagrantCWD))
|
2019-01-11 17:06:15 -05:00
|
|
|
cmd.Stdout = &stdout
|
|
|
|
cmd.Stderr = &stderr
|
|
|
|
|
2019-10-24 13:06:46 -04:00
|
|
|
cmd.Start()
|
|
|
|
|
|
|
|
stdoutString := ""
|
|
|
|
stderrString := ""
|
|
|
|
|
|
|
|
donech := make(chan bool)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-donech:
|
|
|
|
line := stdout.String()
|
|
|
|
if line != "" {
|
|
|
|
log.Printf("[vagrant driver] stdout: %s", line)
|
|
|
|
}
|
|
|
|
stdoutString += line
|
|
|
|
line = stderr.String()
|
|
|
|
if line != "" {
|
|
|
|
log.Printf("[vagrant driver] stderr: %s", line)
|
|
|
|
}
|
|
|
|
stderrString += line
|
|
|
|
default:
|
|
|
|
line, _ := stdout.ReadString('\n')
|
|
|
|
if line != "" {
|
|
|
|
log.Printf("[vagrant driver] stdout: %s", line)
|
|
|
|
stdoutString += line
|
|
|
|
|
|
|
|
}
|
|
|
|
line, _ = stderr.ReadString('\n')
|
|
|
|
if line != "" {
|
|
|
|
log.Printf("[vagrant driver] stderr: %s", line)
|
|
|
|
stderrString += line
|
|
|
|
|
|
|
|
}
|
|
|
|
time.Sleep(500)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
err := cmd.Wait()
|
|
|
|
|
|
|
|
donech <- true
|
2019-01-11 17:06:15 -05:00
|
|
|
|
|
|
|
if _, ok := err.(*exec.ExitError); ok {
|
|
|
|
err = fmt.Errorf("Vagrant error: %s", stderrString)
|
|
|
|
}
|
|
|
|
|
|
|
|
return stdoutString, stderrString, err
|
|
|
|
}
|