builder/parallels: Added 'ToolsConfig' struct

This commit is contained in:
Mikhail Zholobov 2014-09-02 11:53:21 +04:00
parent 909d5ccb54
commit 13b355eaf0
6 changed files with 261 additions and 234 deletions

View File

@ -0,0 +1,78 @@
package common
import (
"errors"
"fmt"
"github.com/mitchellh/packer/packer"
"text/template"
)
// These are the different valid mode values for "parallels_tools_mode" which
// determine how guest additions are delivered to the guest.
const (
ParallelsToolsModeDisable string = "disable"
ParallelsToolsModeAttach = "attach"
ParallelsToolsModeUpload = "upload"
)
type ToolsConfig struct {
ParallelsToolsFlavor string `mapstructure:"parallels_tools_flavor"`
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"`
ParallelsToolsMode string `mapstructure:"parallels_tools_mode"`
}
func (c *ToolsConfig) Prepare(t *packer.ConfigTemplate) []error {
if c.ParallelsToolsMode == "" {
c.ParallelsToolsMode = ParallelsToolsModeUpload
}
if c.ParallelsToolsGuestPath == "" {
c.ParallelsToolsGuestPath = "prl-tools-{{.Flavor}}.iso"
}
templates := map[string]*string{
"parallels_tools_flavor": &c.ParallelsToolsFlavor,
"parallels_tools_mode": &c.ParallelsToolsMode,
}
var err error
errs := make([]error, 0)
for n, ptr := range templates {
*ptr, err = t.Process(*ptr, nil)
if err != nil {
errs = append(errs, fmt.Errorf("Error processing %s: %s", n, err))
}
}
if _, err := template.New("path").Parse(c.ParallelsToolsGuestPath); err != nil {
errs = append(errs, fmt.Errorf("parallels_tools_guest_path invalid: %s", err))
}
validMode := false
validModes := []string{
ParallelsToolsModeDisable,
ParallelsToolsModeAttach,
ParallelsToolsModeUpload,
}
for _, mode := range validModes {
if c.ParallelsToolsMode == mode {
validMode = true
break
}
}
if !validMode {
errs = append(errs,
fmt.Errorf("parallels_tools_mode is invalid. Must be one of: %v",
validModes))
}
if c.ParallelsToolsFlavor == "" {
if c.ParallelsToolsMode != ParallelsToolsModeDisable {
errs = append(errs, errors.New("parallels_tools_flavor must be specified."))
}
}
return errs
}

View File

@ -0,0 +1,123 @@
package common
import (
"testing"
)
func testToolsConfig() *ToolsConfig {
return &ToolsConfig{
ParallelsToolsFlavor: "foo",
ParallelsToolsGuestPath: "foo",
ParallelsToolsMode: "attach",
}
}
func TestToolsConfigPrepare(t *testing.T) {
c := testToolsConfig()
errs := c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("bad err: %#v", errs)
}
}
func TestToolsConfigPrepare_ParallelsToolsMode(t *testing.T) {
var c *ToolsConfig
var errs []error
// Test default mode
c = testToolsConfig()
c.ParallelsToolsMode = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
if c.ParallelsToolsMode != ParallelsToolsModeUpload {
t.Errorf("bad parallels tools mode: %s", c.ParallelsToolsMode)
}
// Test another mode
c = testToolsConfig()
c.ParallelsToolsMode = "attach"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
if c.ParallelsToolsMode != ParallelsToolsModeAttach {
t.Fatalf("bad mode: %s", c.ParallelsToolsMode)
}
// Test invalid mode
c = testToolsConfig()
c.ParallelsToolsMode = "invalid_mode"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should have error")
}
}
func TestToolsConfigPrepare_ParallelsToolsGuestPath(t *testing.T) {
var c *ToolsConfig
var errs []error
// Test default path
c = testToolsConfig()
c.ParallelsToolsGuestPath = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %#v", errs)
}
if c.ParallelsToolsGuestPath == "" {
t.Fatal("should not be empty")
}
// Test with a bad value
c = testToolsConfig()
c.ParallelsToolsGuestPath = "{{{nope}"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should have error")
}
// Test with a good one
c = testToolsConfig()
c.ParallelsToolsGuestPath = "foo"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %s", errs)
}
if c.ParallelsToolsGuestPath != "foo" {
t.Fatalf("bad guest path: %s", c.ParallelsToolsGuestPath)
}
}
func TestToolsConfigPrepare_ParallelsToolsFlavor(t *testing.T) {
var c *ToolsConfig
var errs []error
// Test with a default value
c = testToolsConfig()
c.ParallelsToolsFlavor = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should have error")
}
// Test with an bad value
c = testToolsConfig()
c.ParallelsToolsMode = "attach"
c.ParallelsToolsFlavor = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should have error")
}
// Test with a good one
c = testToolsConfig()
c.ParallelsToolsMode = "disable"
c.ParallelsToolsFlavor = ""
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("should not have error: %s", errs)
}
}

