Merge branch 'master' into fix_8730

This commit is contained in:
Adrien Delorme 2020-03-09 17:49:33 +01:00
commit 631f402d1e
36 changed files with 378 additions and 124 deletions

View File

@ -36,7 +36,7 @@ commands:
type: string
steps:
- checkout
- run: GOOS=<< parameters.GOOS >> go build -ldflags="-s -w" -o ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH) .
- run: GOOS=<< parameters.GOOS >> go build -ldflags="-s -w -X github.com/hashicorp/packer/version.GitCommit=${CIRCLE_SHA1}" -o ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH) .
- run: zip ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH).zip ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH)
- run: rm ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH)
- persist_to_workspace:

View File

@ -300,7 +300,7 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag)
if len(createOutput.Errors) > 0 {
errString := fmt.Sprintf("Error waiting for fleet request (%s) to become ready:", *createOutput.FleetId)
for _, outErr := range createOutput.Errors {
errString = errString + fmt.Sprintf("%s", *outErr.ErrorMessage)
errString = errString + aws.StringValue(outErr.ErrorMessage)
}
err = fmt.Errorf(errString)
state.Put("error", err)

View File

@ -186,12 +186,9 @@ func (c *Communicator) UploadDir(dst string, src string, exclude []string) error
*/
var dockerSource string
dockerSource := src
if src[len(src)-1] == '/' {
dockerSource = fmt.Sprintf("%s.", src)
} else {
dockerSource = fmt.Sprintf("%s", src)
}
// Make the directory, then copy into it

View File

@ -18,7 +18,7 @@ func (s *stepCopyDisk) Run(ctx context.Context, state multistep.StateBag) multis
driver := state.Get("driver").(Driver)
isoPath := state.Get("iso_path").(string)
ui := state.Get("ui").(packer.Ui)
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s", config.VMName))
path := filepath.Join(config.OutputDir, config.VMName)
command := []string{
"convert",

View File

@ -29,13 +29,13 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
ui.Say("Creating required virtual machine disks")
// The 'main' or 'default' disk
diskFullPaths = append(diskFullPaths, filepath.Join(config.OutputDir, name))
diskSizes = append(diskSizes, fmt.Sprintf("%s", config.DiskSize))
diskSizes = append(diskSizes, config.DiskSize)
// Additional disks
if len(config.AdditionalDiskSize) > 0 {
for i, diskSize := range config.AdditionalDiskSize {
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s-%d", name, i+1))
diskFullPaths = append(diskFullPaths, path)
size := fmt.Sprintf("%s", diskSize)
size := diskSize
diskSizes = append(diskSizes, size)
}
}

View File

@ -23,7 +23,7 @@ func (s *stepResizeDisk) Run(ctx context.Context, state multistep.StateBag) mult
"resize",
"-f", config.Format,
path,
fmt.Sprintf("%s", config.DiskSize),
config.DiskSize,
}
if config.DiskImage == false {
return multistep.ActionContinue

View File

@ -25,6 +25,9 @@ type Driver interface {
// Create an NVME controller
CreateNVMeController(vm string, controller string, portcount int) error
// Delete all floppy controllers
RemoveFloppyControllers(vm string) error
// Delete a VM by name
Delete(string) error

View File

@ -75,6 +75,55 @@ func (d *VBox42Driver) CreateSCSIController(vmName string, name string) error {
return d.VBoxManage(command...)
}
func (d *VBox42Driver) RemoveFloppyControllers(vmName string) error {
var stdout bytes.Buffer
cmd := exec.Command(d.VBoxManagePath, "showvminfo", vmName, "--machinereadable")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return err
}
StorageControllerTypeRe := regexp.MustCompile("^storagecontrollertype([0-9]+)=\"(.+)\"$")
StorageControllerNameRe := regexp.MustCompile("^storagecontrollername([0-9]+)=\"(.+)\"$")
storageControllerNames := make(map[string]string)
storageControllerIdx := ""
for _, line := range strings.Split(stdout.String(), "\n") {
// Need to trim off CR character when running in windows
// Trimming whitespaces at this point helps to filter out empty value
line = strings.TrimRight(line, " \r")
matches := StorageControllerTypeRe.FindStringSubmatch(line)
if matches != nil {
// Floppy controllers are of a type I82078
if matches[2] == "I82078" {
// VirtualBox supports only one floppy controller per VM
storageControllerIdx = matches[1]
}
continue
}
matches = StorageControllerNameRe.FindStringSubmatch(line)
if matches != nil {
storageControllerNames[matches[1]] = matches[2]
}
}
if storageControllerIdx == "" {
return nil
}
command := []string{
"storagectl", vmName,
"--name", storageControllerNames[storageControllerIdx],
"--remove",
}
return d.VBoxManage(command...)
}
func (d *VBox42Driver) Delete(name string) error {
return d.VBoxManage("unregistervm", name, "--delete")
}

View File

@ -17,6 +17,9 @@ type DriverMock struct {
CreateNVMeControllerController string
CreateNVMeControllerErr error
RemoveFloppyControllersVM string
RemoveFloppyControllersErr error
DeleteCalled bool
DeleteName string
DeleteErr error
@ -81,6 +84,11 @@ func (d *DriverMock) CreateNVMeController(vm string, controller string, portcoun
return d.CreateNVMeControllerErr
}
func (d *DriverMock) RemoveFloppyControllers(vm string) error {
d.RemoveFloppyControllersVM = vm
return d.RemoveFloppyControllersErr
}
func (d *DriverMock) Delete(name string) error {
d.DeleteCalled = true
d.DeleteName = name

View File

@ -48,6 +48,12 @@ func (s *StepAttachFloppy) Run(ctx context.Context, state multistep.StateBag) mu
ui := state.Get("ui").(packer.Ui)
vmName := state.Get("vmName").(string)
ui.Say("Deleting any current floppy disk...")
if err := driver.RemoveFloppyControllers(vmName); err != nil {
state.Put("error", fmt.Errorf("Error deleting existing floppy controllers: %s", err))
return multistep.ActionHalt
}
ui.Say("Attaching floppy disk...")
// Create the floppy disk controller

View File

@ -38,6 +38,10 @@ func TestStepAttachFloppy(t *testing.T) {
t.Fatal("should NOT have error")
}
if driver.RemoveFloppyControllersVM == "" {
t.Fatal("RemoveFloppyControllers was not called")
}
if len(driver.VBoxManageCalls) != 2 {
t.Fatal("not enough calls to VBoxManage")
}

View File

@ -52,7 +52,7 @@ func (s *StepConfigureVRDP) Run(ctx context.Context, state multistep.StateBag) m
command := []string{
"modifyvm", vmName,
"--vrdeaddress", fmt.Sprintf("%s", s.VRDPBindAddress),
"--vrdeaddress", s.VRDPBindAddress,
"--vrdeauthtype", "null",
"--vrde", "on",
"--vrdeport",

View File

@ -102,7 +102,7 @@ func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multiste
return multistep.ActionHalt
}
ui.Message(fmt.Sprintf("%s", out.String()))
ui.Message(out.String())
return multistep.ActionContinue
}

View File

@ -52,10 +52,7 @@ type NIC struct {
}
type CreateConfig struct {
DiskThinProvisioned bool
DiskEagerlyScrub bool
DiskControllerType string // example: "scsi", "pvscsi"
DiskSize int64
DiskControllerType string // example: "scsi", "pvscsi"
Annotation string
Name string
@ -69,6 +66,13 @@ type CreateConfig struct {
USBController bool
Version uint // example: 10
Firmware string // efi or bios
Storage []Disk
}
type Disk struct {
DiskSize int64
DiskEagerlyScrub bool
DiskThinProvisioned bool
}
func (d *Driver) NewVM(ref *types.ManagedObjectReference) *VirtualMachine {
@ -488,6 +492,10 @@ func (vm *VirtualMachine) GetDir() (string, error) {
}
func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
if len(config.Storage) == 0 {
return nil, errors.New("no storage devices have been defined")
}
device, err := devices.CreateSCSIController(config.DiskControllerType)
if err != nil {
return nil, err
@ -498,20 +506,22 @@ func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig)
return nil, err
}
disk := &types.VirtualDisk{
VirtualDevice: types.VirtualDevice{
Key: devices.NewKey(),
Backing: &types.VirtualDiskFlatVer2BackingInfo{
DiskMode: string(types.VirtualDiskModePersistent),
ThinProvisioned: types.NewBool(config.DiskThinProvisioned),
EagerlyScrub: types.NewBool(config.DiskEagerlyScrub),
for _, dc := range config.Storage {
disk := &types.VirtualDisk{
VirtualDevice: types.VirtualDevice{
Key: devices.NewKey(),
Backing: &types.VirtualDiskFlatVer2BackingInfo{
DiskMode: string(types.VirtualDiskModePersistent),
ThinProvisioned: types.NewBool(dc.DiskThinProvisioned),
EagerlyScrub: types.NewBool(dc.DiskEagerlyScrub),
},
},
},
CapacityInKB: config.DiskSize * 1024,
}
CapacityInKB: dc.DiskSize * 1024,
}
devices.AssignController(disk, controller)
devices = append(devices, disk)
devices.AssignController(disk, controller)
devices = append(devices, disk)
}
return devices, nil
}

View File

@ -1,3 +1,4 @@
//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config
package iso
@ -33,7 +34,10 @@ type Config struct {
common.ShutdownConfig `mapstructure:",squash"`
CreateSnapshot bool `mapstructure:"create_snapshot"`
// Create a snapshot when set to `true`, so the VM can be used as a base
// for linked clones. Defaults to `false`.
CreateSnapshot bool `mapstructure:"create_snapshot"`
// Convert VM to a template. Defaults to `false`.
ConvertToTemplate bool `mapstructure:"convert_to_template"`
ctx interpolate.Context

View File

@ -31,6 +31,7 @@ type FlatConfig struct {
DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"`
DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"`
DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub"`
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage"`
Network *string `mapstructure:"network" cty:"network"`
NetworkCard *string `mapstructure:"network_card" cty:"network_card"`
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters"`
@ -153,6 +154,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
"disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false},
"disk_eagerly_scrub": &hcldec.AttrSpec{Name: "disk_eagerly_scrub", Type: cty.Bool, Required: false},
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*FlatDiskConfig)(nil).HCL2Spec())},
"network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false},
"network_card": &hcldec.AttrSpec{Name: "network_card", Type: cty.String, Required: false},
"network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())},

View File

@ -1,5 +1,5 @@
//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type NIC,CreateConfig
//go:generate mapstructure-to-hcl2 -type NIC,CreateConfig,DiskConfig
package iso
@ -24,6 +24,15 @@ type NIC struct {
Passthrough *bool `mapstructure:"passthrough"`
}
type DiskConfig struct {
// Set the size of the disk
DiskSize int64 `mapstructure:"disk_size" required:"true"`
// Enable VMDK thin provisioning for VM. Defaults to `false`.
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
// Enable VMDK eager scrubbing for VM. Defaults to `false`.
DiskEagerlyScrub bool `mapstructure:"disk_eagerly_scrub"`
}
type CreateConfig struct {
// Set VM hardware version. Defaults to the most current VM hardware
// version supported by vCenter. See
@ -31,7 +40,7 @@ type CreateConfig struct {
// the full list of supported VM hardware versions.
Version uint `mapstructure:"vm_version"`
// Set VM OS type. Defaults to `otherGuest`. See [
// here](https://pubs.vmware.com/vsphere-6-5/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvim.vm.GuestOsDescriptor.GuestOsIdentifier.html)
// here](https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html)
// for a full list of possible values.
GuestOSType string `mapstructure:"guest_os_type"`
// Set the Firmware at machine creation. Example `efi`. Defaults to `bios`.
@ -44,6 +53,8 @@ type CreateConfig struct {
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
// Enable VMDK eager scrubbing for VM. Defaults to `false`.
DiskEagerlyScrub bool `mapstructure:"disk_eagerly_scrub"`
// A collection of one or more disks to be provisioned along with the VM.
Storage []DiskConfig `mapstructure:"storage"`
// Set network VM will be connected to.
Network string `mapstructure:"network"`
// Set VM network card type. Example `vmxnet3`.
@ -115,23 +126,38 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste
})
}
// add disk as the first drive for backwards compatibility if the type is defined
var disks []driver.Disk
if s.Config.DiskSize != 0 {
disks = append(disks, driver.Disk{
DiskSize: s.Config.DiskSize,
DiskEagerlyScrub: s.Config.DiskEagerlyScrub,
DiskThinProvisioned: s.Config.DiskThinProvisioned,
})
}
for _, disk := range s.Config.Storage {
disks = append(disks, driver.Disk{
DiskSize: disk.DiskSize,
DiskEagerlyScrub: disk.DiskEagerlyScrub,
DiskThinProvisioned: disk.DiskThinProvisioned,
})
}
vm, err = d.CreateVM(&driver.CreateConfig{
DiskThinProvisioned: s.Config.DiskThinProvisioned,
DiskEagerlyScrub: s.Config.DiskEagerlyScrub,
DiskControllerType: s.Config.DiskControllerType,
DiskSize: s.Config.DiskSize,
Name: s.Location.VMName,
Folder: s.Location.Folder,
Cluster: s.Location.Cluster,
Host: s.Location.Host,
ResourcePool: s.Location.ResourcePool,
Datastore: s.Location.Datastore,
GuestOS: s.Config.GuestOSType,
NICs: networkCards,
USBController: s.Config.USBController,
Version: s.Config.Version,
Firmware: s.Config.Firmware,
Annotation: s.Config.Notes,
DiskControllerType: s.Config.DiskControllerType,
Storage: disks,
Annotation: s.Config.Notes,
Name: s.Location.VMName,
Folder: s.Location.Folder,
Cluster: s.Location.Cluster,
Host: s.Location.Host,
ResourcePool: s.Location.ResourcePool,
Datastore: s.Location.Datastore,
GuestOS: s.Config.GuestOSType,
NICs: networkCards,
USBController: s.Config.USBController,
Version: s.Config.Version,
Firmware: s.Config.Firmware,
})
if err != nil {
state.Put("error", fmt.Errorf("error creating vm: %v", err))

View File

@ -1,4 +1,4 @@
// Code generated by "mapstructure-to-hcl2 -type NIC,CreateConfig"; DO NOT EDIT.
// Code generated by "mapstructure-to-hcl2 -type NIC,CreateConfig,DiskConfig"; DO NOT EDIT.
package iso
import (
@ -9,18 +9,19 @@ import (
// FlatCreateConfig is an auto-generated flat version of CreateConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatCreateConfig struct {
Version *uint `mapstructure:"vm_version" cty:"vm_version"`
GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type"`
Firmware *string `mapstructure:"firmware" cty:"firmware"`
DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type"`
DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"`
DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"`
DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub"`
Network *string `mapstructure:"network" cty:"network"`
NetworkCard *string `mapstructure:"network_card" cty:"network_card"`
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters"`
USBController *bool `mapstructure:"usb_controller" cty:"usb_controller"`
Notes *string `mapstructure:"notes" cty:"notes"`
Version *uint `mapstructure:"vm_version" cty:"vm_version"`
GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type"`
Firmware *string `mapstructure:"firmware" cty:"firmware"`
DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type"`
DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"`
DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"`
DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub"`
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage"`
Network *string `mapstructure:"network" cty:"network"`
NetworkCard *string `mapstructure:"network_card" cty:"network_card"`
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters"`
USBController *bool `mapstructure:"usb_controller" cty:"usb_controller"`
Notes *string `mapstructure:"notes" cty:"notes"`
}
// FlatMapstructure returns a new FlatCreateConfig.
@ -42,6 +43,7 @@ func (*FlatCreateConfig) HCL2Spec() map[string]hcldec.Spec {
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
"disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false},
"disk_eagerly_scrub": &hcldec.AttrSpec{Name: "disk_eagerly_scrub", Type: cty.Bool, Required: false},
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*FlatDiskConfig)(nil).HCL2Spec())},
"network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false},
"network_card": &hcldec.AttrSpec{Name: "network_card", Type: cty.String, Required: false},
"network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())},
@ -51,6 +53,33 @@ func (*FlatCreateConfig) HCL2Spec() map[string]hcldec.Spec {
return s
}
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatDiskConfig struct {
DiskSize *int64 `mapstructure:"disk_size" required:"true" cty:"disk_size"`
DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"`
DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub"`
}
// FlatMapstructure returns a new FlatDiskConfig.
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*DiskConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatDiskConfig)
}
// HCL2Spec returns the hcl spec of a DiskConfig.
// This spec is used by HCL to read the fields of DiskConfig.
// The decoded values from this spec will then be applied to a FlatDiskConfig.
func (*FlatDiskConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
"disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false},
"disk_eagerly_scrub": &hcldec.AttrSpec{Name: "disk_eagerly_scrub", Type: cty.Bool, Required: false},
}
return s
}
// FlatNIC is an auto-generated flat version of NIC.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatNIC struct {

