Merge pull request #7019 from arizvisa/vmware.cpu-memory

Add configuration options to vmware builder to specify cpu count and memory size
This commit is contained in:
Adrien Delorme 2018-11-23 10:53:46 +01:00 committed by GitHub
commit e539133d8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 746 additions and 331 deletions

View File

@ -0,0 +1,290 @@
package common
import (
"fmt"
"path/filepath"
"runtime"
"strings"
"github.com/hashicorp/packer/template/interpolate"
)
type HWConfig struct {
// cpu information
CpuCount int `mapstructure:"cpus"`
MemorySize int `mapstructure:"memory"`
// network type and adapter
Network string `mapstructure:"network"`
NetworkAdapterType string `mapstructure:"network_adapter_type"`
// device presence
Sound bool `mapstructure:"sound"`
USB bool `mapstructure:"usb"`
// communication ports
Serial string `mapstructure:"serial"`
Parallel string `mapstructure:"parallel"`
}
func (c *HWConfig) Prepare(ctx *interpolate.Context) []error {
var errs []error
// Hardware and cpu options
if c.CpuCount < 0 {
errs = append(errs, fmt.Errorf("An invalid number of cpus was specified (cpus < 0): %d", c.CpuCount))
}
if c.MemorySize < 0 {
errs = append(errs, fmt.Errorf("An invalid amount of memory was specified (memory < 0): %d", c.MemorySize))
}
// Peripherals
if !c.Sound {
c.Sound = false
}
if !c.USB {
c.USB = false
}
if c.Parallel == "" {
c.Parallel = "none"
}
if c.Serial == "" {
c.Serial = "none"
}
return errs
}
/* parallel port */
type ParallelUnion struct {
Union interface{}
File *ParallelPortFile
Device *ParallelPortDevice
Auto *ParallelPortAuto
}
type ParallelPortFile struct {
Filename string
}
type ParallelPortDevice struct {
Bidirectional string
Devicename string
}
type ParallelPortAuto struct {
Bidirectional string
}
func (c *HWConfig) HasParallel() bool {
return c.Parallel != ""
}
func (c *HWConfig) ReadParallel() (*ParallelUnion, error) {
input := strings.SplitN(c.Parallel, ":", 2)
if len(input) < 1 {
return nil, fmt.Errorf("Unexpected format for parallel port: %s", c.Parallel)
}
var formatType, formatOptions string
formatType = input[0]
if len(input) == 2 {
formatOptions = input[1]
} else {
formatOptions = ""
}
switch strings.ToUpper(formatType) {
case "FILE":
res := &ParallelPortFile{Filename: filepath.FromSlash(formatOptions)}
return &ParallelUnion{Union: res, File: res}, nil
case "DEVICE":
comp := strings.Split(formatOptions, ",")
if len(comp) < 1 || len(comp) > 2 {
return nil, fmt.Errorf("Unexpected format for parallel port: %s", c.Parallel)
}
res := new(ParallelPortDevice)
res.Bidirectional = "FALSE"
res.Devicename = filepath.FromSlash(comp[0])
if len(comp) > 1 {
switch strings.ToUpper(comp[1]) {
case "BI":
res.Bidirectional = "TRUE"
case "UNI":
res.Bidirectional = "FALSE"
default:
return nil, fmt.Errorf("Unknown direction %s specified for parallel port: %s", strings.ToUpper(comp[1]), c.Parallel)
}
}
return &ParallelUnion{Union: res, Device: res}, nil
case "AUTO":
res := new(ParallelPortAuto)
switch strings.ToUpper(formatOptions) {
case "":
fallthrough
case "UNI":
res.Bidirectional = "FALSE"
case "BI":
res.Bidirectional = "TRUE"
default:
return nil, fmt.Errorf("Unknown direction %s specified for parallel port: %s", strings.ToUpper(formatOptions), c.Parallel)
}
return &ParallelUnion{Union: res, Auto: res}, nil
case "NONE":
return &ParallelUnion{Union: nil}, nil
}
return nil, fmt.Errorf("Unexpected format for parallel port: %s", c.Parallel)
}
/* serial conversions */
type SerialConfigPipe struct {
Filename string
Endpoint string
Host string
Yield string
}
type SerialConfigFile struct {
Filename string
Yield string
}
type SerialConfigDevice struct {
Devicename string
Yield string
}
type SerialConfigAuto struct {
Devicename string
Yield string
}
type SerialUnion struct {
Union interface{}
Pipe *SerialConfigPipe
File *SerialConfigFile
Device *SerialConfigDevice
Auto *SerialConfigAuto
}
func (c *HWConfig) HasSerial() bool {
return c.Serial != ""
}
func (c *HWConfig) ReadSerial() (*SerialUnion, error) {
var defaultSerialPort string
if runtime.GOOS == "windows" {
defaultSerialPort = "COM1"
} else {
defaultSerialPort = "/dev/ttyS0"
}
input := strings.SplitN(c.Serial, ":", 2)
if len(input) < 1 {
return nil, fmt.Errorf("Unexpected format for serial port: %s", c.Serial)
}
var formatType, formatOptions string
formatType = input[0]
if len(input) == 2 {
formatOptions = input[1]
} else {
formatOptions = ""
}
switch strings.ToUpper(formatType) {
case "PIPE":
comp := strings.Split(formatOptions, ",")
if len(comp) < 3 || len(comp) > 4 {
return nil, fmt.Errorf("Unexpected format for serial port pipe: %s", c.Serial)
}
if res := strings.ToLower(comp[1]); res != "client" && res != "server" {
return nil, fmt.Errorf("Unexpected format for endpoint in serial port pipe: %s -> %s", c.Serial, res)
}
if res := strings.ToLower(comp[2]); res != "app" && res != "vm" {
return nil, fmt.Errorf("Unexpected format for host in serial port pipe: %s -> %s", c.Serial, res)
}
res := &SerialConfigPipe{
Filename: comp[0],
Endpoint: comp[1],
Host: map[string]string{"app": "TRUE", "vm": "FALSE"}[strings.ToLower(comp[2])],
Yield: "FALSE",
}
if len(comp) == 4 {
res.Yield = strings.ToUpper(comp[3])
}
if res.Yield != "TRUE" && res.Yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for yield in serial port pipe: %s -> %s", c.Serial, res.Yield)
}
return &SerialUnion{Union: res, Pipe: res}, nil
case "FILE":
comp := strings.Split(formatOptions, ",")
if len(comp) > 2 {
return nil, fmt.Errorf("Unexpected format for serial port file: %s", c.Serial)
}
res := &SerialConfigFile{Yield: "FALSE"}
res.Filename = filepath.FromSlash(comp[0])
res.Yield = map[bool]string{true: strings.ToUpper(comp[1]), false: "FALSE"}[len(comp) > 1]
if res.Yield != "TRUE" && res.Yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for yield in serial port file: %s -> %s", c.Serial, res.Yield)
}
return &SerialUnion{Union: res, File: res}, nil
case "DEVICE":
comp := strings.Split(formatOptions, ",")
if len(comp) > 2 {
return nil, fmt.Errorf("Unexpected format for serial port device: %s", c.Serial)
}
res := new(SerialConfigDevice)
if len(comp) == 2 {
res.Devicename = map[bool]string{true: filepath.FromSlash(comp[0]), false: defaultSerialPort}[len(comp[0]) > 0]
res.Yield = strings.ToUpper(comp[1])
} else if len(comp) == 1 {
res.Devicename = map[bool]string{true: filepath.FromSlash(comp[0]), false: defaultSerialPort}[len(comp[0]) > 0]
res.Yield = "FALSE"
} else if len(comp) == 0 {
res.Devicename = defaultSerialPort
res.Yield = "FALSE"
}
if res.Yield != "TRUE" && res.Yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for yield in serial port device: %s -> %s", c.Serial, res.Yield)
}
return &SerialUnion{Union: res, Device: res}, nil
case "AUTO":
res := new(SerialConfigAuto)
res.Devicename = defaultSerialPort
if len(formatOptions) > 0 {
res.Yield = strings.ToUpper(formatOptions)
} else {
res.Yield = "FALSE"
}
if res.Yield != "TRUE" && res.Yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for yield in serial port auto: %s -> %s", c.Serial, res.Yield)
}
return &SerialUnion{Union: res, Auto: res}, nil
case "NONE":
return &SerialUnion{Union: nil}, nil
default:
return nil, fmt.Errorf("Unknown serial type %s: %s", strings.ToUpper(formatType), c.Serial)
}
}