View File

@ -1,9 +0,0 @@
package common
// These are the different valid mode values for "parallels_tools_mode" which
// determine how guest additions are delivered to the guest.
const (
ParallelsToolsModeDisable string = "disable"
ParallelsToolsModeAttach = "attach"
ParallelsToolsModeUpload = "upload"
)

View File

@ -22,32 +22,31 @@ type config struct {
common.PackerConfig `mapstructure:",squash"`
parallelscommon.FloppyConfig `mapstructure:",squash"`
parallelscommon.OutputConfig `mapstructure:",squash"`
parallelscommon.PrlctlConfig `mapstructure:",squash"`
parallelscommon.PrlctlVersionConfig `mapstructure:",squash"`
parallelscommon.RunConfig `mapstructure:",squash"`
parallelscommon.ShutdownConfig `mapstructure:",squash"`
parallelscommon.SSHConfig `mapstructure:",squash"`
parallelscommon.PrlctlConfig `mapstructure:",squash"`
parallelscommon.PrlctlVersionConfig `mapstructure:",squash"`
parallelscommon.ToolsConfig `mapstructure:",squash"`
BootCommand []string `mapstructure:"boot_command"`
DiskSize uint `mapstructure:"disk_size"`
ParallelsToolsMode string `mapstructure:"parallels_tools_mode"`
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"`
ParallelsToolsHostPath string `mapstructure:"parallels_tools_host_path"`
GuestOSDistribution string `mapstructure:"guest_os_distribution"`
HardDriveInterface string `mapstructure:"hard_drive_interface"`
HostInterfaces []string `mapstructure:"host_interfaces"`
HTTPDir string `mapstructure:"http_directory"`
HTTPPortMin uint `mapstructure:"http_port_min"`
HTTPPortMax uint `mapstructure:"http_port_max"`
ISOChecksum string `mapstructure:"iso_checksum"`
ISOChecksumType string `mapstructure:"iso_checksum_type"`
ISOUrls []string `mapstructure:"iso_urls"`
VMName string `mapstructure:"vm_name"`
BootCommand []string `mapstructure:"boot_command"`
DiskSize uint `mapstructure:"disk_size"`
GuestOSDistribution string `mapstructure:"guest_os_distribution"`
HardDriveInterface string `mapstructure:"hard_drive_interface"`
HostInterfaces []string `mapstructure:"host_interfaces"`
HTTPDir string `mapstructure:"http_directory"`
HTTPPortMin uint `mapstructure:"http_port_min"`
HTTPPortMax uint `mapstructure:"http_port_max"`
ISOChecksum string `mapstructure:"iso_checksum"`
ISOChecksumType string `mapstructure:"iso_checksum_type"`
ISOUrls []string `mapstructure:"iso_urls"`
VMName string `mapstructure:"vm_name"`
RawSingleISOUrl string `mapstructure:"iso_url"`
// Deprecated parameters
GuestOSType string `mapstructure:"guest_os_type"`
GuestOSType string `mapstructure:"guest_os_type"`
ParallelsToolsHostPath string `mapstructure:"parallels_tools_host_path"`
tpl *packer.ConfigTemplate
}
@ -71,28 +70,17 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(
errs, b.config.OutputConfig.Prepare(b.config.tpl, &b.config.PackerConfig)...)
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.PrlctlConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.PrlctlVersionConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(b.config.tpl)...)
errs = packer.MultiErrorAppend(errs, b.config.ToolsConfig.Prepare(b.config.tpl)...)
warnings := make([]string, 0)
if b.config.DiskSize == 0 {
b.config.DiskSize = 40000
}
if b.config.ParallelsToolsMode == "" {
b.config.ParallelsToolsMode = "upload"
}
if b.config.ParallelsToolsGuestPath == "" {
b.config.ParallelsToolsGuestPath = "prl-tools.iso"
}
if b.config.ParallelsToolsHostPath == "" {
b.config.ParallelsToolsHostPath = "/Applications/Parallels Desktop.app/Contents/Resources/Tools/prl-tools-other.iso"
}
if b.config.HardDriveInterface == "" {
b.config.HardDriveInterface = "sata"
}
@ -120,16 +108,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
// Errors
templates := map[string]*string{
"parallels_tools_mode": &b.config.ParallelsToolsMode,
"parallels_tools_host_path": &b.config.ParallelsToolsHostPath,
"parallels_tools_guest_path": &b.config.ParallelsToolsGuestPath,
"guest_os_distribution": &b.config.GuestOSDistribution,
"hard_drive_interface": &b.config.HardDriveInterface,
"http_directory": &b.config.HTTPDir,
"iso_checksum": &b.config.ISOChecksum,
"iso_checksum_type": &b.config.ISOChecksumType,
"iso_url": &b.config.RawSingleISOUrl,
"vm_name": &b.config.VMName,
"guest_os_distribution": &b.config.GuestOSDistribution,
"hard_drive_interface": &b.config.HardDriveInterface,
"http_directory": &b.config.HTTPDir,
"iso_checksum": &b.config.ISOChecksum,
"iso_checksum_type": &b.config.ISOChecksumType,
"iso_url": &b.config.RawSingleISOUrl,
"vm_name": &b.config.VMName,
}
for n, ptr := range templates {
@ -150,17 +135,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}
}
validates := map[string]*string{
"parallels_tools_guest_path": &b.config.ParallelsToolsGuestPath,
}
for n, ptr := range validates {
if err := b.config.tpl.Validate(*ptr); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error parsing %s: %s", n, err))
}
}
for i, command := range b.config.BootCommand {
if err := b.config.tpl.Validate(command); err != nil {
errs = packer.MultiErrorAppend(errs,
@ -217,25 +191,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}
}
validMode := false
validModes := []string{
parallelscommon.ParallelsToolsModeDisable,
parallelscommon.ParallelsToolsModeAttach,
parallelscommon.ParallelsToolsModeUpload,
}
for _, mode := range validModes {
if b.config.ParallelsToolsMode == mode {
validMode = true
break
}
}
if !validMode {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("parallels_tools_mode is invalid. Must be one of: %v", validModes))
}
// Warnings
if b.config.ISOChecksumType == "none" {
warnings = append(warnings,
@ -249,6 +204,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
"will forcibly halt the virtual machine, which may result in data loss.")
}
if b.config.ParallelsToolsHostPath != "" {
warnings = append(warnings,
"A 'parallels_tools_host_path' has been deprecated and not in use anymore\n"+
"You can remove it from your Packer template.")
}
if errs != nil && len(errs.Errors) > 0 {
return warnings, errs
}

