252 lines
6.2 KiB
Go
252 lines
6.2 KiB
Go
|
package clone
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"path"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/google/go-cmp/cmp"
|
||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||
|
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||
|
"github.com/hashicorp/packer/builder/vsphere/common"
|
||
|
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||
|
)
|
||
|
|
||
|
func TestCreateConfig_Prepare(t *testing.T) {
|
||
|
tc := []struct {
|
||
|
name string
|
||
|
config *CloneConfig
|
||
|
fail bool
|
||
|
expectedErrMsg string
|
||
|
}{
|
||
|
{
|
||
|
name: "Valid config",
|
||
|
config: &CloneConfig{
|
||
|
Template: "template name",
|
||
|
StorageConfig: common.StorageConfig{
|
||
|
DiskControllerType: []string{"test"},
|
||
|
Storage: []common.DiskConfig{
|
||
|
{
|
||
|
DiskSize: 0,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
fail: true,
|
||
|
expectedErrMsg: "storage[0].'disk_size' is required",
|
||
|
},
|
||
|
{
|
||
|
name: "Storage validate disk_size",
|
||
|
config: &CloneConfig{
|
||
|
StorageConfig: common.StorageConfig{
|
||
|
Storage: []common.DiskConfig{
|
||
|
{
|
||
|
DiskSize: 0,
|
||
|
DiskThinProvisioned: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
fail: true,
|
||
|
expectedErrMsg: "storage[0].'disk_size' is required",
|
||
|
},
|
||
|
{
|
||
|
name: "Storage validate disk_controller_index",
|
||
|
config: &CloneConfig{
|
||
|
StorageConfig: common.StorageConfig{
|
||
|
Storage: []common.DiskConfig{
|
||
|
{
|
||
|
DiskSize: 32768,
|
||
|
DiskControllerIndex: 3,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
fail: true,
|
||
|
expectedErrMsg: "storage[0].'disk_controller_index' references an unknown disk controller",
|
||
|
},
|
||
|
{
|
||
|
name: "Validate template is set",
|
||
|
config: &CloneConfig{
|
||
|
StorageConfig: common.StorageConfig{
|
||
|
DiskControllerType: []string{"test"},
|
||
|
Storage: []common.DiskConfig{
|
||
|
{
|
||
|
DiskSize: 32768,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
fail: true,
|
||
|
expectedErrMsg: "'template' is required",
|
||
|
},
|
||
|
{
|
||
|
name: "Validate LinkedClone and DiskSize set at the same time",
|
||
|
config: &CloneConfig{
|
||
|
Template: "template name",
|
||
|
LinkedClone: true,
|
||
|
DiskSize: 32768,
|
||
|
StorageConfig: common.StorageConfig{
|
||
|
DiskControllerType: []string{"test"},
|
||
|
Storage: []common.DiskConfig{
|
||
|
{
|
||
|
DiskSize: 32768,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
fail: true,
|
||
|
expectedErrMsg: "'linked_clone' and 'disk_size' cannot be used together",
|
||
|
},
|
||
|
{
|
||
|
name: "Validate MacAddress and Network not set at the same time",
|
||
|
config: &CloneConfig{
|
||
|
Template: "template name",
|
||
|
MacAddress: "some mac address",
|
||
|
StorageConfig: common.StorageConfig{
|
||
|
DiskControllerType: []string{"test"},
|
||
|
Storage: []common.DiskConfig{
|
||
|
{
|
||
|
DiskSize: 32768,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
fail: true,
|
||
|
expectedErrMsg: "'network' is required when 'mac_address' is specified",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, c := range tc {
|
||
|
t.Run(c.name, func(t *testing.T) {
|
||
|
errs := c.config.Prepare()
|
||
|
if c.fail {
|
||
|
if len(errs) == 0 {
|
||
|
t.Fatalf("Config preprare should fail")
|
||
|
}
|
||
|
if errs[0].Error() != c.expectedErrMsg {
|
||
|
t.Fatalf("Expected error message: %s but was '%s'", c.expectedErrMsg, errs[0].Error())
|
||
|
}
|
||
|
} else {
|
||
|
if len(errs) != 0 {
|
||
|
t.Fatalf("Config preprare should not fail: %s", errs[0])
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestStepCreateVM_Run(t *testing.T) {
|
||
|
state := new(multistep.BasicStateBag)
|
||
|
state.Put("ui", &packersdk.BasicUi{
|
||
|
Reader: new(bytes.Buffer),
|
||
|
Writer: new(bytes.Buffer),
|
||
|
})
|
||
|
driverMock := driver.NewDriverMock()
|
||
|
state.Put("driver", driverMock)
|
||
|
step := basicStepCloneVM()
|
||
|
step.Force = true
|
||
|
vmPath := path.Join(step.Location.Folder, step.Location.VMName)
|
||
|
vmMock := new(driver.VirtualMachineMock)
|
||
|
driverMock.VM = vmMock
|
||
|
|
||
|
if action := step.Run(context.TODO(), state); action == multistep.ActionHalt {
|
||
|
t.Fatalf("Should not halt.")
|
||
|
}
|
||
|
|
||
|
// Pre clean VM
|
||
|
if !driverMock.PreCleanVMCalled {
|
||
|
t.Fatalf("driver.PreCleanVM should be called.")
|
||
|
}
|
||
|
if driverMock.PreCleanForce != step.Force {
|
||
|
t.Fatalf("Force PreCleanVM should be %t but was %t.", step.Force, driverMock.PreCleanForce)
|
||
|
}
|
||
|
if driverMock.PreCleanVMPath != vmPath {
|
||
|
t.Fatalf("VM path expected to be %s but was %s", vmPath, driverMock.PreCleanVMPath)
|
||
|
}
|
||
|
|
||
|
if !driverMock.FindVMCalled {
|
||
|
t.Fatalf("driver.FindVM should be called.")
|
||
|
}
|
||
|
if !vmMock.CloneCalled {
|
||
|
t.Fatalf("vm.Clone should be called.")
|
||
|
}
|
||
|
|
||
|
if diff := cmp.Diff(vmMock.CloneConfig, driverCreateConfig(step.Config, step.Location)); diff != "" {
|
||
|
t.Fatalf("wrong driver.CreateConfig: %s", diff)
|
||
|
}
|
||
|
vm, ok := state.GetOk("vm")
|
||
|
if !ok {
|
||
|
t.Fatal("state must contain the VM")
|
||
|
}
|
||
|
if vm != driverMock.VM {
|
||
|
t.Fatalf("state doesn't contain the created VM.")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func basicStepCloneVM() *StepCloneVM {
|
||
|
step := &StepCloneVM{
|
||
|
Config: createConfig(),
|
||
|
Location: basicLocationConfig(),
|
||
|
}
|
||
|
return step
|
||
|
}
|
||
|
|
||
|
func basicLocationConfig() *common.LocationConfig {
|
||
|
return &common.LocationConfig{
|
||
|
VMName: "test-vm",
|
||
|
Folder: "test-folder",
|
||
|
Cluster: "test-cluster",
|
||
|
Host: "test-host",
|
||
|
ResourcePool: "test-resource-pool",
|
||
|
Datastore: "test-datastore",
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func createConfig() *CloneConfig {
|
||
|
return &CloneConfig{
|
||
|
Template: "template name",
|
||
|
StorageConfig: common.StorageConfig{
|
||
|
DiskControllerType: []string{"pvscsi"},
|
||
|
Storage: []common.DiskConfig{
|
||
|
{
|
||
|
DiskSize: 32768,
|
||
|
DiskThinProvisioned: true,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func driverCreateConfig(config *CloneConfig, location *common.LocationConfig) *driver.CloneConfig {
|
||
|
var disks []driver.Disk
|
||
|
for _, disk := range config.StorageConfig.Storage {
|
||
|
disks = append(disks, driver.Disk{
|
||
|
DiskSize: disk.DiskSize,
|
||
|
DiskEagerlyScrub: disk.DiskEagerlyScrub,
|
||
|
DiskThinProvisioned: disk.DiskThinProvisioned,
|
||
|
ControllerIndex: disk.DiskControllerIndex,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
return &driver.CloneConfig{
|
||
|
StorageConfig: driver.StorageConfig{
|
||
|
DiskControllerType: config.StorageConfig.DiskControllerType,
|
||
|
Storage: disks,
|
||
|
},
|
||
|
Annotation: config.Notes,
|
||
|
Name: location.VMName,
|
||
|
Folder: location.Folder,
|
||
|
Cluster: location.Cluster,
|
||
|
Host: location.Host,
|
||
|
ResourcePool: location.ResourcePool,
|
||
|
Datastore: location.Datastore,
|
||
|
LinkedClone: config.LinkedClone,
|
||
|
Network: config.Network,
|
||
|
MacAddress: config.MacAddress,
|
||
|
VAppProperties: config.VAppConfig.Properties,
|
||
|
PrimaryDiskSize: config.DiskSize,
|
||
|
}
|
||
|
}
|