View File

@ -165,8 +165,8 @@ func createFlattenedEnvVars(config *Config) (string, error) {
envVars := make(map[string]string)
// Always available Packer provided env vars
envVars["PACKER_BUILD_NAME"] = fmt.Sprintf("%s", config.PackerBuildName)
envVars["PACKER_BUILDER_TYPE"] = fmt.Sprintf("%s", config.PackerBuilderType)
envVars["PACKER_BUILD_NAME"] = config.PackerBuildName
envVars["PACKER_BUILDER_TYPE"] = config.PackerBuilderType
// expose ip address variables
httpAddr := common.GetHTTPAddr()

View File

@ -94,7 +94,7 @@ func GetHTTPPort() string {
if err != nil {
return ""
}
return fmt.Sprintf("%s", port)
return port
}
func GetHTTPIP() string {
@ -102,7 +102,7 @@ func GetHTTPIP() string {
if err != nil {
return ""
}
return fmt.Sprintf("%s", ip)
return ip
}
func (s *StepHTTPServer) Cleanup(multistep.StateBag) {

View File

@ -61,8 +61,8 @@ func PopulateProvisionHookData(state multistep.StateBag) map[string]interface{}
hookData["User"] = commConf.User()
hookData["Password"] = commConf.Password()
hookData["ConnType"] = commConf.Type
hookData["SSHPublicKey"] = commConf.SSHPublicKey
hookData["SSHPrivateKey"] = commConf.SSHPrivateKey
hookData["SSHPublicKey"] = string(commConf.SSHPublicKey)
hookData["SSHPrivateKey"] = string(commConf.SSHPrivateKey)
// Backwards compatibility; in practice, WinRMPassword is fulfilled by
// Password.

View File

@ -83,13 +83,11 @@ func TestPopulateProvisionHookData(t *testing.T) {
if hookData["ConnType"] != commConfig.Type {
t.Fatalf("Bad: Expecting hookData[\"ConnType\"] was %s but actual value was %s", commConfig.Type, hookData["ConnType"])
}
sshPublicKey := fmt.Sprintf("%v", hookData["SSHPublicKey"].(interface{}))
if sshPublicKey == string(commConfig.SSHPublicKey) {
t.Fatalf("Bad: Expecting hookData[\"SSHPublicKey\"] was %s but actual value was %s", string(commConfig.SSHPublicKey), sshPublicKey)
if hookData["SSHPublicKey"] != string(commConfig.SSHPublicKey) {
t.Fatalf("Bad: Expecting hookData[\"SSHPublicKey\"] was %s but actual value was %s", string(commConfig.SSHPublicKey), hookData["SSHPublicKey"])
}
sshPrivateKey := fmt.Sprintf("%v", hookData["SSHPrivateKey"].(interface{}))
if sshPrivateKey == string(commConfig.SSHPrivateKey) {
t.Fatalf("Bad: Expecting hookData[\"SSHPrivateKey\"] was %s but actual value was %s", string(commConfig.SSHPrivateKey), sshPrivateKey)
if hookData["SSHPrivateKey"] != string(commConfig.SSHPrivateKey) {
t.Fatalf("Bad: Expecting hookData[\"SSHPrivateKey\"] was %s but actual value was %s", string(commConfig.SSHPrivateKey), hookData["SSHPrivateKey"])
}
if hookData["WinRMPassword"] != commConfig.WinRMPassword {
t.Fatalf("Bad: Expecting hookData[\"WinRMPassword\"] was %s but actual value was %s", commConfig.WinRMPassword, hookData["WinRMPassword"])

View File

@ -177,7 +177,6 @@ func (variables *Variables) decodeVariableBlock(block *hcl.Block, ectx *hcl.Eval
}
res.Type = tp
delete(attrs, "type")
}
if def, ok := attrs["default"]; ok {
@ -203,6 +202,13 @@ func (variables *Variables) decodeVariableBlock(block *hcl.Block, ectx *hcl.Eval
}
res.DefaultValue = defaultValue
// It's possible no type attribute was assigned so lets make
// sure we have a valid type otherwise there will be issues parsing the value.
if res.Type == cty.NilType {
res.Type = res.DefaultValue.Type()
}
}
if len(attrs) > 0 {
keys := []string{}
@ -252,7 +258,7 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
}
fakeFilename := fmt.Sprintf("<value for var.%s from env>", name)
expr, moreDiags := hclsyntax.ParseExpression([]byte(value), fakeFilename, hcl.Pos{Line: 1, Column: 1})
expr, moreDiags := expressionFromVariableDefinition(fakeFilename, value, variable.Type)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
@ -260,7 +266,6 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
val, valDiags := expr.Value(nil)
diags = append(diags, valDiags...)
if variable.Type != cty.NilType {
var err error
val, err = convert.Convert(val, variable.Type)
@ -274,7 +279,6 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
val = cty.DynamicVal
}
}
variable.EnvValue = val
}
@ -380,11 +384,12 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
}
fakeFilename := fmt.Sprintf("<value for var.%s from arguments>", name)
expr, moreDiags := hclsyntax.ParseExpression([]byte(value), fakeFilename, hcl.Pos{Line: 1, Column: 1})
expr, moreDiags := expressionFromVariableDefinition(fakeFilename, value, variable.Type)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
continue
}
val, valDiags := expr.Value(nil)
diags = append(diags, valDiags...)
@ -407,3 +412,14 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
return diags
}
// expressionFromVariableDefinition creates an hclsyntax.Expression that is capable of evaluating the specified value for a given cty.Type.
// The specified filename is to identify the source of where value originated from in the diagnostics report, if there is an error.
func expressionFromVariableDefinition(filename string, value string, variableType cty.Type) (hclsyntax.Expression, hcl.Diagnostics) {
switch variableType {
case cty.String, cty.Number:
return &hclsyntax.LiteralValueExpr{Val: cty.StringVal(value)}, nil
default:
return hclsyntax.ParseExpression([]byte(value), filename, hcl.Pos{Line: 1, Column: 1})
}
}

View File

@ -262,15 +262,18 @@ func TestVariables_collectVariableValues(t *testing.T) {
}{
{name: "string",
variables: Variables{"used_string": &Variable{DefaultValue: cty.StringVal("default_value")}},
variables: Variables{"used_string": &Variable{
DefaultValue: cty.StringVal("default_value"),
Type: cty.String,
}},
args: args{
env: []string{`PKR_VAR_used_string="env_value"`},
env: []string{`PKR_VAR_used_string=env_value`},
hclFiles: []string{
`used_string="xy"`,
`used_string="varfile_value"`,
},
argv: map[string]string{
"used_string": `"cmd_value"`,
"used_string": `cmd_value`,
},
},
@ -278,6 +281,7 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiags: false,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.String,
CmdValue: cty.StringVal("cmd_value"),
VarfileValue: cty.StringVal("varfile_value"),
EnvValue: cty.StringVal("env_value"),
@ -289,6 +293,38 @@ func TestVariables_collectVariableValues(t *testing.T) {
},
},
{name: "quoted string",
variables: Variables{"quoted_string": &Variable{
DefaultValue: cty.StringVal(`"default_value"`),
Type: cty.String,
}},
args: args{
env: []string{`PKR_VAR_quoted_string="env_value"`},
hclFiles: []string{
`quoted_string="\"xy\""`,
`quoted_string="\"varfile_value\""`,
},
argv: map[string]string{
"quoted_string": `"cmd_value"`,
},
},
// output
wantDiags: false,
wantVariables: Variables{
"quoted_string": &Variable{
Type: cty.String,
CmdValue: cty.StringVal(`"cmd_value"`),
VarfileValue: cty.StringVal(`"varfile_value"`),
EnvValue: cty.StringVal(`"env_value"`),
DefaultValue: cty.StringVal(`"default_value"`),
},
},
wantValues: map[string]cty.Value{
"quoted_string": cty.StringVal(`"cmd_value"`),
},
},
{name: "array of strings",
variables: Variables{"used_strings": &Variable{
DefaultValue: stringListVal("default_value_1"),
@ -321,8 +357,42 @@ func TestVariables_collectVariableValues(t *testing.T) {
},
},
{name: "bool",
variables: Variables{"enabled": &Variable{
DefaultValue: cty.False,
Type: cty.Bool,
}},
args: args{
env: []string{`PKR_VAR_enabled=true`},
hclFiles: []string{
`enabled="false"`,
},
argv: map[string]string{
"enabled": `true`,
},
},
// output
wantDiags: false,
wantVariables: Variables{
"enabled": &Variable{
Type: cty.Bool,
CmdValue: cty.True,
VarfileValue: cty.False,
EnvValue: cty.True,
DefaultValue: cty.False,
},
},
wantValues: map[string]cty.Value{
"enabled": cty.True,
},
},
{name: "invalid env var",
variables: Variables{"used_string": &Variable{DefaultValue: cty.StringVal("default_value")}},
variables: Variables{"used_string": &Variable{
DefaultValue: cty.StringVal("default_value"),
Type: cty.String,
}},
args: args{
env: []string{`PKR_VAR_used_string`},
},
@ -331,6 +401,7 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiags: false,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.String,
DefaultValue: cty.StringVal("default_value"),
},
},
@ -398,11 +469,11 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "value not corresponding to type - env",
variables: Variables{
"used_string": &Variable{
Type: cty.String,
Type: cty.List(cty.String),
},
},
args: args{
env: []string{`PKR_VAR_used_string=["string"]`},
env: []string{`PKR_VAR_used_string="string"`},
},
// output
@ -410,7 +481,7 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiagsHasError: true,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.String,
Type: cty.List(cty.String),
EnvValue: cty.DynamicVal,
},
},
@ -422,7 +493,7 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "value not corresponding to type - cfg file",
variables: Variables{
"used_string": &Variable{
Type: cty.String,
Type: cty.Bool,
},
},
args: args{
@ -434,7 +505,7 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiagsHasError: true,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.String,
Type: cty.Bool,
VarfileValue: cty.DynamicVal,
},
},
@ -446,12 +517,12 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "value not corresponding to type - argv",
variables: Variables{
"used_string": &Variable{
Type: cty.String,
Type: cty.Bool,
},
},
args: args{
argv: map[string]string{
"used_string": `["string"]`,
"used_string": `["true"]`,
},
},
@ -460,7 +531,7 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiagsHasError: true,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.String,
Type: cty.Bool,
CmdValue: cty.DynamicVal,
},
},