View File

@ -1,7 +1,6 @@
package iso
import (
"github.com/mitchellh/packer/builder/parallels/common"
"github.com/mitchellh/packer/packer"
"reflect"
"testing"
@ -38,10 +37,6 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
t.Fatalf("should not have error: %s", err)
}
if b.config.ParallelsToolsMode != common.ParallelsToolsModeUpload {
t.Errorf("bad parallels tools mode: %s", b.config.ParallelsToolsMode)
}
if b.config.GuestOSDistribution != "other" {
t.Errorf("bad guest OS distribution: %s", b.config.GuestOSDistribution)
}
@ -83,107 +78,6 @@ func TestBuilderPrepare_DiskSize(t *testing.T) {
}
}
func TestBuilderPrepare_ParallelsToolsMode(t *testing.T) {
var b Builder
config := testConfig()
// test default mode
delete(config, "parallels_tools_mode")
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad err: %s", err)
}
// Test another mode
config["parallels_tools_mode"] = "attach"
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.ParallelsToolsMode != common.ParallelsToolsModeAttach {
t.Fatalf("bad: %s", b.config.ParallelsToolsMode)
}
// Test bad mode
config["parllels_tools_mode"] = "teleport"
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should error")
}
}
func TestBuilderPrepare_ParallelsToolsGuestPath(t *testing.T) {
var b Builder
config := testConfig()
delete(config, "parallesl_tools_guest_path")
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad err: %s", err)
}
if b.config.ParallelsToolsGuestPath != "prl-tools.iso" {
t.Fatalf("bad: %s", b.config.ParallelsToolsGuestPath)
}
config["parallels_tools_guest_path"] = "foo"
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if b.config.ParallelsToolsGuestPath != "foo" {
t.Fatalf("bad size: %s", b.config.ParallelsToolsGuestPath)
}
}
func TestBuilderPrepare_ParallelsToolsHostPath(t *testing.T) {
var b Builder
config := testConfig()
config["parallels_tools_host_path"] = ""
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("err: %s", err)
}
if b.config.ParallelsToolsHostPath != "/Applications/Parallels Desktop.app/Contents/Resources/Tools/prl-tools-other.iso" {
t.Fatalf("bad: %s", b.config.ParallelsToolsHostPath)
}
config["parallels_tools_host_path"] = "./prl-tools-lin.iso"
b = Builder{}
warns, err = b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Errorf("should not have error: %s", err)
}
}
func TestBuilderPrepare_HardDriveInterface(t *testing.T) {
var b Builder
config := testConfig()
@ -434,3 +328,19 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
t.Fatalf("bad: %#v", b.config.ISOUrls)
}
}
func TestBuilderPrepare_ParallelsToolsHostPath(t *testing.T) {
var b Builder
config := testConfig()
delete(config, "parallels_tools_host_path")
// Test that it is deprecated
config["parallels_tools_host_path"] = "/path/to/iso"
warns, err := b.Prepare(config)
if len(warns) == 0 {
t.Fatalf("should have warning")
}
if err != nil {
t.Fatalf("should not have error: %s", err)
}
}

