Merge pull request #4292 from legal90/prl-fix-style

Parallels: Fix style warnings
This commit is contained in:
Rickard von Essen 2016-12-17 19:50:23 +01:00 committed by GitHub
commit bbe3f26ed2
46 changed files with 277 additions and 177 deletions

View File

@ -2,13 +2,14 @@ package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/packer/packer"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"github.com/mitchellh/packer/packer"
) )
// This is the common builder ID to all of these artifacts. // BuilderId is the common builder ID to all of these artifacts.
const BuilderId = "packer.parallels" const BuilderId = "packer.parallels"
// These are the extensions of files and directories that are unnecessary for the function // These are the extensions of files and directories that are unnecessary for the function

View File

@ -25,7 +25,7 @@ func TestNewArtifact(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
if err := os.Mkdir(filepath.Join(td, "b"), 0755); err != nil { if err = os.Mkdir(filepath.Join(td, "b"), 0755); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }

View File

@ -9,7 +9,7 @@ import (
"strings" "strings"
) )
// A driver is able to talk to Parallels and perform certain // Driver is the interface that talks to Parallels and performs certain
// operations with it. Some of the operations on here may seem overly // operations with it. Some of the operations on here may seem overly
// specific, but they were built specifically in mind to handle features // specific, but they were built specifically in mind to handle features
// of the Parallels builder for Packer, and to abstract differences in // of the Parallels builder for Packer, and to abstract differences in
@ -20,7 +20,7 @@ type Driver interface {
CompactDisk(string) error CompactDisk(string) error
// Adds new CD/DVD drive to the VM and returns name of this device // Adds new CD/DVD drive to the VM and returns name of this device
DeviceAddCdRom(string, string) (string, error) DeviceAddCDROM(string, string) (string, error)
// Get path to the first virtual disk image // Get path to the first virtual disk image
DiskPath(string) (string, error) DiskPath(string) (string, error)
@ -38,7 +38,7 @@ type Driver interface {
Prlctl(...string) error Prlctl(...string) error
// Get the path to the Parallels Tools ISO for the given flavor. // Get the path to the Parallels Tools ISO for the given flavor.
ToolsIsoPath(string) (string, error) ToolsISOPath(string) (string, error)
// Verify checks to make sure that this driver should function // Verify checks to make sure that this driver should function
// properly. If there is any indication the driver can't function, // properly. If there is any indication the driver can't function,
@ -55,18 +55,20 @@ type Driver interface {
SetDefaultConfiguration(string) error SetDefaultConfiguration(string) error
// Finds the MAC address of the NIC nic0 // Finds the MAC address of the NIC nic0
Mac(string) (string, error) MAC(string) (string, error)
// Finds the IP address of a VM connected that uses DHCP by its MAC address // Finds the IP address of a VM connected that uses DHCP by its MAC address
IpAddress(string) (string, error) IPAddress(string) (string, error)
} }
// NewDriver returns a new driver implementation for this version of Parallels
// Desktop, or an error if the driver couldn't be initialized.
func NewDriver() (Driver, error) { func NewDriver() (Driver, error) {
var drivers map[string]Driver var drivers map[string]Driver
var prlctlPath string var prlctlPath string
var prlsrvctlPath string var prlsrvctlPath string
var supportedVersions []string var supportedVersions []string
dhcp_lease_file := "/Library/Preferences/Parallels/parallels_dhcp_leases" DHCPLeaseFile := "/Library/Preferences/Parallels/parallels_dhcp_leases"
if runtime.GOOS != "darwin" { if runtime.GOOS != "darwin" {
return nil, fmt.Errorf( return nil, fmt.Errorf(
@ -96,22 +98,22 @@ func NewDriver() (Driver, error) {
drivers = map[string]Driver{ drivers = map[string]Driver{
"11": &Parallels11Driver{ "11": &Parallels11Driver{
Parallels9Driver: Parallels9Driver{ Parallels9Driver: Parallels9Driver{
PrlctlPath: prlctlPath, PrlctlPath: prlctlPath,
PrlsrvctlPath: prlsrvctlPath, PrlsrvctlPath: prlsrvctlPath,
dhcp_lease_file: dhcp_lease_file, dhcpLeaseFile: DHCPLeaseFile,
}, },
}, },
"10": &Parallels10Driver{ "10": &Parallels10Driver{
Parallels9Driver: Parallels9Driver{ Parallels9Driver: Parallels9Driver{
PrlctlPath: prlctlPath, PrlctlPath: prlctlPath,
PrlsrvctlPath: prlsrvctlPath, PrlsrvctlPath: prlsrvctlPath,
dhcp_lease_file: dhcp_lease_file, dhcpLeaseFile: DHCPLeaseFile,
}, },
}, },
"9": &Parallels9Driver{ "9": &Parallels9Driver{
PrlctlPath: prlctlPath, PrlctlPath: prlctlPath,
PrlsrvctlPath: prlsrvctlPath, PrlsrvctlPath: prlsrvctlPath,
dhcp_lease_file: dhcp_lease_file, dhcpLeaseFile: DHCPLeaseFile,
}, },
} }

View File

@ -1,11 +1,11 @@
package common package common
// Parallels10Driver are inherited from Parallels9Driver. // Parallels10Driver are inherited from Parallels9Driver.
// Used for Parallels v 10 & 11
type Parallels10Driver struct { type Parallels10Driver struct {
Parallels9Driver Parallels9Driver
} }
// SetDefaultConfiguration applies pre-defined default settings to the VM config.
func (d *Parallels10Driver) SetDefaultConfiguration(vmName string) error { func (d *Parallels10Driver) SetDefaultConfiguration(vmName string) error {
commands := make([][]string, 12) commands := make([][]string, 12)
commands[0] = []string{"set", vmName, "--cpus", "1"} commands[0] = []string{"set", vmName, "--cpus", "1"}

View File

@ -12,6 +12,7 @@ type Parallels11Driver struct {
Parallels9Driver Parallels9Driver
} }
// Verify raises an error if the builder could not be used on that host machine.
func (d *Parallels11Driver) Verify() error { func (d *Parallels11Driver) Verify() error {
stdout, err := exec.Command(d.PrlsrvctlPath, "info", "--license").Output() stdout, err := exec.Command(d.PrlsrvctlPath, "info", "--license").Output()
@ -24,18 +25,18 @@ func (d *Parallels11Driver) Verify() error {
if matches == nil { if matches == nil {
return fmt.Errorf( return fmt.Errorf(
"Could not determine your Parallels Desktop edition using: %s info --license", d.PrlsrvctlPath) "Could not determine your Parallels Desktop edition using: %s info --license", d.PrlsrvctlPath)
} else { }
switch matches[1] { switch matches[1] {
case "pro", "business": case "pro", "business":
break break
default: default:
return fmt.Errorf("Packer can be used only with Parallels Desktop 11 Pro or Business edition. You use: %s edition", matches[1]) return fmt.Errorf("Packer can be used only with Parallels Desktop 11 Pro or Business edition. You use: %s edition", matches[1])
}
} }
return nil return nil
} }
// SetDefaultConfiguration applies pre-defined default settings to the VM config.
func (d *Parallels11Driver) SetDefaultConfiguration(vmName string) error { func (d *Parallels11Driver) SetDefaultConfiguration(vmName string) error {
commands := make([][]string, 12) commands := make([][]string, 12)
commands[0] = []string{"set", vmName, "--cpus", "1"} commands[0] = []string{"set", vmName, "--cpus", "1"}

View File

@ -16,6 +16,7 @@ import (
"gopkg.in/xmlpath.v2" "gopkg.in/xmlpath.v2"
) )
// Parallels9Driver is a base type for Parallels builders.
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
@ -24,48 +25,51 @@ type Parallels9Driver struct {
PrlsrvctlPath string PrlsrvctlPath string
// The path to the parallels_dhcp_leases file // The path to the parallels_dhcp_leases file
dhcp_lease_file string dhcpLeaseFile string
} }
func (d *Parallels9Driver) Import(name, srcPath, dstDir string, reassignMac bool) error { // Import creates a clone of the source VM and reassigns the MAC address if needed.
func (d *Parallels9Driver) Import(name, srcPath, dstDir string, reassignMAC bool) error {
err := d.Prlctl("register", srcPath, "--preserve-uuid") err := d.Prlctl("register", srcPath, "--preserve-uuid")
if err != nil { if err != nil {
return err return err
} }
srcId, err := getVmId(srcPath) srcID, err := getVMID(srcPath)
if err != nil { if err != nil {
return err return err
} }
srcMac := "auto" srcMAC := "auto"
if !reassignMac { if !reassignMAC {
srcMac, err = getFirtsMacAddress(srcPath) srcMAC, err = getFirtsMACAddress(srcPath)
if err != nil { if err != nil {
return err return err
} }
} }
err = d.Prlctl("clone", srcId, "--name", name, "--dst", dstDir) err = d.Prlctl("clone", srcID, "--name", name, "--dst", dstDir)
if err != nil { if err != nil {
return err return err
} }
err = d.Prlctl("unregister", srcId) err = d.Prlctl("unregister", srcID)
if err != nil { if err != nil {
return err return err
} }
err = d.Prlctl("set", name, "--device-set", "net0", "--mac", srcMac) err = d.Prlctl("set", name, "--device-set", "net0", "--mac", srcMAC)
if err != nil {
return err
}
return nil return nil
} }
func getVmId(path string) (string, error) { func getVMID(path string) (string, error) {
return getConfigValueFromXpath(path, "/ParallelsVirtualMachine/Identification/VmUuid") return getConfigValueFromXpath(path, "/ParallelsVirtualMachine/Identification/VmUuid")
} }
func getFirtsMacAddress(path string) (string, error) { func getFirtsMACAddress(path string) (string, error) {
return getConfigValueFromXpath(path, "/ParallelsVirtualMachine/Hardware/NetworkAdapter[@id='0']/MAC") return getConfigValueFromXpath(path, "/ParallelsVirtualMachine/Hardware/NetworkAdapter[@id='0']/MAC")
} }
@ -84,10 +88,10 @@ func getConfigValueFromXpath(path, xpath string) (string, error) {
} }
// Finds an application bundle by identifier (for "darwin" platform only) // Finds an application bundle by identifier (for "darwin" platform only)
func getAppPath(bundleId string) (string, error) { func getAppPath(bundleID string) (string, error) {
var stdout bytes.Buffer var stdout bytes.Buffer
cmd := exec.Command("mdfind", "kMDItemCFBundleIdentifier ==", bundleId) cmd := exec.Command("mdfind", "kMDItemCFBundleIdentifier ==", bundleID)
cmd.Stdout = &stdout cmd.Stdout = &stdout
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return "", err return "", err
@ -108,6 +112,7 @@ func getAppPath(bundleId string) (string, error) {
return pathOutput, nil return pathOutput, nil
} }
// CompactDisk performs the compation of the specified virtual disk image.
func (d *Parallels9Driver) CompactDisk(diskPath string) error { func (d *Parallels9Driver) CompactDisk(diskPath string) error {
prlDiskToolPath, err := exec.LookPath("prl_disk_tool") prlDiskToolPath, err := exec.LookPath("prl_disk_tool")
if err != nil { if err != nil {
@ -135,7 +140,8 @@ func (d *Parallels9Driver) CompactDisk(diskPath string) error {
return nil return nil
} }
func (d *Parallels9Driver) DeviceAddCdRom(name string, image string) (string, error) { // DeviceAddCDROM adds a virtual CDROM device and attaches the specified image.
func (d *Parallels9Driver) DeviceAddCDROM(name string, image string) (string, error) {
command := []string{ command := []string{
"set", name, "set", name,
"--device-add", "cdrom", "--device-add", "cdrom",
@ -154,27 +160,29 @@ func (d *Parallels9Driver) DeviceAddCdRom(name string, image string) (string, er
"Could not determine cdrom device name in the output:\n%s", string(out)) "Could not determine cdrom device name in the output:\n%s", string(out))
} }
device_name := matches[1] deviceName := matches[1]
return device_name, nil return deviceName, nil
} }
// DiskPath returns a full path to the first virtual disk drive.
func (d *Parallels9Driver) DiskPath(name string) (string, error) { func (d *Parallels9Driver) DiskPath(name string) (string, error) {
out, err := exec.Command(d.PrlctlPath, "list", "-i", name).Output() out, err := exec.Command(d.PrlctlPath, "list", "-i", name).Output()
if err != nil { if err != nil {
return "", err return "", err
} }
hddRe := regexp.MustCompile("hdd0.* image='(.*)' type=*") HDDRe := regexp.MustCompile("hdd0.* image='(.*)' type=*")
matches := hddRe.FindStringSubmatch(string(out)) matches := HDDRe.FindStringSubmatch(string(out))
if matches == nil { if matches == nil {
return "", fmt.Errorf( return "", fmt.Errorf(
"Could not determine hdd image path in the output:\n%s", string(out)) "Could not determine hdd image path in the output:\n%s", string(out))
} }
hdd_path := matches[1] HDDPath := matches[1]
return hdd_path, nil return HDDPath, nil
} }
// IsRunning determines whether the VM is running or not.
func (d *Parallels9Driver) IsRunning(name string) (bool, error) { func (d *Parallels9Driver) IsRunning(name string) (bool, error) {
var stdout bytes.Buffer var stdout bytes.Buffer
@ -205,6 +213,7 @@ func (d *Parallels9Driver) IsRunning(name string) (bool, error) {
return false, nil return false, nil
} }
// Stop forcibly stops the VM.
func (d *Parallels9Driver) Stop(name string) error { func (d *Parallels9Driver) Stop(name string) error {
if err := d.Prlctl("stop", name); err != nil { if err := d.Prlctl("stop", name); err != nil {
return err return err
@ -216,6 +225,7 @@ func (d *Parallels9Driver) Stop(name string) error {
return nil return nil
} }
// Prlctl executes the specified "prlctl" command.
func (d *Parallels9Driver) Prlctl(args ...string) error { func (d *Parallels9Driver) Prlctl(args ...string) error {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
@ -238,10 +248,12 @@ func (d *Parallels9Driver) Prlctl(args ...string) error {
return err return err
} }
// Verify raises an error if the builder could not be used on that host machine.
func (d *Parallels9Driver) Verify() error { func (d *Parallels9Driver) Verify() error {
return nil return nil
} }
// Version returns the version of Parallels Desktop installed on that host.
func (d *Parallels9Driver) Version() (string, error) { func (d *Parallels9Driver) Version() (string, error) {
out, err := exec.Command(d.PrlctlPath, "--version").Output() out, err := exec.Command(d.PrlctlPath, "--version").Output()
if err != nil { if err != nil {
@ -260,6 +272,8 @@ func (d *Parallels9Driver) Version() (string, error) {
return version, nil return version, nil
} }
// SendKeyScanCodes sends the specified scancodes as key events to the VM.
// It is performed using "Prltype" script (refer to "prltype.go").
func (d *Parallels9Driver) SendKeyScanCodes(vmName string, codes ...string) error { func (d *Parallels9Driver) SendKeyScanCodes(vmName string, codes ...string) error {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
@ -309,6 +323,7 @@ func prepend(head string, tail []string) []string {
return tmp return tmp
} }
// SetDefaultConfiguration applies pre-defined default settings to the VM config.
func (d *Parallels9Driver) SetDefaultConfiguration(vmName string) error { func (d *Parallels9Driver) SetDefaultConfiguration(vmName string) error {
commands := make([][]string, 7) commands := make([][]string, 7)
commands[0] = []string{"set", vmName, "--cpus", "1"} commands[0] = []string{"set", vmName, "--cpus", "1"}
@ -328,7 +343,8 @@ func (d *Parallels9Driver) SetDefaultConfiguration(vmName string) error {
return nil return nil
} }
func (d *Parallels9Driver) Mac(vmName string) (string, error) { // MAC returns the MAC address of the VM's first network interface.
func (d *Parallels9Driver) MAC(vmName string) (string, error) {
var stdout bytes.Buffer var stdout bytes.Buffer
cmd := exec.Command(d.PrlctlPath, "list", "-i", vmName) cmd := exec.Command(d.PrlctlPath, "list", "-i", vmName)
@ -351,26 +367,26 @@ func (d *Parallels9Driver) Mac(vmName string) (string, error) {
return mac, nil return mac, nil
} }
// Finds the IP address of a VM connected that uses DHCP by its MAC address // IPAddress finds the IP address of a VM connected that uses DHCP by its MAC address
// //
// Parses the file /Library/Preferences/Parallels/parallels_dhcp_leases // Parses the file /Library/Preferences/Parallels/parallels_dhcp_leases
// file contain a list of DHCP leases given by Parallels Desktop // file contain a list of DHCP leases given by Parallels Desktop
// Example line: // Example line:
// 10.211.55.181="1418921112,1800,001c42f593fb,ff42f593fb000100011c25b9ff001c42f593fb" // 10.211.55.181="1418921112,1800,001c42f593fb,ff42f593fb000100011c25b9ff001c42f593fb"
// IP Address ="Lease expiry, Lease time, MAC, MAC or DUID" // IP Address ="Lease expiry, Lease time, MAC, MAC or DUID"
func (d *Parallels9Driver) IpAddress(mac string) (string, error) { func (d *Parallels9Driver) IPAddress(mac string) (string, error) {
if len(mac) != 12 { if len(mac) != 12 {
return "", fmt.Errorf("Not a valid MAC address: %s. It should be exactly 12 digits.", mac) return "", fmt.Errorf("Not a valid MAC address: %s. It should be exactly 12 digits.", mac)
} }
leases, err := ioutil.ReadFile(d.dhcp_lease_file) leases, err := ioutil.ReadFile(d.dhcpLeaseFile)
if err != nil { if err != nil {
return "", err return "", err
} }
re := regexp.MustCompile("(.*)=\"(.*),(.*)," + strings.ToLower(mac) + ",.*\"") re := regexp.MustCompile("(.*)=\"(.*),(.*)," + strings.ToLower(mac) + ",.*\"")
mostRecentIp := "" mostRecentIP := ""
mostRecentLease := uint64(0) mostRecentLease := uint64(0)
for _, l := range re.FindAllStringSubmatch(string(leases), -1) { for _, l := range re.FindAllStringSubmatch(string(leases), -1) {
ip := l[1] ip := l[1]
@ -378,20 +394,22 @@ func (d *Parallels9Driver) IpAddress(mac string) (string, error) {
leaseTime, _ := strconv.ParseUint(l[3], 10, 32) leaseTime, _ := strconv.ParseUint(l[3], 10, 32)
log.Printf("Found lease: %s for MAC: %s, expiring at %d, leased for %d s.\n", ip, mac, expiry, leaseTime) log.Printf("Found lease: %s for MAC: %s, expiring at %d, leased for %d s.\n", ip, mac, expiry, leaseTime)
if mostRecentLease <= expiry-leaseTime { if mostRecentLease <= expiry-leaseTime {
mostRecentIp = ip mostRecentIP = ip
mostRecentLease = expiry - leaseTime mostRecentLease = expiry - leaseTime
} }
} }
if len(mostRecentIp) == 0 { if len(mostRecentIP) == 0 {
return "", fmt.Errorf("IP lease not found for MAC address %s in: %s\n", mac, d.dhcp_lease_file) return "", fmt.Errorf("IP lease not found for MAC address %s in: %s\n", mac, d.dhcpLeaseFile)
} }
log.Printf("Found IP lease: %s for MAC address %s\n", mostRecentIp, mac) log.Printf("Found IP lease: %s for MAC address %s\n", mostRecentIP, mac)
return mostRecentIp, nil return mostRecentIP, nil
} }
func (d *Parallels9Driver) ToolsIsoPath(k string) (string, error) { // ToolsISOPath returns a full path to the Parallels Tools ISO for the specified guest
// OS type. The following OS types are supported: "win", "lin", "mac", "other".
func (d *Parallels9Driver) ToolsISOPath(k string) (string, error) {
appPath, err := getAppPath("com.parallels.desktop.console") appPath, err := getAppPath("com.parallels.desktop.console")
if err != nil { if err != nil {
return "", err return "", err

View File

@ -10,7 +10,7 @@ func TestParallels9Driver_impl(t *testing.T) {
var _ Driver = new(Parallels9Driver) var _ Driver = new(Parallels9Driver)
} }
func TestIpAddress(t *testing.T) { func TestIPAddress(t *testing.T) {
tf, err := ioutil.TempFile("", "packer") tf, err := ioutil.TempFile("", "packer")
if err != nil { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
@ -18,11 +18,11 @@ func TestIpAddress(t *testing.T) {
defer os.Remove(tf.Name()) defer os.Remove(tf.Name())
d := Parallels9Driver{ d := Parallels9Driver{
dhcp_lease_file: tf.Name(), dhcpLeaseFile: tf.Name(),
} }
// No lease should be found in an empty file // No lease should be found in an empty file
ip, err := d.IpAddress("123456789012") ip, err := d.IPAddress("123456789012")
if err == nil { if err == nil {
t.Fatalf("Found IP: \"%v\". No IP should be found!\n", ip) t.Fatalf("Found IP: \"%v\". No IP should be found!\n", ip)
} }
@ -35,7 +35,7 @@ func TestIpAddress(t *testing.T) {
10.211.55.254="1411712008,1800,001c42a51419,01001c42a51419" 10.211.55.254="1411712008,1800,001c42a51419,01001c42a51419"
`) `)
ioutil.WriteFile(tf.Name(), c, 0666) ioutil.WriteFile(tf.Name(), c, 0666)
ip, err = d.IpAddress("001C4235240c") ip, err = d.IPAddress("001C4235240c")
if err != nil { if err != nil {
t.Fatalf("Error: %v\n", err) t.Fatalf("Error: %v\n", err)
} }
@ -50,7 +50,7 @@ func TestIpAddress(t *testing.T) {
10.211.55.254="1411712008,1800,001c42a51419,01001c42a51419" 10.211.55.254="1411712008,1800,001c42a51419,01001c42a51419"
`) `)
ioutil.WriteFile(tf.Name(), c, 0666) ioutil.WriteFile(tf.Name(), c, 0666)
ip, err = d.IpAddress("001c4235240c") ip, err = d.IPAddress("001c4235240c")
if err != nil { if err != nil {
t.Fatalf("Error: %v\n", err) t.Fatalf("Error: %v\n", err)
} }

View File

@ -9,11 +9,11 @@ type DriverMock struct {
CompactDiskPath string CompactDiskPath string
CompactDiskErr error CompactDiskErr error
DeviceAddCdRomCalled bool DeviceAddCDROMCalled bool
DeviceAddCdRomName string DeviceAddCDROMName string
DeviceAddCdRomImage string DeviceAddCDROMImage string
DeviceAddCdRomResult string DeviceAddCDROMResult string
DeviceAddCdRomErr error DeviceAddCDROMErr error
DiskPathCalled bool DiskPathCalled bool
DiskPathName string DiskPathName string
@ -49,18 +49,18 @@ type DriverMock struct {
SetDefaultConfigurationCalled bool SetDefaultConfigurationCalled bool
SetDefaultConfigurationError error SetDefaultConfigurationError error
ToolsIsoPathCalled bool ToolsISOPathCalled bool
ToolsIsoPathFlavor string ToolsISOPathFlavor string
ToolsIsoPathResult string ToolsISOPathResult string
ToolsIsoPathErr error ToolsISOPathErr error
MacName string MACName string
MacReturn string MACReturn string
MacError error MACError error
IpAddressMac string IPAddressMAC string
IpAddressReturn string IPAddressReturn string
IpAddressError error IPAddressError error
} }
func (d *DriverMock) CompactDisk(path string) error { func (d *DriverMock) CompactDisk(path string) error {
@ -69,11 +69,11 @@ func (d *DriverMock) CompactDisk(path string) error {
return d.CompactDiskErr return d.CompactDiskErr
} }
func (d *DriverMock) DeviceAddCdRom(name string, image string) (string, error) { func (d *DriverMock) DeviceAddCDROM(name string, image string) (string, error) {
d.DeviceAddCdRomCalled = true d.DeviceAddCDROMCalled = true
d.DeviceAddCdRomName = name d.DeviceAddCDROMName = name
d.DeviceAddCdRomImage = image d.DeviceAddCDROMImage = image
return d.DeviceAddCdRomResult, d.DeviceAddCdRomErr return d.DeviceAddCDROMResult, d.DeviceAddCDROMErr
} }
func (d *DriverMock) DiskPath(name string) (string, error) { func (d *DriverMock) DiskPath(name string) (string, error) {
@ -82,7 +82,7 @@ func (d *DriverMock) DiskPath(name string) (string, error) {
return d.DiskPathResult, d.DiskPathErr return d.DiskPathResult, d.DiskPathErr
} }
func (d *DriverMock) Import(name, srcPath, dstPath string, reassignMac bool) error { func (d *DriverMock) Import(name, srcPath, dstPath string, reassignMAC bool) error {
d.ImportCalled = true d.ImportCalled = true
d.ImportName = name d.ImportName = name
d.ImportSrcPath = srcPath d.ImportSrcPath = srcPath
@ -136,18 +136,18 @@ func (d *DriverMock) SetDefaultConfiguration(name string) error {
return d.SetDefaultConfigurationError return d.SetDefaultConfigurationError
} }
func (d *DriverMock) Mac(name string) (string, error) { func (d *DriverMock) MAC(name string) (string, error) {
d.MacName = name d.MACName = name
return d.MacReturn, d.MacError return d.MACReturn, d.MACError
} }
func (d *DriverMock) IpAddress(mac string) (string, error) { func (d *DriverMock) IPAddress(mac string) (string, error) {
d.IpAddressMac = mac d.IPAddressMAC = mac
return d.IpAddressReturn, d.IpAddressError return d.IPAddressReturn, d.IPAddressError
} }
func (d *DriverMock) ToolsIsoPath(flavor string) (string, error) { func (d *DriverMock) ToolsISOPath(flavor string) (string, error) {
d.ToolsIsoPathCalled = true d.ToolsISOPathCalled = true
d.ToolsIsoPathFlavor = flavor d.ToolsISOPathFlavor = flavor
return d.ToolsIsoPathResult, d.ToolsIsoPathErr return d.ToolsISOPathResult, d.ToolsISOPathErr
} }

View File

@ -1,6 +1,6 @@
package common package common
// Interface to help find the host IP that is available from within // HostIPFinder allows to find the host IP that is available from within
// the Parallels virtual machines. // the Parallels virtual machines.
type HostIPFinder interface { type HostIPFinder interface {
HostIP() (string, error) HostIP() (string, error)

View File

@ -13,6 +13,8 @@ type IfconfigIPFinder struct {
Devices []string Devices []string
} }
// HostIP returns the host's IP address or an error if it could not be found
// from the `ifconfig` output.
func (f *IfconfigIPFinder) HostIP() (string, error) { func (f *IfconfigIPFinder) HostIP() (string, error) {
var ifconfigPath string var ifconfigPath string
@ -50,5 +52,5 @@ func (f *IfconfigIPFinder) HostIP() (string, error) {
} }
} }
} }
return "", errors.New("IP not found in ifconfig output...") return "", errors.New("IP not found in ifconfig output")
} }

View File

@ -9,10 +9,12 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
// OutputConfig contains the configuration for builder's output.
type OutputConfig struct { type OutputConfig struct {
OutputDir string `mapstructure:"output_directory"` OutputDir string `mapstructure:"output_directory"`
} }
// Prepare configures the output directory or returns an error if it already exists.
func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error {
if c.OutputDir == "" { if c.OutputDir == "" {
c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName) c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName)

View File

@ -1,10 +1,11 @@
package common package common
import ( import (
"github.com/mitchellh/packer/common"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"github.com/mitchellh/packer/common"
) )
func TestOutputConfigPrepare(t *testing.T) { func TestOutputConfigPrepare(t *testing.T) {

View File

@ -4,10 +4,13 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
// PrlctlConfig contains the configuration for running "prlctl" commands
// before the VM start.
type PrlctlConfig struct { type PrlctlConfig struct {
Prlctl [][]string `mapstructure:"prlctl"` Prlctl [][]string `mapstructure:"prlctl"`
} }
// Prepare sets the default value of "Prlctl" property.
func (c *PrlctlConfig) Prepare(ctx *interpolate.Context) []error { func (c *PrlctlConfig) Prepare(ctx *interpolate.Context) []error {
if c.Prlctl == nil { if c.Prlctl == nil {
c.Prlctl = make([][]string, 0) c.Prlctl = make([][]string, 0)

View File

@ -4,10 +4,13 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
// PrlctlPostConfig contains the configuration for running "prlctl" commands
// in the end of artifact build.
type PrlctlPostConfig struct { type PrlctlPostConfig struct {
PrlctlPost [][]string `mapstructure:"prlctl_post"` PrlctlPost [][]string `mapstructure:"prlctl_post"`
} }
// Prepare sets the default value of "PrlctlPost" property.
func (c *PrlctlPostConfig) Prepare(ctx *interpolate.Context) []error { func (c *PrlctlPostConfig) Prepare(ctx *interpolate.Context) []error {
if c.PrlctlPost == nil { if c.PrlctlPost == nil {
c.PrlctlPost = make([][]string, 0) c.PrlctlPost = make([][]string, 0)

View File

@ -4,10 +4,12 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
// PrlctlVersionConfig contains the configuration for `prlctl` version.
type PrlctlVersionConfig struct { type PrlctlVersionConfig struct {
PrlctlVersionFile string `mapstructure:"prlctl_version_file"` PrlctlVersionFile string `mapstructure:"prlctl_version_file"`
} }
// Prepare sets the default value of "PrlctlVersionFile" property.
func (c *PrlctlVersionConfig) Prepare(ctx *interpolate.Context) []error { func (c *PrlctlVersionConfig) Prepare(ctx *interpolate.Context) []error {
if c.PrlctlVersionFile == "" { if c.PrlctlVersionFile == "" {
c.PrlctlVersionFile = ".prlctl_version" c.PrlctlVersionFile = ".prlctl_version"

View File

@ -1,5 +1,7 @@
package common package common
// Prltype is a Python scrypt allowin to send scancodes to the VM. It requires
// the module "prlsdkapi", which is bundled to Parallels Virtualization SDK.
const Prltype string = ` const Prltype string = `
import sys import sys
import prlsdkapi import prlsdkapi

View File

@ -7,12 +7,14 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
// RunConfig contains the configuration for VM run.
type RunConfig struct { type RunConfig struct {
RawBootWait string `mapstructure:"boot_wait"` RawBootWait string `mapstructure:"boot_wait"`
BootWait time.Duration `` BootWait time.Duration ``
} }
// Prepare sets the configuration for VM run.
func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
if c.RawBootWait == "" { if c.RawBootWait == "" {
c.RawBootWait = "10s" c.RawBootWait = "10s"

View File

@ -7,6 +7,7 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
// ShutdownConfig contains the configuration for VM shutdown.
type ShutdownConfig struct { type ShutdownConfig struct {
ShutdownCommand string `mapstructure:"shutdown_command"` ShutdownCommand string `mapstructure:"shutdown_command"`
RawShutdownTimeout string `mapstructure:"shutdown_timeout"` RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
@ -14,6 +15,7 @@ type ShutdownConfig struct {
ShutdownTimeout time.Duration `` ShutdownTimeout time.Duration ``
} }
// Prepare sets default values to the VM shutdown configuration.
func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error { func (c *ShutdownConfig) Prepare(ctx *interpolate.Context) []error {
if c.RawShutdownTimeout == "" { if c.RawShutdownTimeout == "" {
c.RawShutdownTimeout = "5m" c.RawShutdownTimeout = "5m"

View File

@ -7,16 +7,17 @@ import (
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
// CommHost returns the VM's IP address which should be used to access it by SSH.
func CommHost(state multistep.StateBag) (string, error) { func CommHost(state multistep.StateBag) (string, error) {
vmName := state.Get("vmName").(string) vmName := state.Get("vmName").(string)
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
mac, err := driver.Mac(vmName) mac, err := driver.MAC(vmName)
if err != nil { if err != nil {
return "", err return "", err
} }
ip, err := driver.IpAddress(mac) ip, err := driver.IPAddress(mac)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -24,6 +25,7 @@ func CommHost(state multistep.StateBag) (string, error) {
return ip, nil return ip, nil
} }
// SSHConfigFunc returns SSH credentials to access the VM by SSH.
func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*ssh.ClientConfig, error) { func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*ssh.ClientConfig, error) {
return func(state multistep.StateBag) (*ssh.ClientConfig, error) { return func(state multistep.StateBag) (*ssh.ClientConfig, error) {
auth := []ssh.AuthMethod{ auth := []ssh.AuthMethod{

View File

@ -7,6 +7,7 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
// SSHConfig contains the configuration for SSH communicator.
type SSHConfig struct { type SSHConfig struct {
Comm communicator.Config `mapstructure:",squash"` Comm communicator.Config `mapstructure:",squash"`
@ -15,6 +16,7 @@ type SSHConfig struct {
SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout"` SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout"`
} }
// Prepare sets the default values for SSH communicator properties.
func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error { func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error {
// TODO: backwards compatibility, write fixer instead // TODO: backwards compatibility, write fixer instead
if c.SSHWaitTimeout != 0 { if c.SSHWaitTimeout != 0 {

View File

@ -2,12 +2,13 @@ package common
import ( import (
"fmt" "fmt"
"log"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
) )
// This step attaches a floppy to the virtual machine. // StepAttachFloppy is a step that attaches a floppy to the virtual machine.
// //
// Uses: // Uses:
// driver Driver // driver Driver
@ -19,6 +20,8 @@ type StepAttachFloppy struct {
floppyPath string floppyPath string
} }
// Run adds a virtual FDD device to the VM and attaches the image.
// If the image is not specified, then this step will be skipped.
func (s *StepAttachFloppy) Run(state multistep.StateBag) multistep.StepAction { func (s *StepAttachFloppy) Run(state multistep.StateBag) multistep.StepAction {
// Determine if we even have a floppy disk to attach // Determine if we even have a floppy disk to attach
var floppyPath string var floppyPath string
@ -35,22 +38,22 @@ func (s *StepAttachFloppy) Run(state multistep.StateBag) multistep.StepAction {
ui.Say("Deleting any current floppy disk...") ui.Say("Deleting any current floppy disk...")
// Delete the floppy disk controller // Delete the floppy disk controller
del_command := []string{ delCommand := []string{
"set", vmName, "set", vmName,
"--device-del", "fdd0", "--device-del", "fdd0",
} }
// This will almost certainly fail with 'The fdd0 device does not exist.' // This will almost certainly fail with 'The fdd0 device does not exist.'
driver.Prlctl(del_command...) driver.Prlctl(delCommand...)
ui.Say("Attaching floppy disk...") ui.Say("Attaching floppy disk...")
// Attaching the floppy disk // Attaching the floppy disk
add_command := []string{ addCommand := []string{
"set", vmName, "set", vmName,
"--device-add", "fdd", "--device-add", "fdd",
"--image", floppyPath, "--image", floppyPath,
"--connect", "--connect",
} }
if err := driver.Prlctl(add_command...); err != nil { if err := driver.Prlctl(addCommand...); err != nil {
state.Put("error", fmt.Errorf("Error adding floppy: %s", err)) state.Put("error", fmt.Errorf("Error adding floppy: %s", err))
return multistep.ActionHalt return multistep.ActionHalt
} }
@ -61,6 +64,7 @@ func (s *StepAttachFloppy) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup removes the virtual FDD device attached to the VM.
func (s *StepAttachFloppy) Cleanup(state multistep.StateBag) { func (s *StepAttachFloppy) Cleanup(state multistep.StateBag) {
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
vmName := state.Get("vmName").(string) vmName := state.Get("vmName").(string)

View File

@ -1,10 +1,11 @@
package common package common
import ( import (
"github.com/mitchellh/multistep"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"github.com/mitchellh/multistep"
) )
func TestStepAttachFloppy_impl(t *testing.T) { func TestStepAttachFloppy_impl(t *testing.T) {

View File

@ -2,13 +2,14 @@ package common
import ( import (
"fmt" "fmt"
"log"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
) )
// This step attaches the Parallels Tools as an inserted CD onto // StepAttachParallelsTools is a step that attaches Parallels Tools ISO image
// the virtual machine. // as an inserted CD onto the virtual machine.
// //
// Uses: // Uses:
// driver Driver // driver Driver
@ -22,6 +23,8 @@ type StepAttachParallelsTools struct {
ParallelsToolsMode string ParallelsToolsMode string
} }
// Run adds a virtual CD-ROM device to the VM and attaches Parallels Tools ISO image.
// If ISO image is not specified, then this step will be skipped.
func (s *StepAttachParallelsTools) Run(state multistep.StateBag) multistep.StepAction { func (s *StepAttachParallelsTools) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
@ -39,10 +42,10 @@ func (s *StepAttachParallelsTools) Run(state multistep.StateBag) multistep.StepA
// Attach the guest additions to the computer // Attach the guest additions to the computer
ui.Say("Attaching Parallels Tools ISO to the new CD/DVD drive...") ui.Say("Attaching Parallels Tools ISO to the new CD/DVD drive...")
cdrom, err := driver.DeviceAddCdRom(vmName, parallelsToolsPath) cdrom, err := driver.DeviceAddCDROM(vmName, parallelsToolsPath)
if err != nil { if err != nil {
err := fmt.Errorf("Error attaching Parallels Tools ISO: %s", err) err = fmt.Errorf("Error attaching Parallels Tools ISO: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -54,6 +57,7 @@ func (s *StepAttachParallelsTools) Run(state multistep.StateBag) multistep.StepA
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup removes the virtual CD-ROM device attached to the VM.
func (s *StepAttachParallelsTools) Cleanup(state multistep.StateBag) { func (s *StepAttachParallelsTools) Cleanup(state multistep.StateBag) {
if s.cdromDevice == "" { if s.cdromDevice == "" {
return return

View File

@ -2,12 +2,13 @@ package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
) )
// This step removes all empty blocks from expanding Parallels virtual disks // StepCompactDisk is a step that removes all empty blocks from expanding
// and reduces the result disk size // Parallels virtual disks and reduces the result disk size
// //
// Uses: // Uses:
// driver Driver // driver Driver
@ -20,6 +21,7 @@ type StepCompactDisk struct {
Skip bool Skip bool
} }
// Run runs the compaction of the virtual disk attached to the VM.
func (s *StepCompactDisk) Run(state multistep.StateBag) multistep.StepAction { func (s *StepCompactDisk) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
vmName := state.Get("vmName").(string) vmName := state.Get("vmName").(string)
@ -33,7 +35,7 @@ func (s *StepCompactDisk) Run(state multistep.StateBag) multistep.StepAction {
ui.Say("Compacting the disk image") ui.Say("Compacting the disk image")
diskPath, err := driver.DiskPath(vmName) diskPath, err := driver.DiskPath(vmName)
if err != nil { if err != nil {
err := fmt.Errorf("Error detecting virtual disk path: %s", err) err = fmt.Errorf("Error detecting virtual disk path: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -48,4 +50,5 @@ func (s *StepCompactDisk) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup does nothing.
func (*StepCompactDisk) Cleanup(multistep.StateBag) {} func (*StepCompactDisk) Cleanup(multistep.StateBag) {}

View File

@ -20,6 +20,7 @@ type StepOutputDir struct {
success bool success bool
} }
// Run sets up the output directory.
func (s *StepOutputDir) Run(state multistep.StateBag) multistep.StepAction { func (s *StepOutputDir) Run(state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
@ -48,6 +49,7 @@ func (s *StepOutputDir) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup deletes the output directory.
func (s *StepOutputDir) Cleanup(state multistep.StateBag) { func (s *StepOutputDir) Cleanup(state multistep.StateBag) {
_, cancelled := state.GetOk(multistep.StateCancelled) _, cancelled := state.GetOk(multistep.StateCancelled)
_, halted := state.GetOk(multistep.StateHalted) _, halted := state.GetOk(multistep.StateHalted)

View File

@ -1,10 +1,11 @@
package common package common
import ( import (
"github.com/mitchellh/multistep"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"github.com/mitchellh/multistep"
) )
func testStepOutputDir(t *testing.T) *StepOutputDir { func testStepOutputDir(t *testing.T) *StepOutputDir {

View File

@ -2,11 +2,13 @@ package common
import ( import (
"fmt" "fmt"
"github.com/mitchellh/multistep"
"os" "os"
"github.com/mitchellh/multistep"
) )
// This step prepares parameters related to Parallels Tools. // StepPrepareParallelsTools is a step that prepares parameters related
// to Parallels Tools.
// //
// Uses: // Uses:
// driver Driver // driver Driver
@ -18,6 +20,7 @@ type StepPrepareParallelsTools struct {
ParallelsToolsMode string ParallelsToolsMode string
} }
// Run sets the value of "parallels_tools_path".
func (s *StepPrepareParallelsTools) Run(state multistep.StateBag) multistep.StepAction { func (s *StepPrepareParallelsTools) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
@ -25,7 +28,7 @@ func (s *StepPrepareParallelsTools) Run(state multistep.StateBag) multistep.Step
return multistep.ActionContinue return multistep.ActionContinue
} }
path, err := driver.ToolsIsoPath(s.ParallelsToolsFlavor) path, err := driver.ToolsISOPath(s.ParallelsToolsFlavor)
if err != nil { if err != nil {
state.Put("error", err) state.Put("error", err)
@ -44,4 +47,5 @@ func (s *StepPrepareParallelsTools) Run(state multistep.StateBag) multistep.Step
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup does nothing.
func (s *StepPrepareParallelsTools) Cleanup(multistep.StateBag) {} func (s *StepPrepareParallelsTools) Cleanup(multistep.StateBag) {}

View File

@ -29,7 +29,7 @@ func TestStepPrepareParallelsTools(t *testing.T) {
driver := state.Get("driver").(*DriverMock) driver := state.Get("driver").(*DriverMock)
// Mock results // Mock results
driver.ToolsIsoPathResult = tf.Name() driver.ToolsISOPathResult = tf.Name()
// Test the run // Test the run
if action := step.Run(state); action != multistep.ActionContinue { if action := step.Run(state); action != multistep.ActionContinue {
@ -40,11 +40,11 @@ func TestStepPrepareParallelsTools(t *testing.T) {
} }
// Test the driver // Test the driver
if !driver.ToolsIsoPathCalled { if !driver.ToolsISOPathCalled {
t.Fatal("tools iso path should be called") t.Fatal("tools iso path should be called")
} }
if driver.ToolsIsoPathFlavor != "foo" { if driver.ToolsISOPathFlavor != "foo" {
t.Fatalf("bad: %#v", driver.ToolsIsoPathFlavor) t.Fatalf("bad: %#v", driver.ToolsISOPathFlavor)
} }
// Test the resulting state // Test the resulting state
@ -75,8 +75,8 @@ func TestStepPrepareParallelsTools_disabled(t *testing.T) {
} }
// Test the driver // Test the driver
if driver.ToolsIsoPathCalled { if driver.ToolsISOPathCalled {
t.Fatal("tools iso path should NOT be called") t.Fatal("tools ISO path should NOT be called")
} }
} }
@ -90,7 +90,7 @@ func TestStepPrepareParallelsTools_nonExist(t *testing.T) {
driver := state.Get("driver").(*DriverMock) driver := state.Get("driver").(*DriverMock)
// Mock results // Mock results
driver.ToolsIsoPathResult = "foo" driver.ToolsISOPathResult = "foo"
// Test the run // Test the run
if action := step.Run(state); action != multistep.ActionHalt { if action := step.Run(state); action != multistep.ActionHalt {
@ -101,11 +101,11 @@ func TestStepPrepareParallelsTools_nonExist(t *testing.T) {
} }
// Test the driver // Test the driver
if !driver.ToolsIsoPathCalled { if !driver.ToolsISOPathCalled {
t.Fatal("tools iso path should be called") t.Fatal("tools iso path should be called")
} }
if driver.ToolsIsoPathFlavor != "foo" { if driver.ToolsISOPathFlavor != "foo" {
t.Fatalf("bad: %#v", driver.ToolsIsoPathFlavor) t.Fatalf("bad: %#v", driver.ToolsISOPathFlavor)
} }
// Test the resulting state // Test the resulting state

View File

@ -13,8 +13,8 @@ type commandTemplate struct {
Name string Name string
} }
// This step executes additional prlctl commands as specified by the // StepPrlctl is a step that executes additional `prlctl` commands as specified.
// template. // by the template.
// //
// Uses: // Uses:
// driver Driver // driver Driver
@ -27,6 +27,7 @@ type StepPrlctl struct {
Ctx interpolate.Context Ctx interpolate.Context
} }
// Run executes `prlctl` commands.
func (s *StepPrlctl) Run(state multistep.StateBag) multistep.StepAction { func (s *StepPrlctl) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
@ -48,7 +49,7 @@ func (s *StepPrlctl) Run(state multistep.StateBag) multistep.StepAction {
var err error var err error
command[i], err = interpolate.Render(arg, &s.Ctx) command[i], err = interpolate.Render(arg, &s.Ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing prlctl command: %s", err) err = fmt.Errorf("Error preparing prlctl command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -57,7 +58,7 @@ func (s *StepPrlctl) Run(state multistep.StateBag) multistep.StepAction {
ui.Message(fmt.Sprintf("Executing: prlctl %s", strings.Join(command, " "))) ui.Message(fmt.Sprintf("Executing: prlctl %s", strings.Join(command, " ")))
if err := driver.Prlctl(command...); err != nil { if err := driver.Prlctl(command...); err != nil {
err := fmt.Errorf("Error executing command: %s", err) err = fmt.Errorf("Error executing command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -67,4 +68,5 @@ func (s *StepPrlctl) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup does nothing.
func (s *StepPrlctl) Cleanup(state multistep.StateBag) {} func (s *StepPrlctl) Cleanup(state multistep.StateBag) {}

View File

@ -2,12 +2,13 @@ package common
import ( import (
"fmt" "fmt"
"time"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"time"
) )
// This step starts the virtual machine. // StepRun is a step that starts the virtual machine.
// //
// Uses: // Uses:
// driver Driver // driver Driver
@ -21,6 +22,7 @@ type StepRun struct {
vmName string vmName string
} }
// Run starts the VM.
func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction { func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
@ -29,7 +31,7 @@ func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction {
ui.Say("Starting the virtual machine...") ui.Say("Starting the virtual machine...")
command := []string{"start", vmName} command := []string{"start", vmName}
if err := driver.Prlctl(command...); err != nil { if err := driver.Prlctl(command...); err != nil {
err := fmt.Errorf("Error starting VM: %s", err) err = fmt.Errorf("Error starting VM: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -56,6 +58,7 @@ func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup stops the VM.
func (s *StepRun) Cleanup(state multistep.StateBag) { func (s *StepRun) Cleanup(state multistep.StateBag) {
if s.vmName == "" { if s.vmName == "" {
return return

View File

@ -3,14 +3,15 @@ package common
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log" "log"
"time" "time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
) )
// This step shuts down the machine. It first attempts to do so gracefully, // StepShutdown is a step that shuts down the machine. It first attempts to do
// but ultimately forcefully shuts it down if that fails. // so gracefully, but ultimately forcefully shuts it down if that fails.
// //
// Uses: // Uses:
// communicator packer.Communicator // communicator packer.Communicator
@ -25,6 +26,7 @@ type StepShutdown struct {
Timeout time.Duration Timeout time.Duration
} }
// Run shuts down the VM.
func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction { func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
comm := state.Get("communicator").(packer.Communicator) comm := state.Get("communicator").(packer.Communicator)
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
@ -36,7 +38,7 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
log.Printf("Executing shutdown command: %s", s.Command) log.Printf("Executing shutdown command: %s", s.Command)
cmd := &packer.RemoteCmd{Command: s.Command} cmd := &packer.RemoteCmd{Command: s.Command}
if err := cmd.StartWithUi(comm, ui); err != nil { if err := cmd.StartWithUi(comm, ui); err != nil {
err := fmt.Errorf("Failed to send shutdown command: %s", err) err = fmt.Errorf("Failed to send shutdown command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -64,7 +66,7 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
} else { } else {
ui.Say("Halting the virtual machine...") ui.Say("Halting the virtual machine...")
if err := driver.Stop(vmName); err != nil { if err := driver.Stop(vmName); err != nil {
err := fmt.Errorf("Error stopping VM: %s", err) err = fmt.Errorf("Error stopping VM: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -75,4 +77,5 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup does nothing.
func (s *StepShutdown) Cleanup(state multistep.StateBag) {} func (s *StepShutdown) Cleanup(state multistep.StateBag) {}

View File

@ -1,10 +1,11 @@
package common package common
import ( import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"testing" "testing"
"time" "time"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
) )
func TestStepShutdown_impl(t *testing.T) { func TestStepShutdown_impl(t *testing.T) {

View File

@ -2,9 +2,10 @@ package common
import ( import (
"bytes" "bytes"
"testing"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"testing"
) )
func testState(t *testing.T) multistep.StateBag { func testState(t *testing.T) multistep.StateBag {

View File

@ -13,16 +13,14 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
const KeyLeftShift uint32 = 0xFFE1
type bootCommandTemplateData struct { type bootCommandTemplateData struct {
HTTPIP string HTTPIP string
HTTPPort uint HTTPPort uint
Name string Name string
} }
// This step "types" the boot command into the VM via the prltype script, built on the // StepTypeBootCommand is a step that "types" the boot command into the VM via
// Parallels Virtualization SDK - Python API. // the prltype script, built on the Parallels Virtualization SDK - Python API.
// //
// Uses: // Uses:
// driver Driver // driver Driver
@ -39,6 +37,7 @@ type StepTypeBootCommand struct {
Ctx interpolate.Context Ctx interpolate.Context
} }
// Run types the boot command by sending key scancodes into the VM.
func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction {
debug := state.Get("debug").(bool) debug := state.Get("debug").(bool)
httpPort := state.Get("http_port").(uint) httpPort := state.Get("http_port").(uint)
@ -50,7 +49,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
pauseFn = state.Get("pauseFn").(multistep.DebugPauseFn) pauseFn = state.Get("pauseFn").(multistep.DebugPauseFn)
} }
hostIp := "0.0.0.0" hostIP := "0.0.0.0"
if len(s.HostInterfaces) > 0 { if len(s.HostInterfaces) > 0 {
// Determine the host IP // Determine the host IP
@ -58,18 +57,18 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
ip, err := ipFinder.HostIP() ip, err := ipFinder.HostIP()
if err != nil { if err != nil {
err := fmt.Errorf("Error detecting host IP: %s", err) err = fmt.Errorf("Error detecting host IP: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
} }
hostIp = ip hostIP = ip
} }
ui.Say(fmt.Sprintf("Host IP for the Parallels machine: %s", hostIp)) ui.Say(fmt.Sprintf("Host IP for the Parallels machine: %s", hostIP))
s.Ctx.Data = &bootCommandTemplateData{ s.Ctx.Data = &bootCommandTemplateData{
hostIp, hostIP,
httpPort, httpPort,
s.VMName, s.VMName,
} }
@ -78,7 +77,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
for i, command := range s.BootCommand { for i, command := range s.BootCommand {
command, err := interpolate.Render(command, &s.Ctx) command, err := interpolate.Render(command, &s.Ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing boot command: %s", err) err = fmt.Errorf("Error preparing boot command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -88,7 +87,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
for _, code := range scancodes(command) { for _, code := range scancodes(command) {
if code == "wait" { if code == "wait" {
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil { if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
err := fmt.Errorf("Error sending boot command: %s", err) err = fmt.Errorf("Error sending boot command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -100,7 +99,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
if code == "wait5" { if code == "wait5" {
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil { if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
err := fmt.Errorf("Error sending boot command: %s", err) err = fmt.Errorf("Error sending boot command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -112,7 +111,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
if code == "wait10" { if code == "wait10" {
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil { if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
err := fmt.Errorf("Error sending boot command: %s", err) err = fmt.Errorf("Error sending boot command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -136,7 +135,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
log.Printf("Sending scancodes: %#v", codes) log.Printf("Sending scancodes: %#v", codes)
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil { if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
err := fmt.Errorf("Error sending boot command: %s", err) err = fmt.Errorf("Error sending boot command: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -146,6 +145,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup does nothing.
func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {} func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {}
func scancodes(message string) []string { func scancodes(message string) []string {
@ -208,12 +208,12 @@ func scancodes(message string) []string {
scancodeMap := make(map[rune]uint) scancodeMap := make(map[rune]uint)
for chars, start := range scancodeIndex { for chars, start := range scancodeIndex {
var i uint = 0 var i uint
for len(chars) > 0 { for len(chars) > 0 {
r, size := utf8.DecodeRuneInString(chars) r, size := utf8.DecodeRuneInString(chars)
chars = chars[size:] chars = chars[size:]
scancodeMap[r] = start + i scancodeMap[r] = start + i
i += 1 i++
} }
} }

View File

@ -1,10 +1,11 @@
package common package common
import ( import (
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"strings" "strings"
"testing" "testing"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
) )
func TestStepTypeBootCommand(t *testing.T) { func TestStepTypeBootCommand(t *testing.T) {

View File

@ -22,7 +22,13 @@ type toolsPathTemplate struct {
Flavor string Flavor string
} }
// This step uploads the guest additions ISO to the VM. // StepUploadParallelsTools is a step that uploads the Parallels Tools ISO
// to the VM.
//
// Uses:
// communicator packer.Communicator
// parallels_tools_path string
// ui packer.Ui
type StepUploadParallelsTools struct { type StepUploadParallelsTools struct {
ParallelsToolsFlavor string ParallelsToolsFlavor string
ParallelsToolsGuestPath string ParallelsToolsGuestPath string
@ -30,6 +36,7 @@ type StepUploadParallelsTools struct {
Ctx interpolate.Context Ctx interpolate.Context
} }
// Run uploads the Parallels Tools ISO to the VM.
func (s *StepUploadParallelsTools) Run(state multistep.StateBag) multistep.StepAction { func (s *StepUploadParallelsTools) Run(state multistep.StateBag) multistep.StepAction {
comm := state.Get("communicator").(packer.Communicator) comm := state.Get("communicator").(packer.Communicator)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
@ -56,7 +63,7 @@ func (s *StepUploadParallelsTools) Run(state multistep.StateBag) multistep.StepA
s.ParallelsToolsGuestPath, err = interpolate.Render(s.ParallelsToolsGuestPath, &s.Ctx) s.ParallelsToolsGuestPath, err = interpolate.Render(s.ParallelsToolsGuestPath, &s.Ctx)
if err != nil { if err != nil {
err := fmt.Errorf("Error preparing Parallels Tools path: %s", err) err = fmt.Errorf("Error preparing Parallels Tools path: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -65,7 +72,7 @@ func (s *StepUploadParallelsTools) Run(state multistep.StateBag) multistep.StepA
ui.Say(fmt.Sprintf("Uploading Parallels Tools for '%s' to path: '%s'", ui.Say(fmt.Sprintf("Uploading Parallels Tools for '%s' to path: '%s'",
s.ParallelsToolsFlavor, s.ParallelsToolsGuestPath)) s.ParallelsToolsFlavor, s.ParallelsToolsGuestPath))
if err := comm.Upload(s.ParallelsToolsGuestPath, f, nil); err != nil { if err := comm.Upload(s.ParallelsToolsGuestPath, f, nil); err != nil {
err := fmt.Errorf("Error uploading Parallels Tools: %s", err) err = fmt.Errorf("Error uploading Parallels Tools: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
@ -74,4 +81,5 @@ func (s *StepUploadParallelsTools) Run(state multistep.StateBag) multistep.StepA
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup does nothing.
func (s *StepUploadParallelsTools) Cleanup(state multistep.StateBag) {} func (s *StepUploadParallelsTools) Cleanup(state multistep.StateBag) {}

View File

@ -1,9 +1,10 @@
package common package common
import ( import (
"testing"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"testing"
) )
func TestStepUploadParallelsTools_impl(t *testing.T) { func TestStepUploadParallelsTools_impl(t *testing.T) {

View File

@ -3,17 +3,24 @@ package common
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"log"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
) )
// This step uploads a file containing the Parallels version, which // StepUploadVersion is a step that uploads a file containing the version of
// can be useful for various provisioning reasons. // Parallels Desktop, which can be useful for various provisioning reasons.
//
// Uses:
// communicator packer.Communicator
// driver Driver
// ui packer.Ui
type StepUploadVersion struct { type StepUploadVersion struct {
Path string Path string
} }
// Run uploads a file containing the version of Parallels Desktop.
func (s *StepUploadVersion) Run(state multistep.StateBag) multistep.StepAction { func (s *StepUploadVersion) Run(state multistep.StateBag) multistep.StepAction {
comm := state.Get("communicator").(packer.Communicator) comm := state.Get("communicator").(packer.Communicator)
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
@ -41,4 +48,5 @@ func (s *StepUploadVersion) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue return multistep.ActionContinue
} }
// Cleanup does nothing.
func (s *StepUploadVersion) Cleanup(state multistep.StateBag) {} func (s *StepUploadVersion) Cleanup(state multistep.StateBag) {}

View File

@ -1,9 +1,10 @@
package common package common
import ( import (
"testing"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"testing"
) )
func TestStepUploadVersion_impl(t *testing.T) { func TestStepUploadVersion_impl(t *testing.T) {

View File

@ -15,12 +15,14 @@ const (
ParallelsToolsModeUpload = "upload" ParallelsToolsModeUpload = "upload"
) )
// ToolsConfig contains the builder configuration related to Parallels Tools.
type ToolsConfig struct { type ToolsConfig struct {
ParallelsToolsFlavor string `mapstructure:"parallels_tools_flavor"` ParallelsToolsFlavor string `mapstructure:"parallels_tools_flavor"`
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"` ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"`
ParallelsToolsMode string `mapstructure:"parallels_tools_mode"` ParallelsToolsMode string `mapstructure:"parallels_tools_mode"`
} }
// Prepare validates & sets up configuration options related to Parallels Tools.
func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []error { func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []error {
if c.ParallelsToolsMode == "" { if c.ParallelsToolsMode == "" {
c.ParallelsToolsMode = ParallelsToolsModeUpload c.ParallelsToolsMode = ParallelsToolsModeUpload
@ -53,7 +55,7 @@ func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []error {
if c.ParallelsToolsFlavor == "" { if c.ParallelsToolsFlavor == "" {
if c.ParallelsToolsMode != ParallelsToolsModeDisable { if c.ParallelsToolsMode != ParallelsToolsModeDisable {
errs = append(errs, errors.New("parallels_tools_flavor must be specified.")) errs = append(errs, errors.New("parallels_tools_flavor must be specified"))
} }
} }

View File

@ -2,17 +2,18 @@ package iso
import ( import (
"fmt" "fmt"
"log"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
parallelscommon "github.com/mitchellh/packer/builder/parallels/common" parallelscommon "github.com/mitchellh/packer/builder/parallels/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
) )
// This step attaches the ISO to the virtual machine. // This step attaches the ISO to the virtual machine.
// //
// Uses: // Uses:
// driver Driver // driver Driver
// isoPath string // iso_path string
// ui packer.Ui // ui packer.Ui
// vmName string // vmName string
// //

View File

@ -2,10 +2,11 @@ package iso
import ( import (
"fmt" "fmt"
"strconv"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
parallelscommon "github.com/mitchellh/packer/builder/parallels/common" parallelscommon "github.com/mitchellh/packer/builder/parallels/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"strconv"
) )
// This step creates the virtual disk that will be used as the // This step creates the virtual disk that will be used as the

View File

@ -2,6 +2,7 @@ package iso
import ( import (
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
parallelscommon "github.com/mitchellh/packer/builder/parallels/common" parallelscommon "github.com/mitchellh/packer/builder/parallels/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"

View File

@ -27,7 +27,7 @@ type Config struct {
BootCommand []string `mapstructure:"boot_command"` BootCommand []string `mapstructure:"boot_command"`
SourcePath string `mapstructure:"source_path"` SourcePath string `mapstructure:"source_path"`
VMName string `mapstructure:"vm_name"` VMName string `mapstructure:"vm_name"`
ReassignMac bool `mapstructure:"reassign_mac"` ReassignMAC bool `mapstructure:"reassign_mac"`
ctx interpolate.Context ctx interpolate.Context
} }

View File

@ -2,6 +2,7 @@ package pvm
import ( import (
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
parallelscommon "github.com/mitchellh/packer/builder/parallels/common" parallelscommon "github.com/mitchellh/packer/builder/parallels/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
@ -20,7 +21,7 @@ func (s *StepImport) Run(state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config) config := state.Get("config").(*Config)
ui.Say(fmt.Sprintf("Importing VM: %s", s.SourcePath)) ui.Say(fmt.Sprintf("Importing VM: %s", s.SourcePath))
if err := driver.Import(s.Name, s.SourcePath, config.OutputDir, config.ReassignMac); err != nil { if err := driver.Import(s.Name, s.SourcePath, config.OutputDir, config.ReassignMAC); err != nil {
err := fmt.Errorf("Error importing VM: %s", err) err := fmt.Errorf("Error importing VM: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())

View File

@ -2,10 +2,11 @@ package pvm
import ( import (
"bytes" "bytes"
"testing"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
parallelscommon "github.com/mitchellh/packer/builder/parallels/common" parallelscommon "github.com/mitchellh/packer/builder/parallels/common"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"testing"
) )
func testState(t *testing.T) multistep.StateBag { func testState(t *testing.T) multistep.StateBag {