View File

@ -70,19 +70,3 @@ func (t *mockT) Skip(args ...interface{}) {
t.SkipArgs = args
t.f = true
}
func (t *mockT) failed() bool {
return t.f
}
func (t *mockT) failMessage() string {
if t.FatalCalled {
return t.FatalArgs[0].(string)
} else if t.ErrorCalled {
return t.ErrorArgs[0].(string)
} else if t.SkipCalled {
return t.SkipArgs[0].(string)
}
return "unknown"
}

View File

@ -326,7 +326,7 @@ func (c *Config) Port() int {
}
}
// Host returns the port that will be used for access based on config.
// Host returns the host that will be used for access based on config.
func (c *Config) Host() string {
switch c.Type {
case "ssh":
@ -338,7 +338,7 @@ func (c *Config) Host() string {
}
}
// User returns the port that will be used for access based on config.
// User returns the user that will be used for access based on config.
func (c *Config) User() string {
switch c.Type {
case "ssh":
@ -350,7 +350,7 @@ func (c *Config) User() string {
}
}
// Password returns the port that will be used for access based on config.
// Password returns the password that will be used for access based on config.
func (c *Config) Password() string {
switch c.Type {
case "ssh":

View File

@ -217,8 +217,8 @@ func (p *PostProcessor) BuildArgs(source, ovftool_uri string) ([]string, error)
args = append(args, p.config.Options...)
}
args = append(args, fmt.Sprintf(`%s`, source))
args = append(args, fmt.Sprintf(`%s`, ovftool_uri))
args = append(args, source)
args = append(args, ovftool_uri)
return args, nil
}

View File

@ -406,8 +406,8 @@ func (p *Provisioner) escapeEnvVars() ([]string, map[string]string) {
envVars := make(map[string]string)
// Always available Packer provided env vars
envVars["PACKER_BUILD_NAME"] = fmt.Sprintf("%s", p.config.PackerBuildName)
envVars["PACKER_BUILDER_TYPE"] = fmt.Sprintf("%s", p.config.PackerBuilderType)
envVars["PACKER_BUILD_NAME"] = p.config.PackerBuildName
envVars["PACKER_BUILDER_TYPE"] = p.config.PackerBuilderType
// expose ip address variables
httpAddr := common.GetHTTPAddr()

View File

@ -43,6 +43,8 @@ references for [ISO](#iso-configuration),
configuration references, which are
necessary for this build to succeed and can be found further down the page.
<%= partial "partials/builder/vsphere/iso/Config-not-required" %>
### Connection Configuration
<%= partial "partials/builder/vsphere/common/ConnectConfig-not-required" %>
@ -70,6 +72,10 @@ necessary for this build to succeed and can be found further down the page.
### Network Adapter Configuration
<%= partial "partials/builder/vsphere/iso/NIC-required" %>
### Storage Configuration
<%= partial "partials/builder/vsphere/iso/DiskConfig-required" %>
<%= partial "partials/builder/vsphere/iso/DiskConfig-not-required" %>
### Floppy Configuration
<%= partial "partials/builder/vsphere/iso/FloppyConfig-not-required" %>

View File

@ -34,7 +34,7 @@ However, if you are building from a brand-new and unconfigured operating system
image, you will almost always have to perform some extra work to configure SSH
on the guest machine. For most operating system distributions, this work will
be performed by a
(boot command)[/docs/builders/vmware-iso.html#boot-configuration]
[boot command](/docs/builders/vmware-iso.html#boot-configuration)
that references a file which provides answers to the normally-interactive
questions you get asked when installing an operating system. The name of this
file varies by operating system; some common examples are the "preseed" file

View File

@ -27,7 +27,7 @@ DigitalOcean. Replace the mock `api_token` value with your own.
Example Packer template:
``` json
```json
{
"provisioners": [
{

View File

@ -74,15 +74,37 @@ Here is a full list of the available functions for reference.
}
```
Valid variables to request are: "ID", "Host",
"Port", "User", "Password", "ConnType",
"PackerRunUUID", "PackerHTTPAddr", "SSHPublicKey", and "SSHPrivateKey".
Depending on which communicator you are using, some of these values may be
empty -- for example, the public and private keys are unique to the SSH
communicator. InstanceID represents the vm being provisioned. For example,
in Amazon it is the instance id; in digitalocean, it is the droplet id; in
Vmware, it is the vm name.
Valid variables to request are:
- __ID__: Represents the vm being provisioned. For example, in Amazon it is the instance id; in digitalocean,
it is the droplet id; in Vmware, it is the vm name.
- __Host__, __Port__, __User__ and __Password__: The host, port, user, and password that Packer uses to access the machine.
Useful for using the shell local provisioner to run Ansible or Inspec against the provisioned instance.
- __ConnType__: Type of communicator being used. For example, for SSH communicator this will be "ssh".
- __PackerRunUUID__: Current build's unique id. Can be used to specify build artifacts.
- __PackerHTTPAddr__: HTTP address of the file server Packer creates to serve items in the "http" dir to the vm, displayed in the format `IP:PORT`.
- __SSHPublicKey__ and __SSHPrivateKey__: The public and private key that Packer uses to connect to the instance.
These are unique to the SSH communicator and are unset when using other communicators.
__SSHPublicKey__ and __SSHPrivateKey__ can have escape sequences and special characters so their output should be single quoted to avoid surprises. For example:
```
{
...
"provisioners": [
{
"type": "shell",
"inline": [
"echo '{{ build `SSHPrivateKey`}}' > /tmp/packer-session.pem"
]
}
]
}
```
For backwards compatability, `WinRMPassword` is also available through this
engine, though it is no different than using the more general `Password`.

View File

@ -0,0 +1,7 @@
<!-- Code generated from the comments of the Config struct in builder/vsphere/iso/config.go; DO NOT EDIT MANUALLY -->
- `create_snapshot` (bool) - Create a snapshot when set to `true`, so the VM can be used as a base
for linked clones. Defaults to `false`.
- `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`.

View File

@ -6,7 +6,7 @@
the full list of supported VM hardware versions.
- `guest_os_type` (string) - Set VM OS type. Defaults to `otherGuest`. See [
here](https://pubs.vmware.com/vsphere-6-5/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvim.vm.GuestOsDescriptor.GuestOsIdentifier.html)
here](https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html)
for a full list of possible values.
- `firmware` (string) - Set the Firmware at machine creation. Example `efi`. Defaults to `bios`.
@ -19,6 +19,8 @@
- `disk_eagerly_scrub` (bool) - Enable VMDK eager scrubbing for VM. Defaults to `false`.
- `storage` ([]DiskConfig) - A collection of one or more disks to be provisioned along with the VM.
- `network` (string) - Set network VM will be connected to.
- `network_card` (string) - Set VM network card type. Example `vmxnet3`.

View File

@ -0,0 +1,6 @@
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
- `disk_thin_provisioned` (bool) - Enable VMDK thin provisioning for VM. Defaults to `false`.
- `disk_eagerly_scrub` (bool) - Enable VMDK eager scrubbing for VM. Defaults to `false`.

View File

@ -0,0 +1,4 @@
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
- `disk_size` (int64) - Set the size of the disk