View File

@ -13,18 +13,16 @@ type Config struct {
common.PackerConfig `mapstructure:",squash"`
parallelscommon.FloppyConfig `mapstructure:",squash"`
parallelscommon.OutputConfig `mapstructure:",squash"`
parallelscommon.PrlctlConfig `mapstructure:",squash"`
parallelscommon.PrlctlVersionConfig `mapstructure:",squash"`
parallelscommon.RunConfig `mapstructure:",squash"`
parallelscommon.SSHConfig `mapstructure:",squash"`
parallelscommon.ShutdownConfig `mapstructure:",squash"`
parallelscommon.PrlctlConfig `mapstructure:",squash"`
parallelscommon.PrlctlVersionConfig `mapstructure:",squash"`
parallelscommon.ToolsConfig `mapstructure:",squash"`
BootCommand []string `mapstructure:"boot_command"`
ParallelsToolsMode string `mapstructure:"parallels_tools_mode"`
ParallelsToolsGuestPath string `mapstructure:"parallels_tools_guest_path"`
ParallelsToolsHostPath string `mapstructure:"parallels_tools_host_path"`
SourcePath string `mapstructure:"source_path"`
VMName string `mapstructure:"vm_name"`
BootCommand []string `mapstructure:"boot_command"`
SourcePath string `mapstructure:"source_path"`
VMName string `mapstructure:"vm_name"`
tpl *packer.ConfigTemplate
}
@ -42,19 +40,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}
c.tpl.UserVars = c.PackerUserVars
// Defaults
if c.ParallelsToolsMode == "" {
c.ParallelsToolsMode = "disable"
}
if c.ParallelsToolsGuestPath == "" {
c.ParallelsToolsGuestPath = "prl-tools.iso"
}
if c.ParallelsToolsHostPath == "" {
c.ParallelsToolsHostPath = "/Applications/Parallels Desktop.app/Contents/Resources/Tools/prl-tools-other.iso"
}
if c.VMName == "" {
c.VMName = fmt.Sprintf("packer-%s-{{timestamp}}", c.PackerBuildName)
}
@ -63,18 +48,16 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
errs := common.CheckUnusedConfig(md)
errs = packer.MultiErrorAppend(errs, c.FloppyConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.OutputConfig.Prepare(c.tpl, &c.PackerConfig)...)
errs = packer.MultiErrorAppend(errs, c.PrlctlConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.PrlctlVersionConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.RunConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.SSHConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.PrlctlConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.PrlctlVersionConfig.Prepare(c.tpl)...)
errs = packer.MultiErrorAppend(errs, c.ToolsConfig.Prepare(c.tpl)...)
templates := map[string]*string{
"parallels_tools_mode": &c.ParallelsToolsMode,
"parallels_tools_host_paht": &c.ParallelsToolsHostPath,
"parallels_tools_guest_path": &c.ParallelsToolsGuestPath,
"source_path": &c.SourcePath,
"vm_name": &c.VMName,
"source_path": &c.SourcePath,
"vm_name": &c.VMName,
}
for n, ptr := range templates {
@ -93,25 +76,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}
}
validMode := false
validModes := []string{
parallelscommon.ParallelsToolsModeDisable,
parallelscommon.ParallelsToolsModeAttach,
parallelscommon.ParallelsToolsModeUpload,
}
for _, mode := range validModes {
if c.ParallelsToolsMode == mode {
validMode = true
break
}
}
if !validMode {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("parallels_tools_mode is invalid. Must be one of: %v", validModes))
}
if c.SourcePath == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is required"))
} else {