Merge pull request #1440 from legal90/master

Enhancements for Parallels builder
This commit is contained in:
Rickard von Essen 2014-08-26 00:49:52 +02:00
commit b0161f40fe
6 changed files with 65 additions and 31 deletions

View File

@ -1,8 +1,11 @@
package common package common
import ( import (
"fmt"
"log" "log"
"os/exec" "os/exec"
"runtime"
"strings"
) )
// A driver is able to talk to Parallels and perform certain // A driver is able to talk to Parallels and perform certain
@ -43,7 +46,14 @@ type Driver interface {
} }
func NewDriver() (Driver, error) { func NewDriver() (Driver, error) {
var drivers map[string]Driver
var prlctlPath string var prlctlPath string
var supportedVersions []string
if runtime.GOOS != "darwin" {
return nil, fmt.Errorf(
"Parallels builder works only on \"darwin\" platform!")
}
if prlctlPath == "" { if prlctlPath == "" {
var err error var err error
@ -54,10 +64,27 @@ func NewDriver() (Driver, error) {
} }
log.Printf("prlctl path: %s", prlctlPath) log.Printf("prlctl path: %s", prlctlPath)
driver := &Parallels9Driver{prlctlPath}
if err := driver.Verify(); err != nil { drivers = map[string]Driver{
return nil, err "10": &Parallels10Driver{
Parallels9Driver: Parallels9Driver{
PrlctlPath: prlctlPath,
},
},
"9": &Parallels9Driver{
PrlctlPath: prlctlPath,
},
} }
return driver, nil for v, d := range drivers {
version, _ := d.Version()
if strings.HasPrefix(version, v) {
return d, nil
}
supportedVersions = append(supportedVersions, v)
}
return nil, fmt.Errorf(
"Unable to initialize any driver. Supported Parallels Desktop versions: "+
"%s\n", strings.Join(supportedVersions, ", "))
} }

View File

@ -0,0 +1,6 @@
package common
// Parallels10Driver are inherited from Parallels9Driver.
type Parallels10Driver struct {
Parallels9Driver
}

View File

@ -13,7 +13,6 @@ import (
"github.com/going/toolkit/xmlpath" "github.com/going/toolkit/xmlpath"
) )
// Driver supporting Parallels Desktop for Mac v. 9 & 10
type Parallels9Driver struct { type Parallels9Driver struct {
// This is the path to the "prlctl" application. // This is the path to the "prlctl" application.
PrlctlPath string PrlctlPath string
@ -72,6 +71,20 @@ func getConfigValueFromXpath(path, xpath string) (string, error) {
return value, nil return value, nil
} }
// Finds an application bundle by identifier (for "darwin" platform only)
func getAppPath(bundleId string) (string, error) {
cmd := exec.Command("mdfind", "kMDItemCFBundleIdentifier ==", bundleId)
out, err := cmd.Output()
if err != nil {
return "", err
}
if string(out) == "" {
return "", fmt.Errorf(
"Could not detect Parallels Desktop! Make sure it is properly installed.")
}
return string(out), nil
}
func (d *Parallels9Driver) IsRunning(name string) (bool, error) { func (d *Parallels9Driver) IsRunning(name string) (bool, error) {
var stdout bytes.Buffer var stdout bytes.Buffer
@ -136,32 +149,24 @@ func (d *Parallels9Driver) Prlctl(args ...string) error {
} }
func (d *Parallels9Driver) Verify() error { func (d *Parallels9Driver) Verify() error {
version, _ := d.Version()
if !(strings.HasPrefix(version, "9.") || strings.HasPrefix(version, "10.")) {
return fmt.Errorf("The packer-parallels builder plugin only supports Parallels Desktop v. 9 & 10. You have: %s!\n", version)
}
return nil return nil
} }
func (d *Parallels9Driver) Version() (string, error) { func (d *Parallels9Driver) Version() (string, error) {
var stdout bytes.Buffer out, err := exec.Command(d.PrlctlPath, "--version").Output()
if err != nil {
cmd := exec.Command(d.PrlctlPath, "--version")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err return "", err
} }
versionOutput := strings.TrimSpace(stdout.String()) versionRe := regexp.MustCompile(`prlctl version (\d+\.\d+.\d+)`)
re := regexp.MustCompile("prlctl version ([0-9\\.]+)") matches := versionRe.FindStringSubmatch(string(out))
verMatch := re.FindAllStringSubmatch(versionOutput, 1) if matches == nil {
return "", fmt.Errorf(
if len(verMatch) != 1 { "Could not find Parallels Desktop version in output:\n%s", string(out))
return "", fmt.Errorf("prlctl version not found!\n")
} }
version := verMatch[0][1] version := matches[1]
log.Printf("prlctl version: %s\n", version) log.Printf("Parallels Desktop version: %s", version)
return version, nil return version, nil
} }

View File

@ -33,7 +33,6 @@ type config struct {
ParallelsToolsMode string `mapstructure:"parallels_tools_mode"` ParallelsToolsMode string `mapstructure:"parallels_tools_mode"`
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"` ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"`
ParallelsToolsHostPath string `mapstructure:"parallels_tools_host_path"` ParallelsToolsHostPath string `mapstructure:"parallels_tools_host_path"`
GuestOSType string `mapstructure:"guest_os_type"`
GuestOSDistribution string `mapstructure:"guest_os_distribution"` GuestOSDistribution string `mapstructure:"guest_os_distribution"`
HardDriveInterface string `mapstructure:"hard_drive_interface"` HardDriveInterface string `mapstructure:"hard_drive_interface"`
HostInterfaces []string `mapstructure:"host_interfaces"` HostInterfaces []string `mapstructure:"host_interfaces"`
@ -47,6 +46,9 @@ type config struct {
RawSingleISOUrl string `mapstructure:"iso_url"` RawSingleISOUrl string `mapstructure:"iso_url"`
// Deprecated parameters
GuestOSType string `mapstructure:"guest_os_type"`
tpl *packer.ConfigTemplate tpl *packer.ConfigTemplate
} }
@ -95,10 +97,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.HardDriveInterface = "sata" b.config.HardDriveInterface = "sata"
} }
if b.config.GuestOSType == "" {
b.config.GuestOSType = "other"
}
if b.config.GuestOSDistribution == "" { if b.config.GuestOSDistribution == "" {
b.config.GuestOSDistribution = "other" b.config.GuestOSDistribution = "other"
} }
@ -125,7 +123,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
"parallels_tools_mode": &b.config.ParallelsToolsMode, "parallels_tools_mode": &b.config.ParallelsToolsMode,
"parallels_tools_host_path": &b.config.ParallelsToolsHostPath, "parallels_tools_host_path": &b.config.ParallelsToolsHostPath,
"parallels_tools_guest_path": &b.config.ParallelsToolsGuestPath, "parallels_tools_guest_path": &b.config.ParallelsToolsGuestPath,
"guest_os_type": &b.config.GuestOSType,
"guest_os_distribution": &b.config.GuestOSDistribution, "guest_os_distribution": &b.config.GuestOSDistribution,
"hard_drive_interface": &b.config.HardDriveInterface, "hard_drive_interface": &b.config.HardDriveInterface,
"http_directory": &b.config.HTTPDir, "http_directory": &b.config.HTTPDir,

View File

@ -42,8 +42,8 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
t.Errorf("bad parallels tools mode: %s", b.config.ParallelsToolsMode) t.Errorf("bad parallels tools mode: %s", b.config.ParallelsToolsMode)
} }
if b.config.GuestOSType != "other" { if b.config.GuestOSDistribution != "other" {
t.Errorf("bad guest OS type: %s", b.config.GuestOSType) t.Errorf("bad guest OS distribution: %s", b.config.GuestOSDistribution)
} }
if b.config.VMName != "packer-foo" { if b.config.VMName != "packer-foo" {

View File

@ -28,7 +28,6 @@ func (s *stepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
commands := make([][]string, 8) commands := make([][]string, 8)
commands[0] = []string{ commands[0] = []string{
"create", name, "create", name,
"--ostype", config.GuestOSType,
"--distribution", config.GuestOSDistribution, "--distribution", config.GuestOSDistribution,
"--dst", path, "--dst", path,
"--vmtype", "vm", "--vmtype", "vm",