View File

@ -0,0 +1,319 @@
package common
import (
"strings"
"testing"
)
func testHWConfig() *HWConfig {
return &HWConfig{
CpuCount: 1,
MemorySize: 512,
Sound: true,
USB: true,
}
}
func TestHWConfigPrepare(t *testing.T) {
c := new(HWConfig)
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if c.CpuCount < 0 {
t.Errorf("bad cpu count: %d", c.CpuCount)
}
if c.MemorySize < 0 {
t.Errorf("bad memory size: %d", c.MemorySize)
}
if c.Sound {
t.Errorf("peripheral choice (sound) should be conservative: %t", c.Sound)
}
if c.USB {
t.Errorf("peripheral choice (usb) should be conservative: %t", c.USB)
}
if strings.ToUpper(c.Parallel) != "NONE" {
t.Errorf("parallel port should not be defined: %s", c.Parallel)
}
if strings.ToUpper(c.Serial) != "NONE" {
t.Errorf("serial port should not be defined: %s", c.Serial)
}
}
func TestHWConfigParallel_File(t *testing.T) {
c := new(HWConfig)
c.Parallel = "file:filename"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasParallel() {
t.Errorf("parallel port should be defined")
}
parallel, err := c.ReadParallel()
if err != nil {
t.Fatalf("Unable to read parallel port definition: %s", err)
}
switch parallel.Union.(type) {
case *ParallelPortFile:
break
default:
t.Errorf("parallel port should be a file type")
}
if parallel.File.Filename != "filename" {
t.Errorf("parallel port filename should be \"filename\": %s", parallel.File.Filename)
}
}
func TestHWConfigParallel_Device(t *testing.T) {
c := new(HWConfig)
c.Parallel = "device:devicename,uni"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasParallel() {
t.Errorf("parallel port should be defined")
}
parallel, err := c.ReadParallel()
if err != nil {
t.Fatalf("Unable to read parallel port definition: %s", err)
}
switch parallel.Union.(type) {
case *ParallelPortDevice:
break
default:
t.Errorf("parallel port should be a device type")
}
if strings.ToLower(parallel.Device.Bidirectional) != "false" {
t.Errorf("parallel port device should not be bidirectional: %s", parallel.Device.Bidirectional)
}
if parallel.Device.Devicename != "devicename" {
t.Errorf("parallel port device should be \"devicename\": %s", parallel.Device.Devicename)
}
}
func TestHWConfigParallel_Auto(t *testing.T) {
c := new(HWConfig)
c.Parallel = "auto:bi"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasParallel() {
t.Errorf("parallel port should be defined")
}
parallel, err := c.ReadParallel()
if err != nil {
t.Fatalf("Unable to read parallel port definition: %s", err)
}
switch parallel.Union.(type) {
case *ParallelPortAuto:
break
default:
t.Errorf("parallel port should be an auto type")
}
if strings.ToLower(parallel.Auto.Bidirectional) != "true" {
t.Errorf("parallel port device should be bidirectional: %s", parallel.Auto.Bidirectional)
}
}
func TestHWConfigParallel_None(t *testing.T) {
c := new(HWConfig)
c.Parallel = "none"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasParallel() {
t.Errorf("parallel port should be defined")
}
parallel, err := c.ReadParallel()
if err != nil {
t.Fatalf("Unable to read parallel port definition: %s", err)
}
if parallel.Union != nil {
t.Errorf("parallel port shouldn't exist")
}
}
func TestHWConfigSerial_File(t *testing.T) {
c := new(HWConfig)
c.Serial = "file:filename,true"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasSerial() {
t.Errorf("serial port should be defined")
}
serial, err := c.ReadSerial()
if err != nil {
t.Fatalf("Unable to read serial port definition: %s", err)
}
switch serial.Union.(type) {
case *SerialConfigFile:
break
default:
t.Errorf("serial port should be a file type")
}
if serial.File.Filename != "filename" {
t.Errorf("serial port filename should be \"filename\": %s", serial.File.Filename)
}
if strings.ToLower(serial.File.Yield) != "true" {
t.Errorf("serial port yield should be true: %s", serial.File.Yield)
}
}
func TestHWConfigSerial_Device(t *testing.T) {
c := new(HWConfig)
c.Serial = "device:devicename,true"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasSerial() {
t.Errorf("serial port should be defined")
}
serial, err := c.ReadSerial()
if err != nil {
t.Fatalf("Unable to read serial port definition: %s", err)
}
switch serial.Union.(type) {
case *SerialConfigDevice:
break
default:
t.Errorf("serial port should be a device type")
}
if serial.Device.Devicename != "devicename" {
t.Errorf("serial port device should be \"devicename\": %s", serial.Device.Devicename)
}
if strings.ToLower(serial.Device.Yield) != "true" {
t.Errorf("serial port device should yield: %s", serial.Device.Yield)
}
}
func TestHWConfigSerial_Pipe(t *testing.T) {
c := new(HWConfig)
c.Serial = "pipe:mypath,client,app,true"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasSerial() {
t.Errorf("serial port should be defined")
}
serial, err := c.ReadSerial()
if err != nil {
t.Fatalf("Unable to read serial port definition: %s", err)
}
switch serial.Union.(type) {
case *SerialConfigPipe:
break
default:
t.Errorf("serial port should be a pipe type")
}
if serial.Pipe.Filename != "mypath" {
t.Errorf("serial port pipe name should be \"mypath\": %s", serial.Pipe.Filename)
}
if strings.ToLower(serial.Pipe.Endpoint) != "client" {
t.Errorf("serial port endpoint should be \"client\": %s", serial.Pipe.Endpoint)
}
if strings.ToLower(serial.Pipe.Host) != "true" {
t.Errorf("serial port host type for app should be true: %s", serial.Pipe.Host)
}
if strings.ToLower(serial.Pipe.Yield) != "true" {
t.Errorf("serial port should yield: %s", serial.Pipe.Yield)
}
}
func TestHWConfigSerial_Auto(t *testing.T) {
c := new(HWConfig)
c.Serial = "auto:true"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasSerial() {
t.Errorf("serial port should be defined")
}
serial, err := c.ReadSerial()
if err != nil {
t.Fatalf("Unable to read serial port definition: %s", err)
}
switch serial.Union.(type) {
case *SerialConfigAuto:
break
default:
t.Errorf("serial port should be an auto type")
}
if strings.ToLower(serial.Auto.Yield) != "true" {
t.Errorf("serial port should yield: %s", serial.Auto.Yield)
}
}
func TestHWConfigSerial_None(t *testing.T) {
c := new(HWConfig)
c.Serial = "none"
if errs := c.Prepare(testConfigTemplate(t)); len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if !c.HasSerial() {
t.Errorf("serial port should be defined")
}
serial, err := c.ReadSerial()
if err != nil {
t.Fatalf("Unable to read serial port definition: %s", err)
}
if serial.Union != nil {
t.Errorf("serial port shouldn't exist")
}
}

View File

@ -21,6 +21,7 @@ type Config struct {
common.FloppyConfig `mapstructure:",squash"`
bootcommand.VNCConfig `mapstructure:",squash"`
vmwcommon.DriverConfig `mapstructure:",squash"`
vmwcommon.HWConfig `mapstructure:",squash"`
vmwcommon.OutputConfig `mapstructure:",squash"`
vmwcommon.RunConfig `mapstructure:",squash"`
vmwcommon.ShutdownConfig `mapstructure:",squash"`
@ -45,18 +46,6 @@ type Config struct {
Version string `mapstructure:"version"`
VMName string `mapstructure:"vm_name"`
// Network adapter and type
NetworkAdapterType string `mapstructure:"network_adapter_type"`
Network string `mapstructure:"network"`
// device presence
Sound bool `mapstructure:"sound"`
USB bool `mapstructure:"usb"`
// communication ports
Serial string `mapstructure:"serial"`
Parallel string `mapstructure:"parallel"`
VMXDiskTemplatePath string `mapstructure:"vmx_disk_template_path"`
VMXTemplatePath string `mapstructure:"vmx_template_path"`
@ -87,6 +76,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
warnings = append(warnings, isoWarnings...)
errs = packer.MultiErrorAppend(errs, isoErrs...)
errs = packer.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.HWConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.DriverConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs,
c.OutputConfig.Prepare(&c.ctx, &c.PackerConfig)...)
@ -160,16 +150,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
}
}
if c.Network == "" {
c.Network = "nat"
}
if !c.Sound {
c.Sound = false
}
if !c.USB {
c.USB = false
if c.HWConfig.Network == "" {
c.HWConfig.Network = "nat"
}
// Remote configuration validation

View File

@ -6,7 +6,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
vmwcommon "github.com/hashicorp/packer/builder/vmware/common"
@ -21,6 +21,9 @@ type vmxTemplateData struct {
ISOPath string
Version string
CpuCount string
MemorySize string
HDD_BootOrder string
SCSI_Present string
@ -72,227 +75,6 @@ type stepCreateVMX struct {
tempDir string
}
/* serial conversions */
type serialConfigPipe struct {
filename string
endpoint string
host string
yield string
}
type serialConfigFile struct {
filename string
yield string
}
type serialConfigDevice struct {
devicename string
yield string
}
type serialConfigAuto struct {
devicename string
yield string
}
type serialUnion struct {
serialType interface{}
pipe *serialConfigPipe
file *serialConfigFile
device *serialConfigDevice
auto *serialConfigAuto
}
func unformat_serial(config string) (*serialUnion, error) {
var defaultSerialPort string
if runtime.GOOS == "windows" {
defaultSerialPort = "COM1"
} else {
defaultSerialPort = "/dev/ttyS0"
}
input := strings.SplitN(config, ":", 2)
if len(input) < 1 {
return nil, fmt.Errorf("Unexpected format for serial port: %s", config)
}
var formatType, formatOptions string
formatType = input[0]
if len(input) == 2 {
formatOptions = input[1]
} else {
formatOptions = ""
}
switch strings.ToUpper(formatType) {
case "PIPE":
comp := strings.Split(formatOptions, ",")
if len(comp) < 3 || len(comp) > 4 {
return nil, fmt.Errorf("Unexpected format for serial port : pipe : %s", config)
}
if res := strings.ToLower(comp[1]); res != "client" && res != "server" {
return nil, fmt.Errorf("Unexpected format for serial port : pipe : endpoint : %s : %s", res, config)
}
if res := strings.ToLower(comp[2]); res != "app" && res != "vm" {
return nil, fmt.Errorf("Unexpected format for serial port : pipe : host : %s : %s", res, config)
}
res := &serialConfigPipe{
filename: comp[0],
endpoint: comp[1],
host: map[string]string{"app": "TRUE", "vm": "FALSE"}[strings.ToLower(comp[2])],
yield: "FALSE",
}
if len(comp) == 4 {
res.yield = strings.ToUpper(comp[3])
}
if res.yield != "TRUE" && res.yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for serial port : pipe : yield : %s : %s", res.yield, config)
}
return &serialUnion{serialType: res, pipe: res}, nil
case "FILE":
comp := strings.Split(formatOptions, ",")
if len(comp) > 2 {
return nil, fmt.Errorf("Unexpected format for serial port : file : %s", config)
}
res := &serialConfigFile{yield: "FALSE"}
res.filename = filepath.FromSlash(comp[0])
res.yield = map[bool]string{true: strings.ToUpper(comp[0]), false: "FALSE"}[len(comp) > 1]
if res.yield != "TRUE" && res.yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for serial port : file : yield : %s : %s", res.yield, config)
}
return &serialUnion{serialType: res, file: res}, nil
case "DEVICE":
comp := strings.Split(formatOptions, ",")
if len(comp) > 2 {
return nil, fmt.Errorf("Unexpected format for serial port : device : %s", config)
}
res := new(serialConfigDevice)
if len(comp) == 2 {
res.devicename = map[bool]string{true: filepath.FromSlash(comp[0]), false: defaultSerialPort}[len(comp[0]) > 0]
res.yield = strings.ToUpper(comp[1])
} else if len(comp) == 1 {
res.devicename = map[bool]string{true: filepath.FromSlash(comp[0]), false: defaultSerialPort}[len(comp[0]) > 0]
res.yield = "FALSE"
} else if len(comp) == 0 {
res.devicename = defaultSerialPort
res.yield = "FALSE"
}
if res.yield != "TRUE" && res.yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for serial port : device : yield : %s : %s", res.yield, config)
}
return &serialUnion{serialType: res, device: res}, nil
case "AUTO":
res := new(serialConfigAuto)
res.devicename = defaultSerialPort
if len(formatOptions) > 0 {
res.yield = strings.ToUpper(formatOptions)
} else {
res.yield = "FALSE"
}
if res.yield != "TRUE" && res.yield != "FALSE" {
return nil, fmt.Errorf("Unexpected format for serial port : auto : yield : %s : %s", res.yield, config)
}
return &serialUnion{serialType: res, auto: res}, nil
case "NONE":
return &serialUnion{serialType: nil}, nil
default:
return nil, fmt.Errorf("Unknown serial type : %s : %s", strings.ToUpper(formatType), config)
}
}
/* parallel port */
type parallelUnion struct {
parallelType interface{}
file *parallelPortFile
device *parallelPortDevice
auto *parallelPortAuto
}
type parallelPortFile struct {
filename string
}
type parallelPortDevice struct {
bidirectional string
devicename string
}
type parallelPortAuto struct {
bidirectional string
}
func unformat_parallel(config string) (*parallelUnion, error) {
input := strings.SplitN(config, ":", 2)
if len(input) < 1 {
return nil, fmt.Errorf("Unexpected format for parallel port: %s", config)
}
var formatType, formatOptions string
formatType = input[0]
if len(input) == 2 {
formatOptions = input[1]
} else {
formatOptions = ""
}
switch strings.ToUpper(formatType) {
case "FILE":
res := &parallelPortFile{filename: filepath.FromSlash(formatOptions)}
return &parallelUnion{parallelType: res, file: res}, nil
case "DEVICE":
comp := strings.Split(formatOptions, ",")
if len(comp) < 1 || len(comp) > 2 {
return nil, fmt.Errorf("Unexpected format for parallel port: %s", config)
}
res := new(parallelPortDevice)
res.bidirectional = "FALSE"
res.devicename = filepath.FromSlash(comp[0])
if len(comp) > 1 {
switch strings.ToUpper(comp[1]) {
case "BI":
res.bidirectional = "TRUE"
case "UNI":
res.bidirectional = "FALSE"
default:
return nil, fmt.Errorf("Unknown parallel port direction : %s : %s", strings.ToUpper(comp[0]), config)
}
}
return &parallelUnion{parallelType: res, device: res}, nil
case "AUTO":
res := new(parallelPortAuto)
switch strings.ToUpper(formatOptions) {
case "":
fallthrough
case "UNI":
res.bidirectional = "FALSE"
case "BI":
res.bidirectional = "TRUE"
default:
return nil, fmt.Errorf("Unknown parallel port direction : %s : %s", strings.ToUpper(formatOptions), config)
}
return &parallelUnion{parallelType: res, auto: res}, nil
case "NONE":
return &parallelUnion{parallelType: nil}, nil
}
return nil, fmt.Errorf("Unexpected format for parallel port: %s", config)
}
/* regular steps */
func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
@ -390,8 +172,8 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
Network_Adapter: "e1000",
Sound_Present: map[bool]string{true: "TRUE", false: "FALSE"}[bool(config.Sound)],
Usb_Present: map[bool]string{true: "TRUE", false: "FALSE"}[bool(config.USB)],
Sound_Present: map[bool]string{true: "TRUE", false: "FALSE"}[bool(config.HWConfig.Sound)],
Usb_Present: map[bool]string{true: "TRUE", false: "FALSE"}[bool(config.HWConfig.USB)],
Serial_Present: "FALSE",
Parallel_Present: "FALSE",
@ -462,13 +244,13 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
}
/// Assign the network adapter type into the template if one was specified.
network_adapter := strings.ToLower(config.NetworkAdapterType)
network_adapter := strings.ToLower(config.HWConfig.NetworkAdapterType)
if network_adapter != "" {
templateData.Network_Adapter = network_adapter
}
/// Check the network type that the user specified
network := config.Network
network := config.HWConfig.Network
driver := state.Get("driver").(vmwcommon.Driver).GetVmwareDriver()
// check to see if the driver implements a network mapper for mapping
@ -514,10 +296,11 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
state.Put("vmnetwork", network)
/// check if serial port has been configured
if config.Serial == "" {
if !config.HWConfig.HasSerial() {
templateData.Serial_Present = "FALSE"
} else {
serial, err := unformat_serial(config.Serial)
// FIXME
serial, err := config.HWConfig.ReadSerial()
if err != nil {
err := fmt.Errorf("Error processing VMX template: %s", err)
state.Put("error", err)
@ -532,23 +315,23 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
templateData.Serial_Host = ""
templateData.Serial_Auto = "FALSE"
switch serial.serialType.(type) {
case *serialConfigPipe:
switch serial.Union.(type) {
case *vmwcommon.SerialConfigPipe:
templateData.Serial_Type = "pipe"
templateData.Serial_Endpoint = serial.pipe.endpoint
templateData.Serial_Host = serial.pipe.host
templateData.Serial_Yield = serial.pipe.yield
templateData.Serial_Filename = filepath.FromSlash(serial.pipe.filename)
case *serialConfigFile:
templateData.Serial_Endpoint = serial.Pipe.Endpoint
templateData.Serial_Host = serial.Pipe.Host
templateData.Serial_Yield = serial.Pipe.Yield
templateData.Serial_Filename = filepath.FromSlash(serial.Pipe.Filename)
case *vmwcommon.SerialConfigFile:
templateData.Serial_Type = "file"
templateData.Serial_Filename = filepath.FromSlash(serial.file.filename)
case *serialConfigDevice:
templateData.Serial_Filename = filepath.FromSlash(serial.File.Filename)
case *vmwcommon.SerialConfigDevice:
templateData.Serial_Type = "device"
templateData.Serial_Filename = filepath.FromSlash(serial.device.devicename)
case *serialConfigAuto:
templateData.Serial_Filename = filepath.FromSlash(serial.Device.Devicename)
case *vmwcommon.SerialConfigAuto:
templateData.Serial_Type = "device"
templateData.Serial_Filename = filepath.FromSlash(serial.auto.devicename)
templateData.Serial_Yield = serial.auto.yield
templateData.Serial_Filename = filepath.FromSlash(serial.Auto.Devicename)
templateData.Serial_Yield = serial.Auto.Yield
templateData.Serial_Auto = "TRUE"
case nil:
templateData.Serial_Present = "FALSE"
@ -563,10 +346,11 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
}
/// check if parallel port has been configured
if config.Parallel == "" {
if !config.HWConfig.HasParallel() {
templateData.Parallel_Present = "FALSE"
} else {
parallel, err := unformat_parallel(config.Parallel)
// FIXME
parallel, err := config.HWConfig.ReadParallel()
if err != nil {
err := fmt.Errorf("Error processing VMX template: %s", err)
state.Put("error", err)
@ -575,18 +359,18 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
}
templateData.Parallel_Auto = "FALSE"
switch parallel.parallelType.(type) {
case *parallelPortFile:
switch parallel.Union.(type) {
case *vmwcommon.ParallelPortFile:
templateData.Parallel_Present = "TRUE"
templateData.Parallel_Filename = filepath.FromSlash(parallel.file.filename)
case *parallelPortDevice:
templateData.Parallel_Filename = filepath.FromSlash(parallel.File.Filename)
case *vmwcommon.ParallelPortDevice:
templateData.Parallel_Present = "TRUE"
templateData.Parallel_Bidirectional = parallel.device.bidirectional
templateData.Parallel_Filename = filepath.FromSlash(parallel.device.devicename)
case *parallelPortAuto:
templateData.Parallel_Bidirectional = parallel.Device.Bidirectional
templateData.Parallel_Filename = filepath.FromSlash(parallel.Device.Devicename)
case *vmwcommon.ParallelPortAuto:
templateData.Parallel_Present = "TRUE"
templateData.Parallel_Auto = "TRUE"
templateData.Parallel_Bidirectional = parallel.auto.bidirectional
templateData.Parallel_Bidirectional = parallel.Auto.Bidirectional
case nil:
templateData.Parallel_Present = "FALSE"
break
@ -626,8 +410,22 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
s.tempDir = vmxDir
}
/// Now to handle options that will modify the template
vmxData := vmwcommon.ParseVMX(vmxContents)
// Set the number of cpus if it was specified
if config.HWConfig.CpuCount > 0 {
vmxData["numvcpus"] = strconv.Itoa(config.HWConfig.CpuCount)
}
// Apply the memory size that was specified
if config.HWConfig.MemorySize > 0 {
vmxData["memsize"] = strconv.Itoa(config.HWConfig.MemorySize)
}
/// Write the vmxData to the vmxPath
vmxPath := filepath.Join(vmxDir, config.VMName+".vmx")
if err := vmwcommon.WriteVMX(vmxPath, vmwcommon.ParseVMX(vmxContents)); err != nil {
if err := vmwcommon.WriteVMX(vmxPath, vmxData); err != nil {
err := fmt.Errorf("Error creating VMX file: %s", err)
state.Put("error", err)
ui.Error(err.Error())
@ -650,49 +448,51 @@ func (s *stepCreateVMX) Cleanup(multistep.StateBag) {
// do so by specifying in the builder configuration.
const DefaultVMXTemplate = `
.encoding = "UTF-8"
displayName = "{{ .Name }}"
// Hardware
numvcpus = "{{ .CpuCount }}"
memsize = "{{ .MemorySize }}"
config.version = "8"
virtualHW.productCompatibility = "hosted"
virtualHW.version = "{{ .Version }}"
// Bootup
nvram = "{{ .Name }}.nvram"
floppy0.present = "FALSE"
bios.bootOrder = "hdd,cdrom"
bios.hddOrder = "{{ .HDD_BootOrder }}"
checkpoint.vmState = ""
cleanShutdown = "TRUE"
config.version = "8"
displayName = "{{ .Name }}"
ehci.pciSlotNumber = "34"
ehci.present = "TRUE"
ethernet0.addressType = "generated"
ethernet0.bsdName = "en0"
ethernet0.connectionType = "{{ .Network_Type }}"
ethernet0.vnet = "{{ .Network_Device }}"
ethernet0.displayName = "Ethernet"
ethernet0.linkStatePropagation.enable = "FALSE"
ethernet0.pciSlotNumber = "33"
ethernet0.present = "TRUE"
ethernet0.virtualDev = "{{ .Network_Adapter }}"
ethernet0.wakeOnPcktRcv = "FALSE"
// Configuration
extendedConfigFile = "{{ .Name }}.vmxf"
floppy0.present = "FALSE"
guestOS = "{{ .GuestOS }}"
gui.fullScreenAtPowerOn = "FALSE"
gui.viewModeAtPowerOn = "windowed"
hgfs.linkRootShare = "TRUE"
hgfs.mapRootShare = "TRUE"
scsi0.present = "{{ .SCSI_Present }}"
scsi0.virtualDev = "{{ .SCSI_diskAdapterType }}"
scsi0.pciSlotNumber = "16"
scsi0:0.redo = ""
sata0.present = "{{ .SATA_Present }}"
nvme0.present = "{{ .NVME_Present }}"
{{ .DiskType }}0:0.present = "TRUE"
{{ .DiskType }}0:0.fileName = "{{ .DiskName }}.vmdk"
{{ .CDROMType }}0:{{ .CDROMType_PrimarySecondary }}.present = "TRUE"
{{ .CDROMType }}0:{{ .CDROMType_PrimarySecondary }}.fileName = "{{ .ISOPath }}"
{{ .CDROMType }}0:{{ .CDROMType_PrimarySecondary }}.deviceType = "cdrom-image"
isolation.tools.hgfs.disable = "FALSE"
memsize = "512"
nvram = "{{ .Name }}.nvram"
proxyApps.publishToHost = "FALSE"
replay.filename = ""
replay.supported = "FALSE"
checkpoint.vmState = ""
vmotion.checkpointFBSize = "65536000"
// Power control
cleanShutdown = "TRUE"
powerType.powerOff = "soft"
powerType.powerOn = "soft"
powerType.reset = "soft"
powerType.suspend = "soft"
// Tools
guestOS = "{{ .GuestOS }}"
tools.syncTime = "TRUE"
tools.upgrade.policy = "upgradeAtPowerCycle"
// Bus
pciBridge0.pciSlotNumber = "17"
pciBridge0.present = "TRUE"
pciBridge4.functions = "8"
@ -711,13 +511,40 @@ pciBridge7.functions = "8"
pciBridge7.pciSlotNumber = "24"
pciBridge7.present = "TRUE"
pciBridge7.virtualDev = "pcieRootPort"
powerType.powerOff = "soft"
powerType.powerOn = "soft"
powerType.reset = "soft"
powerType.suspend = "soft"
proxyApps.publishToHost = "FALSE"
replay.filename = ""
replay.supported = "FALSE"
ehci.present = "TRUE"
ehci.pciSlotNumber = "34"
vmci0.present = "TRUE"
vmci0.id = "1861462627"
vmci0.pciSlotNumber = "35"
// Network Adapter
ethernet0.addressType = "generated"
ethernet0.bsdName = "en0"
ethernet0.connectionType = "{{ .Network_Type }}"
ethernet0.vnet = "{{ .Network_Device }}"
ethernet0.displayName = "Ethernet"
ethernet0.linkStatePropagation.enable = "FALSE"
ethernet0.pciSlotNumber = "33"
ethernet0.present = "TRUE"
ethernet0.virtualDev = "{{ .Network_Adapter }}"
ethernet0.wakeOnPcktRcv = "FALSE"
// Hard disks
scsi0.present = "{{ .SCSI_Present }}"
scsi0.virtualDev = "{{ .SCSI_diskAdapterType }}"
scsi0.pciSlotNumber = "16"
scsi0:0.redo = ""
sata0.present = "{{ .SATA_Present }}"
nvme0.present = "{{ .NVME_Present }}"
{{ .DiskType }}0:0.present = "TRUE"
{{ .DiskType }}0:0.fileName = "{{ .DiskName }}.vmdk"
{{ .CDROMType }}0:{{ .CDROMType_PrimarySecondary }}.present = "TRUE"
{{ .CDROMType }}0:{{ .CDROMType_PrimarySecondary }}.fileName = "{{ .ISOPath }}"
{{ .CDROMType }}0:{{ .CDROMType_PrimarySecondary }}.deviceType = "cdrom-image"
// Sound
sound.startConnected = "{{ .Sound_Present }}"
@ -725,9 +552,6 @@ sound.present = "{{ .Sound_Present }}"
sound.fileName = "-1"
sound.autodetect = "TRUE"
tools.syncTime = "TRUE"
tools.upgrade.policy = "upgradeAtPowerCycle"
// USB
usb.pciSlotNumber = "32"
usb.present = "{{ .Usb_Present }}"
@ -748,13 +572,6 @@ parallel0.startConnected = "{{ .Parallel_Present }}"
parallel0.fileName = "{{ .Parallel_Filename }}"
parallel0.autodetect = "{{ .Parallel_Auto }}"
parallel0.bidirectional = "{{ .Parallel_Bidirectional }}"
virtualHW.productCompatibility = "hosted"
virtualHW.version = "{{ .Version }}"
vmci0.id = "1861462627"
vmci0.pciSlotNumber = "35"
vmci0.present = "TRUE"
vmotion.checkpointFBSize = "65536000"
`
const DefaultAdditionalDiskTemplate = `

View File

@ -98,6 +98,8 @@ builder.
five seconds and one minute 30 seconds, respectively. If this isn't
specified, the default is `10s` or 10 seconds.
- `cpus` (number) - The number of cpus to use when building the VM.
- `cdrom_adapter_type` (string) - The adapter type (or bus) that will be used
by the cdrom device. This is chosen by default based on the disk adapter
type. VMware tends to lean towards `ide` for the cdrom device unless
@ -221,6 +223,9 @@ builder.
URLs must point to the same file (same checksum). By default this is empty
and `iso_url` is used. Only one of `iso_url` or `iso_urls` can be specified.
- `memory` (number) - The amount of memory to use when building the VM
in megabytes.
- `network` (string) - This is the network type that the virtual machine will
be created with. This can be one of the generic values that map to a device
such as `hostonly`, `nat`, or `bridged`. If the network is not one of these
@ -371,7 +376,8 @@ builder.
given are valid. If you set this flag to `true`, Packer will skip this
validation. Default: `false`.
- `sound` (boolean) - Enable VMware's virtual soundcard device for the VM.
- `sound` (boolean) - Specify whether to enable VMware's virtual soundcard
device when building the VM. Defaults to `false`.
- `tools_upload_flavor` (string) - The flavor of the VMware Tools ISO to
upload into the VM. Valid values are `darwin`, `linux`, and `windows`. By
@ -385,9 +391,10 @@ builder.
By default the upload path is set to `{{.Flavor}}.iso`. This setting is not
used when `remote_type` is `esx5`.
- `usb` (boolean) - Enable VMware's USB bus for the guest VM. To enable usage
of the XHCI bus for USB 3 (5 Gbit/s), one can use the `vmx_data` option to
enable it by specifying `true` for the `usb_xhci.present` property.
- `usb` (boolean) - Enable VMware's USB bus when building the guest VM.
Defaults to `false`. To enable usage of the XHCI bus for USB 3 (5 Gbit/s),
one can use the `vmx_data` option to enable it by specifying `true` for
the `usb_xhci.present` property.
- `version` (string) - The [vmx hardware
version](http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1003746)
@ -403,7 +410,7 @@ builder.
- `vmx_data` (object of key/value strings) - Arbitrary key/values to enter
into the virtual machine VMX file. This is for advanced users who want to
set properties such as memory, CPU, etc.
set properties that aren't yet supported by the builder.
- `vmx_data_post` (object of key/value strings) - Identical to `vmx_data`,
except that it is run after the virtual machine is shutdown, and before the