Merge pull request #10896 from hashicorp/extract_vsphere
Extract vSphere plugin
This commit is contained in:
commit
da312e2785
|
@ -1,734 +0,0 @@
|
|||
package clone
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
commonT "github.com/hashicorp/packer/builder/vsphere/common/testing"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestCloneBuilderAcc_default(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
config := defaultConfig()
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: commonT.RenderConfig(config),
|
||||
Check: checkDefault(t, config["vm_name"].(string), config["host"].(string), "datastore1"),
|
||||
})
|
||||
}
|
||||
|
||||
func defaultConfig() map[string]interface{} {
|
||||
username := os.Getenv("VSPHERE_USERNAME")
|
||||
if username == "" {
|
||||
username = "root"
|
||||
}
|
||||
password := os.Getenv("VSPHERE_PASSWORD")
|
||||
if password == "" {
|
||||
password = "jetbrains"
|
||||
}
|
||||
|
||||
config := map[string]interface{}{
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"username": username,
|
||||
"password": password,
|
||||
"insecure_connection": true,
|
||||
|
||||
"template": "alpine",
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
|
||||
"linked_clone": true, // speed up
|
||||
"communicator": "none",
|
||||
}
|
||||
config["vm_name"] = commonT.NewVMName()
|
||||
return config
|
||||
}
|
||||
|
||||
func checkDefault(t *testing.T, name string, host string, datastore string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("name", "parent", "runtime.host", "resourcePool", "datastore")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if vmInfo.Name != name {
|
||||
t.Errorf("Invalid VM name: expected '%v', got '%v'", name, vmInfo.Name)
|
||||
}
|
||||
|
||||
f := d.NewFolder(vmInfo.Parent)
|
||||
folderPath, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
if folderPath != "" {
|
||||
t.Errorf("Invalid folder: expected '/', got '%v'", folderPath)
|
||||
}
|
||||
|
||||
h := d.NewHost(vmInfo.Runtime.Host)
|
||||
hostInfo, err := h.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read host properties: ", err)
|
||||
}
|
||||
if hostInfo.Name != host {
|
||||
t.Errorf("Invalid host name: expected '%v', got '%v'", host, hostInfo.Name)
|
||||
}
|
||||
|
||||
p := d.NewResourcePool(vmInfo.ResourcePool)
|
||||
poolPath, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
if poolPath != "" {
|
||||
t.Errorf("Invalid resource pool: expected '/', got '%v'", poolPath)
|
||||
}
|
||||
|
||||
dsr := vmInfo.Datastore[0].Reference()
|
||||
ds := d.NewDatastore(&dsr)
|
||||
dsInfo, err := ds.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read datastore properties: ", err)
|
||||
}
|
||||
if dsInfo.Name != datastore {
|
||||
t.Errorf("Invalid datastore name: expected '%v', got '%v'", datastore, dsInfo.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_artifact(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
config := defaultConfig()
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: commonT.RenderConfig(config),
|
||||
Check: checkArtifact(t),
|
||||
})
|
||||
}
|
||||
|
||||
func checkArtifact(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
if len(artifacts) > 1 {
|
||||
t.Fatal("more than 1 artifact")
|
||||
}
|
||||
|
||||
artifactRaw := artifacts[0]
|
||||
_, ok := artifactRaw.(*common.Artifact)
|
||||
if !ok {
|
||||
t.Fatalf("unknown artifact: %#v", artifactRaw)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_folder(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: folderConfig(),
|
||||
Check: checkFolder(t, "folder1/folder2"),
|
||||
})
|
||||
}
|
||||
|
||||
func folderConfig() string {
|
||||
config := defaultConfig()
|
||||
config["folder"] = "folder1/folder2"
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkFolder(t *testing.T, folder string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("parent")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
f := d.NewFolder(vmInfo.Parent)
|
||||
path, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
if path != folder {
|
||||
t.Errorf("Wrong folder. expected: %v, got: %v", folder, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_resourcePool(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: resourcePoolConfig(),
|
||||
Check: checkResourcePool(t, "pool1/pool2"),
|
||||
})
|
||||
}
|
||||
|
||||
func resourcePoolConfig() string {
|
||||
config := defaultConfig()
|
||||
config["resource_pool"] = "pool1/pool2"
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkResourcePool(t *testing.T, pool string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("resourcePool")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
p := d.NewResourcePool(vmInfo.ResourcePool)
|
||||
path, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
if path != pool {
|
||||
t.Errorf("Wrong folder. expected: %v, got: %v", pool, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_datastore(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: datastoreConfig(),
|
||||
Check: checkDatastore(t, "datastore1"), // on esxi-1.vsphere65.test
|
||||
})
|
||||
}
|
||||
|
||||
func datastoreConfig() string {
|
||||
config := defaultConfig()
|
||||
config["template"] = "alpine-host4" // on esxi-4.vsphere65.test
|
||||
config["linked_clone"] = false
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkDatastore(t *testing.T, name string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("datastore")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
n := len(vmInfo.Datastore)
|
||||
if n != 1 {
|
||||
t.Fatalf("VM should have 1 datastore, got %v", n)
|
||||
}
|
||||
|
||||
ds := d.NewDatastore(&vmInfo.Datastore[0])
|
||||
info, err := ds.Info("name")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read datastore properties: %v", err)
|
||||
}
|
||||
if info.Name != name {
|
||||
t.Errorf("Wrong datastore. expected: %v, got: %v", name, info.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_multipleDatastores(t *testing.T) {
|
||||
t.Skip("test must fail")
|
||||
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: multipleDatastoresConfig(),
|
||||
})
|
||||
}
|
||||
|
||||
func multipleDatastoresConfig() string {
|
||||
config := defaultConfig()
|
||||
config["host"] = "esxi-4.vsphere65.test" // host with 2 datastores
|
||||
config["linked_clone"] = false
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_fullClone(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: fullCloneConfig(),
|
||||
Check: checkFullClone(t),
|
||||
})
|
||||
}
|
||||
|
||||
func fullCloneConfig() string {
|
||||
config := defaultConfig()
|
||||
config["linked_clone"] = false
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkFullClone(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if len(vmInfo.LayoutEx.Disk[0].Chain) != 1 {
|
||||
t.Error("Not a full clone")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_linkedClone(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: linkedCloneConfig(),
|
||||
Check: checkLinkedClone(t),
|
||||
})
|
||||
}
|
||||
|
||||
func linkedCloneConfig() string {
|
||||
config := defaultConfig()
|
||||
config["linked_clone"] = true
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkLinkedClone(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if len(vmInfo.LayoutEx.Disk[0].Chain) != 2 {
|
||||
t.Error("Not a linked clone")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_network(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: networkConfig(),
|
||||
Check: checkNetwork(t, "VM Network 2"),
|
||||
})
|
||||
}
|
||||
|
||||
func networkConfig() string {
|
||||
config := defaultConfig()
|
||||
config["template"] = "alpine-host4"
|
||||
config["host"] = "esxi-4.vsphere65.test"
|
||||
config["datastore"] = "datastore4"
|
||||
config["network"] = "VM Network 2"
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkNetwork(t *testing.T, name string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("network")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
n := len(vmInfo.Network)
|
||||
if n != 1 {
|
||||
t.Fatalf("VM should have 1 network, got %v", n)
|
||||
}
|
||||
|
||||
ds := d.NewNetwork(&vmInfo.Network[0])
|
||||
info, err := ds.Info("name")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read network properties: %v", err)
|
||||
}
|
||||
if info.Name != name {
|
||||
t.Errorf("Wrong network. expected: %v, got: %v", name, info.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_hardware(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: hardwareConfig(),
|
||||
Check: checkHardware(t),
|
||||
})
|
||||
}
|
||||
|
||||
func hardwareConfig() string {
|
||||
config := defaultConfig()
|
||||
config["CPUs"] = 2
|
||||
config["cpu_cores"] = 2
|
||||
config["CPU_reservation"] = 1000
|
||||
config["CPU_limit"] = 1500
|
||||
config["RAM"] = 2048
|
||||
config["RAM_reservation"] = 1024
|
||||
config["CPU_hot_plug"] = true
|
||||
config["RAM_hot_plug"] = true
|
||||
config["video_ram"] = 8192
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkHardware(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
vmInfo, err := vm.Info("config")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
cpuSockets := vmInfo.Config.Hardware.NumCPU
|
||||
if cpuSockets != 2 {
|
||||
t.Errorf("VM should have 2 CPU sockets, got %v", cpuSockets)
|
||||
}
|
||||
|
||||
cpuCores := vmInfo.Config.Hardware.NumCoresPerSocket
|
||||
if cpuCores != 2 {
|
||||
t.Errorf("VM should have 2 CPU cores per socket, got %v", cpuCores)
|
||||
}
|
||||
|
||||
cpuReservation := *vmInfo.Config.CpuAllocation.Reservation
|
||||
if cpuReservation != 1000 {
|
||||
t.Errorf("VM should have CPU reservation for 1000 Mhz, got %v", cpuReservation)
|
||||
}
|
||||
|
||||
cpuLimit := *vmInfo.Config.CpuAllocation.Limit
|
||||
if cpuLimit != 1500 {
|
||||
t.Errorf("VM should have CPU reservation for 1500 Mhz, got %v", cpuLimit)
|
||||
}
|
||||
|
||||
ram := vmInfo.Config.Hardware.MemoryMB
|
||||
if ram != 2048 {
|
||||
t.Errorf("VM should have 2048 MB of RAM, got %v", ram)
|
||||
}
|
||||
|
||||
ramReservation := *vmInfo.Config.MemoryAllocation.Reservation
|
||||
if ramReservation != 1024 {
|
||||
t.Errorf("VM should have RAM reservation for 1024 MB, got %v", ramReservation)
|
||||
}
|
||||
|
||||
cpuHotAdd := vmInfo.Config.CpuHotAddEnabled
|
||||
if !*cpuHotAdd {
|
||||
t.Errorf("VM should have CPU hot add enabled, got %v", cpuHotAdd)
|
||||
}
|
||||
|
||||
memoryHotAdd := vmInfo.Config.MemoryHotAddEnabled
|
||||
if !*memoryHotAdd {
|
||||
t.Errorf("VM should have Memory hot add enabled, got %v", memoryHotAdd)
|
||||
}
|
||||
|
||||
l, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM devices: %v", err)
|
||||
}
|
||||
v := l.SelectByType((*types.VirtualMachineVideoCard)(nil))
|
||||
if len(v) != 1 {
|
||||
t.Errorf("VM should have one video card")
|
||||
}
|
||||
if v[0].(*types.VirtualMachineVideoCard).VideoRamSizeInKB != 8192 {
|
||||
t.Errorf("Video RAM should be equal 8192")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_RAMReservation(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: RAMReservationConfig(),
|
||||
Check: checkRAMReservation(t),
|
||||
})
|
||||
}
|
||||
|
||||
func RAMReservationConfig() string {
|
||||
config := defaultConfig()
|
||||
config["RAM_reserve_all"] = true
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkRAMReservation(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
vmInfo, err := vm.Info("config")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if *vmInfo.Config.MemoryReservationLockedToMax != true {
|
||||
t.Errorf("VM should have all RAM reserved")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_sshPassword(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: sshPasswordConfig(),
|
||||
Check: checkDefaultBootOrder(t),
|
||||
})
|
||||
}
|
||||
|
||||
func sshPasswordConfig() string {
|
||||
config := defaultConfig()
|
||||
config["communicator"] = "ssh"
|
||||
config["ssh_username"] = "root"
|
||||
config["ssh_password"] = "jetbrains"
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkDefaultBootOrder(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("config.bootOptions")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
order := vmInfo.Config.BootOptions.BootOrder
|
||||
if order != nil {
|
||||
t.Errorf("Boot order must be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_sshKey(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: sshKeyConfig(),
|
||||
})
|
||||
}
|
||||
|
||||
func sshKeyConfig() string {
|
||||
config := defaultConfig()
|
||||
config["communicator"] = "ssh"
|
||||
config["ssh_username"] = "root"
|
||||
config["ssh_private_key_file"] = "../test/test-key.pem"
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_snapshot(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: snapshotConfig(),
|
||||
Check: checkSnapshot(t),
|
||||
})
|
||||
}
|
||||
|
||||
func snapshotConfig() string {
|
||||
config := defaultConfig()
|
||||
config["linked_clone"] = false
|
||||
config["create_snapshot"] = true
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkSnapshot(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
vmInfo, err := vm.Info("layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
layers := len(vmInfo.LayoutEx.Disk[0].Chain)
|
||||
if layers != 2 {
|
||||
t.Errorf("VM should have a single snapshot. expected 2 disk layers, got %v", layers)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_template(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: templateConfig(),
|
||||
Check: checkTemplate(t),
|
||||
})
|
||||
}
|
||||
|
||||
func templateConfig() string {
|
||||
config := defaultConfig()
|
||||
config["convert_to_template"] = true
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkTemplate(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
vmInfo, err := vm.Info("config.template")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if vmInfo.Config.Template != true {
|
||||
t.Error("Not a template")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_bootOrder(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: bootOrderConfig(),
|
||||
Check: checkBootOrder(t),
|
||||
})
|
||||
}
|
||||
|
||||
func bootOrderConfig() string {
|
||||
config := defaultConfig()
|
||||
config["communicator"] = "ssh"
|
||||
config["ssh_username"] = "root"
|
||||
config["ssh_password"] = "jetbrains"
|
||||
|
||||
config["boot_order"] = "disk,cdrom,floppy"
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkBootOrder(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("config.bootOptions")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
order := vmInfo.Config.BootOptions.BootOrder
|
||||
if order == nil {
|
||||
t.Errorf("Boot order must not be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_notes(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: notesConfig(),
|
||||
Check: checkNotes(t),
|
||||
})
|
||||
}
|
||||
|
||||
func notesConfig() string {
|
||||
config := defaultConfig()
|
||||
config["notes"] = "test"
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkNotes(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("config.annotation")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
notes := vmInfo.Config.Annotation
|
||||
if notes != "test" {
|
||||
t.Errorf("notest should be 'test'")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneBuilderAcc_windows(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
t.Skip("test is too slow")
|
||||
config := windowsConfig()
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: commonT.RenderConfig(config),
|
||||
})
|
||||
}
|
||||
|
||||
func windowsConfig() map[string]interface{} {
|
||||
username := os.Getenv("VSPHERE_USERNAME")
|
||||
if username == "" {
|
||||
username = "root"
|
||||
}
|
||||
password := os.Getenv("VSPHERE_PASSWORD")
|
||||
if password == "" {
|
||||
password = "jetbrains"
|
||||
}
|
||||
|
||||
config := map[string]interface{}{
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"username": username,
|
||||
"password": password,
|
||||
"insecure_connection": true,
|
||||
|
||||
"vm_name": commonT.NewVMName(),
|
||||
"template": "windows",
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
"linked_clone": true, // speed up
|
||||
|
||||
"communicator": "winrm",
|
||||
"winrm_username": "jetbrains",
|
||||
"winrm_password": "jetbrains",
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package clone
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func TestCloneBuilder_ImplementsBuilder(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Builder{}
|
||||
if _, ok := raw.(packersdk.Builder); !ok {
|
||||
t.Fatalf("Builder should be a builder")
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package clone
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCloneConfig_MinimalConfig(t *testing.T) {
|
||||
c := new(Config)
|
||||
warns, errs := c.Prepare(minimalConfig())
|
||||
testConfigOk(t, warns, errs)
|
||||
}
|
||||
|
||||
func TestCloneConfig_MandatoryParameters(t *testing.T) {
|
||||
params := []string{"vcenter_server", "username", "password", "template", "vm_name", "host"}
|
||||
for _, param := range params {
|
||||
raw := minimalConfig()
|
||||
raw[param] = ""
|
||||
c := new(Config)
|
||||
warns, err := c.Prepare(raw)
|
||||
testConfigErr(t, param, warns, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneConfig_Timeout(t *testing.T) {
|
||||
raw := minimalConfig()
|
||||
raw["shutdown_timeout"] = "3m"
|
||||
conf := new(Config)
|
||||
warns, err := conf.Prepare(raw)
|
||||
testConfigOk(t, warns, err)
|
||||
if conf.ShutdownConfig.Timeout != 3*time.Minute {
|
||||
t.Fatalf("shutdown_timeout sould be equal 3 minutes, got %v", conf.ShutdownConfig.Timeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloneConfig_RAMReservation(t *testing.T) {
|
||||
raw := minimalConfig()
|
||||
raw["RAM_reservation"] = 1000
|
||||
raw["RAM_reserve_all"] = true
|
||||
c := new(Config)
|
||||
warns, err := c.Prepare(raw)
|
||||
testConfigErr(t, "RAM_reservation", warns, err)
|
||||
}
|
||||
|
||||
func minimalConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"vcenter_server": "vcenter.domain.local",
|
||||
"username": "root",
|
||||
"password": "vmware",
|
||||
"template": "ubuntu",
|
||||
"vm_name": "vm1",
|
||||
"host": "esxi1.domain.local",
|
||||
"ssh_username": "root",
|
||||
"ssh_password": "secret",
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigOk(t *testing.T, warns []string, err error) {
|
||||
if len(warns) > 0 {
|
||||
t.Errorf("Should be no warnings: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testConfigErr(t *testing.T, context string, warns []string, err error) {
|
||||
if len(warns) > 0 {
|
||||
t.Errorf("Should be no warnings: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Error("An error is not raised for", context)
|
||||
}
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
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,
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func cleanupTestState(mockVM driver.VirtualMachine) multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("vm", mockVM)
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
return state
|
||||
}
|
||||
|
||||
func Test_CleanupVM(t *testing.T) {
|
||||
type testCase struct {
|
||||
Reason string
|
||||
ExtraState map[string]interface{}
|
||||
ExpectDestroy bool
|
||||
}
|
||||
testCases := []testCase{
|
||||
{
|
||||
"if cancelled, we should destroy the VM",
|
||||
map[string]interface{}{multistep.StateCancelled: true},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"if halted, we should destroy the VM",
|
||||
map[string]interface{}{multistep.StateHalted: true},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"if destroy flag is set, we should destroy the VM",
|
||||
map[string]interface{}{"destroy_vm": true},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"if none of the above flags are set, we should not destroy the VM",
|
||||
map[string]interface{}{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
mockVM := &driver.VirtualMachineMock{}
|
||||
state := cleanupTestState(mockVM)
|
||||
for k, v := range tc.ExtraState {
|
||||
state.Put(k, v)
|
||||
}
|
||||
CleanupVM(state)
|
||||
if mockVM.DestroyCalled != tc.ExpectDestroy {
|
||||
t.Fatalf("Problem with cleanup: %s", tc.Reason)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func basicStateBag(errorBuffer *strings.Builder) *multistep.BasicStateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
ErrorWriter: errorBuffer,
|
||||
})
|
||||
return state
|
||||
}
|
|
@ -1,235 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func TestCDRomConfig_Prepare(t *testing.T) {
|
||||
// Data validation
|
||||
tc := []struct {
|
||||
name string
|
||||
config *CDRomConfig
|
||||
fail bool
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "Should not fail for empty config",
|
||||
config: new(CDRomConfig),
|
||||
fail: false,
|
||||
expectedErrMsg: "",
|
||||
},
|
||||
{
|
||||
name: "Valid cdroom type ide",
|
||||
config: &CDRomConfig{CdromType: "ide"},
|
||||
fail: false,
|
||||
expectedErrMsg: "",
|
||||
},
|
||||
{
|
||||
name: "Valid cdroom type sata",
|
||||
config: &CDRomConfig{CdromType: "ide"},
|
||||
fail: false,
|
||||
expectedErrMsg: "",
|
||||
},
|
||||
{
|
||||
name: "Invalid cdroom type",
|
||||
config: &CDRomConfig{CdromType: "invalid"},
|
||||
fail: true,
|
||||
expectedErrMsg: "'cdrom_type' must be 'ide' or 'sata'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepAddCDRom_Run(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
state *multistep.BasicStateBag
|
||||
step *StepAddCDRom
|
||||
vmMock *driver.VirtualMachineMock
|
||||
expectedAction multistep.StepAction
|
||||
expectedVmMock *driver.VirtualMachineMock
|
||||
fail bool
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "CDRom SATA type with all iso paths set",
|
||||
state: cdAndIsoRemotePathStateBag(),
|
||||
step: &StepAddCDRom{
|
||||
Config: &CDRomConfig{
|
||||
CdromType: "sata",
|
||||
ISOPaths: []string{"iso/path"},
|
||||
},
|
||||
},
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedAction: multistep.ActionContinue,
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FindSATAControllerCalled: true,
|
||||
AddCdromCalled: true,
|
||||
AddCdromCalledTimes: 3,
|
||||
AddCdromTypes: []string{"sata", "sata", "sata"},
|
||||
AddCdromPaths: []string{"remote/path", "iso/path", "cd/path"},
|
||||
},
|
||||
fail: false,
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Add SATA Controller",
|
||||
state: basicStateBag(nil),
|
||||
step: &StepAddCDRom{
|
||||
Config: &CDRomConfig{
|
||||
CdromType: "sata",
|
||||
},
|
||||
},
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
FindSATAControllerErr: driver.ErrNoSataController,
|
||||
},
|
||||
expectedAction: multistep.ActionContinue,
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FindSATAControllerCalled: true,
|
||||
FindSATAControllerErr: driver.ErrNoSataController,
|
||||
AddSATAControllerCalled: true,
|
||||
},
|
||||
fail: false,
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Fail to add SATA Controller",
|
||||
state: basicStateBag(nil),
|
||||
step: &StepAddCDRom{
|
||||
Config: &CDRomConfig{
|
||||
CdromType: "sata",
|
||||
},
|
||||
},
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
FindSATAControllerErr: driver.ErrNoSataController,
|
||||
AddSATAControllerErr: fmt.Errorf("AddSATAController error"),
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FindSATAControllerCalled: true,
|
||||
AddSATAControllerCalled: true,
|
||||
},
|
||||
fail: true,
|
||||
errMessage: fmt.Sprintf("error adding SATA controller: %v", fmt.Errorf("AddSATAController error")),
|
||||
},
|
||||
{
|
||||
name: "IDE CDRom Type and Iso Path set",
|
||||
state: basicStateBag(nil),
|
||||
step: &StepAddCDRom{
|
||||
Config: &CDRomConfig{
|
||||
CdromType: "ide",
|
||||
ISOPaths: []string{"iso/path"},
|
||||
},
|
||||
},
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedAction: multistep.ActionContinue,
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
AddCdromCalled: true,
|
||||
AddCdromCalledTimes: 1,
|
||||
AddCdromTypes: []string{"ide"},
|
||||
AddCdromPaths: []string{"iso/path"},
|
||||
},
|
||||
fail: false,
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Fail to add cdrom from ISOPaths",
|
||||
state: basicStateBag(nil),
|
||||
step: &StepAddCDRom{
|
||||
Config: &CDRomConfig{
|
||||
ISOPaths: []string{"iso/path"},
|
||||
},
|
||||
},
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
AddCdromErr: fmt.Errorf("AddCdrom error"),
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
AddCdromCalled: true,
|
||||
AddCdromCalledTimes: 1,
|
||||
AddCdromTypes: []string{""},
|
||||
AddCdromPaths: []string{"iso/path"},
|
||||
},
|
||||
fail: true,
|
||||
errMessage: fmt.Sprintf("error mounting an image 'iso/path': %v", fmt.Errorf("AddCdrom error")),
|
||||
},
|
||||
{
|
||||
name: "Fail to add cdrom from state iso_remote_path",
|
||||
state: isoRemotePathStateBag(),
|
||||
step: &StepAddCDRom{
|
||||
Config: new(CDRomConfig),
|
||||
},
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
AddCdromErr: fmt.Errorf("AddCdrom error"),
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
AddCdromCalled: true,
|
||||
AddCdromCalledTimes: 1,
|
||||
AddCdromTypes: []string{""},
|
||||
AddCdromPaths: []string{"remote/path"},
|
||||
},
|
||||
fail: true,
|
||||
errMessage: fmt.Sprintf("error mounting an image 'remote/path': %v", fmt.Errorf("AddCdrom error")),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
c.state.Put("vm", c.vmMock)
|
||||
if action := c.step.Run(context.TODO(), c.state); action != c.expectedAction {
|
||||
t.Fatalf("unexpected action %v", action)
|
||||
}
|
||||
err, ok := c.state.Get("error").(error)
|
||||
if ok {
|
||||
if err.Error() != c.errMessage {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
if c.fail {
|
||||
t.Fatalf("expected to fail but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(c.vmMock, c.expectedVmMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected VirtualMachine calls: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func cdAndIsoRemotePathStateBag() *multistep.BasicStateBag {
|
||||
state := basicStateBag(nil)
|
||||
state.Put("iso_remote_path", "remote/path")
|
||||
state.Put("cd_path", "cd/path")
|
||||
return state
|
||||
}
|
||||
|
||||
func isoRemotePathStateBag() *multistep.BasicStateBag {
|
||||
state := basicStateBag(nil)
|
||||
state.Put("iso_remote_path", "remote/path")
|
||||
return state
|
||||
}
|
|
@ -1,453 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func TestStepAddFloppy_Run(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
floppyPath string
|
||||
uploadedPath string
|
||||
step *StepAddFloppy
|
||||
expectedAction multistep.StepAction
|
||||
vmMock *driver.VirtualMachineMock
|
||||
expectedVmMock *driver.VirtualMachineMock
|
||||
driverMock *driver.DriverMock
|
||||
expectedDriverMock *driver.DriverMock
|
||||
dsMock *driver.DatastoreMock
|
||||
expectedDsMock *driver.DatastoreMock
|
||||
fail bool
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "Add floppy from state floppy path",
|
||||
floppyPath: "floppy/path",
|
||||
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
step: &StepAddFloppy{
|
||||
Config: new(FloppyConfig),
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
SetHostForDatastoreUploads: true,
|
||||
},
|
||||
expectedAction: multistep.ActionContinue,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
GetDirResponse: "vm/dir",
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
GetDirResponse: "vm/dir",
|
||||
GetDirCalled: true,
|
||||
AddFloppyCalled: true,
|
||||
AddFloppyImagePath: "resolved/path",
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: &driver.DatastoreMock{
|
||||
ResolvePathReturn: "resolved/path",
|
||||
},
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
UploadFileCalled: true,
|
||||
UploadFileSrc: "floppy/path",
|
||||
UploadFileDst: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
UploadFileHost: "host",
|
||||
UploadFileSetHost: true,
|
||||
ResolvePathCalled: true,
|
||||
ResolvePathReturn: "resolved/path",
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "State floppy path - find datastore fail",
|
||||
floppyPath: "floppy/path",
|
||||
step: &StepAddFloppy{
|
||||
Config: new(FloppyConfig),
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
SetHostForDatastoreUploads: true,
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: new(driver.VirtualMachineMock),
|
||||
driverMock: &driver.DriverMock{
|
||||
FindDatastoreErr: fmt.Errorf("error finding datastore"),
|
||||
},
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: true,
|
||||
errMessage: "error finding datastore",
|
||||
},
|
||||
{
|
||||
name: "State floppy path - vm get dir fail",
|
||||
floppyPath: "floppy/path",
|
||||
step: &StepAddFloppy{
|
||||
Config: new(FloppyConfig),
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
SetHostForDatastoreUploads: true,
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
GetDirErr: fmt.Errorf("fail to get vm dir"),
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
GetDirCalled: true,
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: true,
|
||||
errMessage: "fail to get vm dir",
|
||||
},
|
||||
{
|
||||
name: "State floppy path - datastore upload file fail",
|
||||
floppyPath: "floppy/path",
|
||||
step: &StepAddFloppy{
|
||||
Config: new(FloppyConfig),
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
SetHostForDatastoreUploads: true,
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
GetDirResponse: "vm/dir",
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
GetDirResponse: "vm/dir",
|
||||
GetDirCalled: true,
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: &driver.DatastoreMock{
|
||||
UploadFileErr: fmt.Errorf("failed to upload file"),
|
||||
},
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
UploadFileCalled: true,
|
||||
UploadFileSrc: "floppy/path",
|
||||
UploadFileDst: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
UploadFileHost: "host",
|
||||
UploadFileSetHost: true,
|
||||
},
|
||||
fail: true,
|
||||
errMessage: "failed to upload file",
|
||||
},
|
||||
{
|
||||
name: "State floppy path - vm fail to add floppy",
|
||||
floppyPath: "floppy/path",
|
||||
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
step: &StepAddFloppy{
|
||||
Config: new(FloppyConfig),
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
SetHostForDatastoreUploads: true,
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
GetDirResponse: "vm/dir",
|
||||
AddFloppyErr: fmt.Errorf("failed to add floppy"),
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
GetDirResponse: "vm/dir",
|
||||
GetDirCalled: true,
|
||||
AddFloppyCalled: true,
|
||||
AddFloppyImagePath: "resolved/path",
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: &driver.DatastoreMock{
|
||||
ResolvePathReturn: "resolved/path",
|
||||
},
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
UploadFileCalled: true,
|
||||
UploadFileSrc: "floppy/path",
|
||||
UploadFileDst: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
UploadFileHost: "host",
|
||||
UploadFileSetHost: true,
|
||||
ResolvePathCalled: true,
|
||||
ResolvePathReturn: "resolved/path",
|
||||
},
|
||||
fail: true,
|
||||
errMessage: "failed to add floppy",
|
||||
},
|
||||
{
|
||||
name: "Add floppy from FloppyIMGPath config",
|
||||
step: &StepAddFloppy{
|
||||
Config: &FloppyConfig{
|
||||
FloppyIMGPath: "floppy/image/path",
|
||||
},
|
||||
},
|
||||
expectedAction: multistep.ActionContinue,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
AddFloppyCalled: true,
|
||||
AddFloppyImagePath: "floppy/image/path",
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: new(driver.DriverMock),
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Fail to add floppy from FloppyIMGPath config",
|
||||
step: &StepAddFloppy{
|
||||
Config: &FloppyConfig{
|
||||
FloppyIMGPath: "floppy/image/path",
|
||||
},
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
AddFloppyErr: fmt.Errorf("fail to add floppy"),
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
AddFloppyCalled: true,
|
||||
AddFloppyImagePath: "floppy/image/path",
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: new(driver.DriverMock),
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: true,
|
||||
errMessage: "fail to add floppy",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
state := basicStateBag(nil)
|
||||
state.Put("vm", c.vmMock)
|
||||
c.driverMock.DatastoreMock = c.dsMock
|
||||
state.Put("driver", c.driverMock)
|
||||
|
||||
if c.floppyPath != "" {
|
||||
state.Put("floppy_path", c.floppyPath)
|
||||
}
|
||||
|
||||
if action := c.step.Run(context.TODO(), state); action != c.expectedAction {
|
||||
t.Fatalf("unexpected action %v", action)
|
||||
}
|
||||
err, ok := state.Get("error").(error)
|
||||
if ok {
|
||||
if err.Error() != c.errMessage {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
if c.fail {
|
||||
t.Fatalf("expected to fail but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
uploadedPath, _ := state.Get("uploaded_floppy_path").(string)
|
||||
if uploadedPath != c.uploadedPath {
|
||||
t.Fatalf("Unexpected uploaded path state %s", uploadedPath)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(c.vmMock, c.expectedVmMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected VirtualMachine calls: %s", diff)
|
||||
}
|
||||
c.expectedDriverMock.DatastoreMock = c.expectedDsMock
|
||||
if diff := cmp.Diff(c.driverMock, c.expectedDriverMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected Driver calls: %s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(c.dsMock, c.expectedDsMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected Datastore calls: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepAddFloppy_Cleanup(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
uploadedPath string
|
||||
multistepState string
|
||||
step *StepAddFloppy
|
||||
driverMock *driver.DriverMock
|
||||
expectedDriverMock *driver.DriverMock
|
||||
dsMock *driver.DatastoreMock
|
||||
expectedDsMock *driver.DatastoreMock
|
||||
fail bool
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "State cancelled clean up",
|
||||
uploadedPath: "uploaded/path",
|
||||
multistepState: multistep.StateCancelled,
|
||||
step: &StepAddFloppy{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
},
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
DeletePath: "uploaded/path",
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "State halted clean up",
|
||||
uploadedPath: "uploaded/path",
|
||||
multistepState: multistep.StateHalted,
|
||||
step: &StepAddFloppy{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
},
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
DeletePath: "uploaded/path",
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Don't clean up without uploaded path",
|
||||
multistepState: multistep.StateHalted,
|
||||
step: new(StepAddFloppy),
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: new(driver.DriverMock),
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Don't clean up if state is not halted or canceled",
|
||||
multistepState: "",
|
||||
step: new(StepAddFloppy),
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: new(driver.DriverMock),
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Fail because datastore is not found",
|
||||
uploadedPath: "uploaded/path",
|
||||
multistepState: multistep.StateHalted,
|
||||
step: &StepAddFloppy{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
},
|
||||
driverMock: &driver.DriverMock{
|
||||
FindDatastoreErr: fmt.Errorf("fail to find datastore"),
|
||||
},
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: true,
|
||||
errMessage: "fail to find datastore",
|
||||
},
|
||||
{
|
||||
name: "Fail to delete floppy",
|
||||
uploadedPath: "uploaded/path",
|
||||
multistepState: multistep.StateHalted,
|
||||
step: &StepAddFloppy{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
DeleteErr: fmt.Errorf("failed to delete floppy"),
|
||||
},
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
DeletePath: "uploaded/path",
|
||||
},
|
||||
fail: true,
|
||||
errMessage: "failed to delete floppy",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
state := basicStateBag(nil)
|
||||
c.driverMock.DatastoreMock = c.dsMock
|
||||
state.Put("driver", c.driverMock)
|
||||
if c.uploadedPath != "" {
|
||||
state.Put("uploaded_floppy_path", c.uploadedPath)
|
||||
}
|
||||
|
||||
if c.multistepState != "" {
|
||||
state.Put(c.multistepState, true)
|
||||
}
|
||||
|
||||
c.step.Cleanup(state)
|
||||
err, ok := state.Get("error").(error)
|
||||
if ok {
|
||||
if err.Error() != c.errMessage {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
if c.fail {
|
||||
t.Fatalf("expected to fail but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
c.expectedDriverMock.DatastoreMock = c.expectedDsMock
|
||||
if diff := cmp.Diff(c.driverMock, c.expectedDriverMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected Driver calls: %s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(c.dsMock, c.expectedDsMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected Datastore calls: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
/// create mock step
|
||||
type MockDownloadStep struct {
|
||||
RunCalled bool
|
||||
}
|
||||
|
||||
func (s *MockDownloadStep) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.RunCalled = true
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *MockDownloadStep) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
func (s *MockDownloadStep) UseSourceToFindCacheTarget(source string) (*url.URL, string, error) {
|
||||
return nil, "sometarget", nil
|
||||
}
|
||||
|
||||
/// start tests
|
||||
func downloadStepState(exists bool) *multistep.BasicStateBag {
|
||||
state := basicStateBag(nil)
|
||||
dsMock := &driver.DatastoreMock{
|
||||
FileExistsReturn: exists,
|
||||
}
|
||||
driverMock := &driver.DriverMock{
|
||||
DatastoreMock: dsMock,
|
||||
}
|
||||
state.Put("driver", driverMock)
|
||||
return state
|
||||
}
|
||||
|
||||
func TestStepDownload_Run(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
filePresent bool
|
||||
expectedAction multistep.StepAction
|
||||
expectInternalStepCalled bool
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "Remote iso present; download shouldn't be called",
|
||||
filePresent: true,
|
||||
expectedAction: multistep.ActionContinue,
|
||||
expectInternalStepCalled: false,
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Remote iso not present; download should be called",
|
||||
filePresent: false,
|
||||
expectedAction: multistep.ActionContinue,
|
||||
expectInternalStepCalled: true,
|
||||
errMessage: "",
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
internalStep := &MockDownloadStep{}
|
||||
state := downloadStepState(tc.filePresent)
|
||||
step := &StepDownload{
|
||||
DownloadStep: internalStep,
|
||||
Url: []string{"https://path/to/fake-url.iso"},
|
||||
Datastore: "datastore-mock",
|
||||
Host: "fake-host",
|
||||
}
|
||||
stepAction := step.Run(context.TODO(), state)
|
||||
if stepAction != tc.expectedAction {
|
||||
t.Fatalf("%s: Recieved wrong step action; step exists, should return early.", tc.name)
|
||||
}
|
||||
if tc.expectInternalStepCalled != internalStep.RunCalled {
|
||||
if tc.expectInternalStepCalled {
|
||||
t.Fatalf("%s: Expected internal download step to be called", tc.name)
|
||||
} else {
|
||||
t.Fatalf("%s: Expected internal download step not to be called", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func TestHardwareConfig_Prepare(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
config *HardwareConfig
|
||||
fail bool
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "Validate empty config",
|
||||
config: &HardwareConfig{},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Validate RAMReservation RAMReserveAll cannot be used together",
|
||||
config: &HardwareConfig{
|
||||
RAMReservation: 2,
|
||||
RAMReserveAll: true,
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "'RAM_reservation' and 'RAM_reserve_all' cannot be used together",
|
||||
},
|
||||
{
|
||||
name: "Invalid firmware",
|
||||
config: &HardwareConfig{
|
||||
Firmware: "invalid",
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "'firmware' must be '', 'bios', 'efi' or 'efi-secure'",
|
||||
},
|
||||
{
|
||||
name: "Validate 'bios' firmware",
|
||||
config: &HardwareConfig{
|
||||
Firmware: "bios",
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Validate 'efi' firmware",
|
||||
config: &HardwareConfig{
|
||||
Firmware: "efi",
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Validate 'efi-secure' firmware",
|
||||
config: &HardwareConfig{
|
||||
Firmware: "efi-secure",
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepConfigureHardware_Run(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
step *StepConfigureHardware
|
||||
action multistep.StepAction
|
||||
configureError error
|
||||
configureCalled bool
|
||||
hardwareConfig *driver.HardwareConfig
|
||||
}{
|
||||
{
|
||||
name: "Configure hardware",
|
||||
step: basicStepConfigureHardware(),
|
||||
action: multistep.ActionContinue,
|
||||
configureError: nil,
|
||||
configureCalled: true,
|
||||
hardwareConfig: driverHardwareConfigFromConfig(basicStepConfigureHardware().Config),
|
||||
},
|
||||
{
|
||||
name: "Don't configure hardware when config is empty",
|
||||
step: &StepConfigureHardware{Config: &HardwareConfig{}},
|
||||
action: multistep.ActionContinue,
|
||||
configureError: nil,
|
||||
configureCalled: false,
|
||||
},
|
||||
{
|
||||
name: "Halt when configure return error",
|
||||
step: basicStepConfigureHardware(),
|
||||
action: multistep.ActionHalt,
|
||||
configureError: errors.New("failed to configure"),
|
||||
configureCalled: true,
|
||||
hardwareConfig: driverHardwareConfigFromConfig(basicStepConfigureHardware().Config),
|
||||
},
|
||||
}
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
state := basicStateBag(nil)
|
||||
vmMock := new(driver.VirtualMachineMock)
|
||||
vmMock.ConfigureError = c.configureError
|
||||
state.Put("vm", vmMock)
|
||||
|
||||
action := c.step.Run(context.TODO(), state)
|
||||
if action != c.action {
|
||||
t.Fatalf("expected action '%v' but actual action was '%v'", c.action, action)
|
||||
}
|
||||
if vmMock.ConfigureCalled != c.configureCalled {
|
||||
t.Fatalf("expecting vm.Configure called to %t but was %t", c.configureCalled, vmMock.ConfigureCalled)
|
||||
}
|
||||
if diff := cmp.Diff(vmMock.ConfigureHardwareConfig, c.hardwareConfig); diff != "" {
|
||||
t.Fatalf("wrong driver.HardwareConfig: %s", diff)
|
||||
}
|
||||
|
||||
err, ok := state.GetOk("error")
|
||||
containsError := c.configureError != nil
|
||||
if containsError != ok {
|
||||
t.Fatalf("Contain error - expecting %t but was %t", containsError, ok)
|
||||
}
|
||||
if containsError {
|
||||
if !strings.Contains(err.(error).Error(), c.configureError.Error()) {
|
||||
t.Fatalf("Destroy should fail with error message '%s' but failed with '%s'", c.configureError.Error(), err.(error).Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func basicStepConfigureHardware() *StepConfigureHardware {
|
||||
return &StepConfigureHardware{
|
||||
Config: &HardwareConfig{
|
||||
CPUs: 1,
|
||||
CpuCores: 1,
|
||||
CPUReservation: 1,
|
||||
CPULimit: 4000,
|
||||
RAM: 1024,
|
||||
RAMReserveAll: true,
|
||||
Firmware: "efi-secure",
|
||||
ForceBIOSSetup: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func driverHardwareConfigFromConfig(config *HardwareConfig) *driver.HardwareConfig {
|
||||
return &driver.HardwareConfig{
|
||||
CPUs: config.CPUs,
|
||||
CpuCores: config.CpuCores,
|
||||
CPUReservation: config.CPUReservation,
|
||||
CPULimit: config.CPULimit,
|
||||
RAM: config.RAM,
|
||||
RAMReservation: config.RAMReservation,
|
||||
RAMReserveAll: config.RAMReserveAll,
|
||||
NestedHV: config.NestedHV,
|
||||
CpuHotAddEnabled: config.CpuHotAddEnabled,
|
||||
MemoryHotAddEnabled: config.MemoryHotAddEnabled,
|
||||
VideoRAM: config.VideoRAM,
|
||||
VGPUProfile: config.VGPUProfile,
|
||||
Firmware: config.Firmware,
|
||||
ForceBIOSSetup: config.ForceBIOSSetup,
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
)
|
||||
|
||||
func TestStepHTTPIPDiscover_Run(t *testing.T) {
|
||||
state := new(multistep.BasicStateBag)
|
||||
step := new(StepHTTPIPDiscover)
|
||||
|
||||
// without setting HTTPIP
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
if _, ok := state.GetOk("error"); ok {
|
||||
t.Fatal("should NOT have error")
|
||||
}
|
||||
_, ok := state.GetOk("http_ip")
|
||||
if !ok {
|
||||
t.Fatal("should have http_ip")
|
||||
}
|
||||
|
||||
// setting HTTPIP
|
||||
ip := "10.0.2.2"
|
||||
step = &StepHTTPIPDiscover{
|
||||
HTTPIP: ip,
|
||||
}
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
if _, ok := state.GetOk("error"); ok {
|
||||
t.Fatal("should NOT have error")
|
||||
}
|
||||
httpIp, ok := state.GetOk("http_ip")
|
||||
if !ok {
|
||||
t.Fatal("should have http_ip")
|
||||
}
|
||||
if httpIp != ip {
|
||||
t.Fatalf("bad: Http ip is %s but was supposed to be %s", httpIp, ip)
|
||||
}
|
||||
|
||||
_, ipNet, err := net.ParseCIDR("0.0.0.0/0")
|
||||
if err != nil {
|
||||
t.Fatal("error getting ipNet", err)
|
||||
}
|
||||
step = new(StepHTTPIPDiscover)
|
||||
step.Network = ipNet
|
||||
|
||||
// without setting HTTPIP with Network
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
if _, ok := state.GetOk("error"); ok {
|
||||
t.Fatal("should NOT have error")
|
||||
}
|
||||
_, ok = state.GetOk("http_ip")
|
||||
if !ok {
|
||||
t.Fatal("should have http_ip")
|
||||
}
|
||||
|
||||
// setting HTTPIP with Network
|
||||
step = &StepHTTPIPDiscover{
|
||||
HTTPIP: ip,
|
||||
Network: ipNet,
|
||||
}
|
||||
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
if _, ok := state.GetOk("error"); ok {
|
||||
t.Fatal("should NOT have error")
|
||||
}
|
||||
httpIp, ok = state.GetOk("http_ip")
|
||||
if !ok {
|
||||
t.Fatal("should have http_ip")
|
||||
}
|
||||
if httpIp != ip {
|
||||
t.Fatalf("bad: Http ip is %s but was supposed to be %s", httpIp, ip)
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func TestStepRemoteUpload_Run(t *testing.T) {
|
||||
state := basicStateBag(nil)
|
||||
dsMock := driver.DatastoreMock{
|
||||
DirExistsReturn: false,
|
||||
}
|
||||
driverMock := driver.NewDriverMock()
|
||||
driverMock.DatastoreMock = &dsMock
|
||||
state.Put("driver", driverMock)
|
||||
state.Put("iso_path", "[datastore] iso/path")
|
||||
|
||||
step := &StepRemoteUpload{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
SetHostForDatastoreUploads: false,
|
||||
}
|
||||
|
||||
if action := step.Run(context.TODO(), state); action == multistep.ActionHalt {
|
||||
t.Fatalf("Should not halt.")
|
||||
}
|
||||
|
||||
if !driverMock.FindDatastoreCalled {
|
||||
t.Fatalf("driver.FindDatastore should be called.")
|
||||
}
|
||||
if !driverMock.DatastoreMock.FileExistsCalled {
|
||||
t.Fatalf("datastore.FindDatastore should be called.")
|
||||
}
|
||||
if !driverMock.DatastoreMock.MakeDirectoryCalled {
|
||||
t.Fatalf("datastore.MakeDirectory should be called.")
|
||||
}
|
||||
if !driverMock.DatastoreMock.UploadFileCalled {
|
||||
t.Fatalf("datastore.UploadFile should be called.")
|
||||
}
|
||||
remotePath, ok := state.GetOk("iso_remote_path")
|
||||
if !ok {
|
||||
t.Fatalf("state should contain iso_remote_path")
|
||||
}
|
||||
expectedRemovePath := fmt.Sprintf("[%s] packer_cache//path", driverMock.DatastoreMock.Name())
|
||||
if remotePath != expectedRemovePath {
|
||||
t.Fatalf("iso_remote_path expected to be %s but was %s", expectedRemovePath, remotePath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepRemoteUpload_SkipRun(t *testing.T) {
|
||||
state := basicStateBag(nil)
|
||||
driverMock := driver.NewDriverMock()
|
||||
state.Put("driver", driverMock)
|
||||
|
||||
step := &StepRemoteUpload{}
|
||||
|
||||
if action := step.Run(context.TODO(), state); action == multistep.ActionHalt {
|
||||
t.Fatalf("Should not halt.")
|
||||
}
|
||||
|
||||
if driverMock.FindDatastoreCalled {
|
||||
t.Fatalf("driver.FindDatastore should not be called.")
|
||||
}
|
||||
if _, ok := state.GetOk("iso_remote_path"); ok {
|
||||
t.Fatalf("state should not contain iso_remote_path")
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func TestStepRemoveCDRom_Run(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
step *StepRemoveCDRom
|
||||
expectedAction multistep.StepAction
|
||||
vmMock *driver.VirtualMachineMock
|
||||
expectedVmMock *driver.VirtualMachineMock
|
||||
fail bool
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "Eject CD-ROM drives",
|
||||
step: &StepRemoveCDRom{
|
||||
Config: &RemoveCDRomConfig{},
|
||||
},
|
||||
expectedAction: multistep.ActionContinue,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
EjectCdromsCalled: true,
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Failed to eject CD-ROM drives",
|
||||
step: &StepRemoveCDRom{
|
||||
Config: &RemoveCDRomConfig{},
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
EjectCdromsErr: fmt.Errorf("failed to eject cd-rom drives"),
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
EjectCdromsCalled: true,
|
||||
},
|
||||
fail: true,
|
||||
errMessage: "failed to eject cd-rom drives",
|
||||
},
|
||||
{
|
||||
name: "Eject and delete CD-ROM drives",
|
||||
step: &StepRemoveCDRom{
|
||||
Config: &RemoveCDRomConfig{
|
||||
RemoveCdrom: true,
|
||||
},
|
||||
},
|
||||
expectedAction: multistep.ActionContinue,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
EjectCdromsCalled: true,
|
||||
RemoveCdromsCalled: true,
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Fail to delete CD-ROM drives",
|
||||
step: &StepRemoveCDRom{
|
||||
Config: &RemoveCDRomConfig{
|
||||
RemoveCdrom: true,
|
||||
},
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
RemoveCdromsErr: fmt.Errorf("failed to delete cd-rom devices"),
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
EjectCdromsCalled: true,
|
||||
RemoveCdromsCalled: true,
|
||||
},
|
||||
fail: true,
|
||||
errMessage: "failed to delete cd-rom devices",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
state := basicStateBag(nil)
|
||||
state.Put("vm", c.vmMock)
|
||||
|
||||
if action := c.step.Run(context.TODO(), state); action != c.expectedAction {
|
||||
t.Fatalf("unexpected action %v", action)
|
||||
}
|
||||
err, ok := state.Get("error").(error)
|
||||
if ok {
|
||||
if err.Error() != c.errMessage {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
if c.fail {
|
||||
t.Fatalf("expected to fail but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(c.vmMock, c.expectedVmMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected VirtualMachine calls: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func TestStepRemoveFloppy_Run(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
uploadedPath string
|
||||
step *StepRemoveFloppy
|
||||
expectedAction multistep.StepAction
|
||||
vmMock *driver.VirtualMachineMock
|
||||
expectedVmMock *driver.VirtualMachineMock
|
||||
driverMock *driver.DriverMock
|
||||
expectedDriverMock *driver.DriverMock
|
||||
dsMock *driver.DatastoreMock
|
||||
expectedDsMock *driver.DatastoreMock
|
||||
fail bool
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "Remove floppy drives and images",
|
||||
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
step: &StepRemoveFloppy{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
},
|
||||
expectedAction: multistep.ActionContinue,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FloppyDevicesCalled: true,
|
||||
RemoveDeviceCalled: true,
|
||||
RemoveDeviceKeepFiles: true,
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
DeletePath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "No floppy image to remove",
|
||||
step: &StepRemoveFloppy{},
|
||||
expectedAction: multistep.ActionContinue,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FloppyDevicesCalled: true,
|
||||
RemoveDeviceCalled: true,
|
||||
RemoveDeviceKeepFiles: true,
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: new(driver.DriverMock),
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "Fail to find floppy devices",
|
||||
step: &StepRemoveFloppy{},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
FloppyDevicesErr: fmt.Errorf("failed to find floppy devices"),
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FloppyDevicesCalled: true,
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: new(driver.DriverMock),
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: true,
|
||||
errMessage: "failed to find floppy devices",
|
||||
},
|
||||
{
|
||||
name: "Fail to remove floppy devices",
|
||||
step: &StepRemoveFloppy{},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: &driver.VirtualMachineMock{
|
||||
RemoveDeviceErr: fmt.Errorf("failed to remove device"),
|
||||
},
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FloppyDevicesCalled: true,
|
||||
RemoveDeviceCalled: true,
|
||||
RemoveDeviceKeepFiles: true,
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: new(driver.DriverMock),
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: true,
|
||||
errMessage: "failed to remove device",
|
||||
},
|
||||
{
|
||||
name: "Fail to find datastore",
|
||||
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
step: &StepRemoveFloppy{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FloppyDevicesCalled: true,
|
||||
RemoveDeviceCalled: true,
|
||||
RemoveDeviceKeepFiles: true,
|
||||
},
|
||||
driverMock: &driver.DriverMock{
|
||||
FindDatastoreErr: fmt.Errorf("failed to find datastore"),
|
||||
},
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: new(driver.DatastoreMock),
|
||||
expectedDsMock: new(driver.DatastoreMock),
|
||||
fail: true,
|
||||
errMessage: "failed to find datastore",
|
||||
},
|
||||
{
|
||||
name: "Fail to delete floppy image",
|
||||
uploadedPath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
step: &StepRemoveFloppy{
|
||||
Datastore: "datastore",
|
||||
Host: "host",
|
||||
},
|
||||
expectedAction: multistep.ActionHalt,
|
||||
vmMock: new(driver.VirtualMachineMock),
|
||||
expectedVmMock: &driver.VirtualMachineMock{
|
||||
FloppyDevicesCalled: true,
|
||||
RemoveDeviceCalled: true,
|
||||
RemoveDeviceKeepFiles: true,
|
||||
},
|
||||
driverMock: new(driver.DriverMock),
|
||||
expectedDriverMock: &driver.DriverMock{
|
||||
FindDatastoreCalled: true,
|
||||
FindDatastoreName: "datastore",
|
||||
FindDatastoreHost: "host",
|
||||
},
|
||||
dsMock: &driver.DatastoreMock{
|
||||
DeleteErr: fmt.Errorf("failed to delete floppy"),
|
||||
},
|
||||
expectedDsMock: &driver.DatastoreMock{
|
||||
DeleteCalled: true,
|
||||
DeletePath: "vm/dir/packer-tmp-created-floppy.flp",
|
||||
},
|
||||
fail: true,
|
||||
errMessage: "failed to delete floppy",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
state := basicStateBag(nil)
|
||||
state.Put("vm", c.vmMock)
|
||||
c.driverMock.DatastoreMock = c.dsMock
|
||||
state.Put("driver", c.driverMock)
|
||||
|
||||
if c.uploadedPath != "" {
|
||||
state.Put("uploaded_floppy_path", c.uploadedPath)
|
||||
}
|
||||
|
||||
if action := c.step.Run(context.TODO(), state); action != c.expectedAction {
|
||||
t.Fatalf("unexpected action %v", action)
|
||||
}
|
||||
err, ok := state.Get("error").(error)
|
||||
if ok {
|
||||
if err.Error() != c.errMessage {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
if c.fail {
|
||||
t.Fatalf("expected to fail but it didn't")
|
||||
}
|
||||
}
|
||||
|
||||
if !c.fail {
|
||||
if _, ok := state.GetOk("uploaded_floppy_path"); ok {
|
||||
t.Fatalf("uploaded_floppy_path should not be in state")
|
||||
}
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(c.vmMock, c.expectedVmMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected VirtualMachine calls: %s", diff)
|
||||
}
|
||||
c.expectedDriverMock.DatastoreMock = c.expectedDsMock
|
||||
if diff := cmp.Diff(c.driverMock, c.expectedDriverMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected Driver calls: %s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(c.dsMock, c.expectedDsMock,
|
||||
cmpopts.IgnoreInterfaces(struct{ error }{})); diff != "" {
|
||||
t.Fatalf("unexpected Datastore calls: %s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package testing
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func NewVMName() string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return fmt.Sprintf("test-%v", rand.Intn(1000))
|
||||
}
|
||||
|
||||
func RenderConfig(config map[string]interface{}) string {
|
||||
t := map[string][]map[string]interface{}{
|
||||
"builders": {
|
||||
map[string]interface{}{
|
||||
"type": "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range config {
|
||||
t["builders"][0][k] = v
|
||||
}
|
||||
|
||||
j, _ := json.Marshal(t)
|
||||
return string(j)
|
||||
}
|
||||
|
||||
func TestConn(t *testing.T) driver.Driver {
|
||||
username := os.Getenv("VSPHERE_USERNAME")
|
||||
if username == "" {
|
||||
username = "root"
|
||||
}
|
||||
password := os.Getenv("VSPHERE_PASSWORD")
|
||||
if password == "" {
|
||||
password = "jetbrains"
|
||||
}
|
||||
|
||||
d, err := driver.NewDriver(&driver.ConnectConfig{
|
||||
VCenterServer: "vcenter.vsphere65.test",
|
||||
Username: username,
|
||||
Password: password,
|
||||
InsecureConnection: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("Cannot connect: ", err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func GetVM(t *testing.T, d driver.Driver, artifacts []packersdk.Artifact) driver.VirtualMachine {
|
||||
artifactRaw := artifacts[0]
|
||||
artifact, _ := artifactRaw.(*common.Artifact)
|
||||
|
||||
vm, err := d.FindVM(artifact.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find VM: %v", err)
|
||||
}
|
||||
|
||||
return vm
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDatastoreAcc(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
d := newTestDriver(t)
|
||||
ds, err := d.FindDatastore("datastore1", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find the default datastore '%v': %v", "datastore1", err)
|
||||
}
|
||||
info, err := ds.Info("name")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read datastore properties: %v", err)
|
||||
}
|
||||
if info.Name != "datastore1" {
|
||||
t.Errorf("Wrong datastore. expected: 'datastore1', got: '%v'", info.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileUpload(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
dsName := "datastore1"
|
||||
hostName := "esxi-1.vsphere65.test"
|
||||
|
||||
fileName := fmt.Sprintf("test-%v", time.Now().Unix())
|
||||
tmpFile, err := ioutil.TempFile("", fileName)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating temp file")
|
||||
}
|
||||
err = tmpFile.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating temp file")
|
||||
}
|
||||
|
||||
d := newTestDriver(t)
|
||||
ds, err := d.FindDatastore(dsName, hostName)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find datastore '%v': %v", dsName, err)
|
||||
}
|
||||
|
||||
err = ds.UploadFile(tmpFile.Name(), fileName, hostName, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot upload file: %v", err)
|
||||
}
|
||||
|
||||
if ds.FileExists(fileName) != true {
|
||||
t.Fatalf("Cannot find file")
|
||||
}
|
||||
|
||||
err = ds.Delete(fileName)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot delete file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileUploadDRS(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
dsName := "datastore3"
|
||||
hostName := ""
|
||||
|
||||
fileName := fmt.Sprintf("test-%v", time.Now().Unix())
|
||||
tmpFile, err := ioutil.TempFile("", fileName)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating temp file")
|
||||
}
|
||||
err = tmpFile.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating temp file")
|
||||
}
|
||||
|
||||
d := newTestDriver(t)
|
||||
ds, err := d.FindDatastore(dsName, hostName)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find datastore '%v': %v", dsName, err)
|
||||
}
|
||||
|
||||
err = ds.UploadFile(tmpFile.Name(), fileName, hostName, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot upload file: %v", err)
|
||||
}
|
||||
|
||||
if ds.FileExists(fileName) != true {
|
||||
t.Fatalf("Cannot find file")
|
||||
}
|
||||
|
||||
err = ds.Delete(fileName)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot delete file: %v", err)
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator"
|
||||
)
|
||||
|
||||
func TestDatastoreIsoPath(t *testing.T) {
|
||||
tc := []struct {
|
||||
isoPath string
|
||||
filePath string
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
isoPath: "[datastore] dir/subdir/file",
|
||||
filePath: "dir/subdir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: "[] dir/subdir/file",
|
||||
filePath: "dir/subdir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: "dir/subdir/file",
|
||||
filePath: "dir/subdir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: "[datastore] /dir/subdir/file",
|
||||
filePath: "/dir/subdir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: "/dir/subdir/file [datastore] ",
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
isoPath: "[datastore][] /dir/subdir/file",
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
isoPath: "[data/store] /dir/subdir/file",
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
isoPath: "[data store] /dir/sub dir/file",
|
||||
filePath: "/dir/sub dir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: " [datastore] /dir/subdir/file",
|
||||
filePath: "/dir/subdir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: "[datastore] /dir/subdir/file",
|
||||
filePath: "/dir/subdir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: "[datastore] /dir/subdir/file ",
|
||||
filePath: "/dir/subdir/file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
isoPath: "[привѣ́тъ] /привѣ́тъ/привѣ́тъ/привѣ́тъ",
|
||||
filePath: "/привѣ́тъ/привѣ́тъ/привѣ́тъ",
|
||||
valid: true,
|
||||
},
|
||||
// Test case for #9846
|
||||
{
|
||||
isoPath: "[ISO-StorageLun9] Linux/rhel-8.0-x86_64-dvd.iso",
|
||||
filePath: "Linux/rhel-8.0-x86_64-dvd.iso",
|
||||
valid: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range tc {
|
||||
dsIsoPath := &DatastoreIsoPath{path: c.isoPath}
|
||||
if dsIsoPath.Validate() != c.valid {
|
||||
t.Fatalf("%d Expecting %s to be %t but was %t", i, c.isoPath, c.valid, !c.valid)
|
||||
}
|
||||
if !c.valid {
|
||||
continue
|
||||
}
|
||||
filePath := dsIsoPath.GetFilePath()
|
||||
if filePath != c.filePath {
|
||||
t.Fatalf("%d Expecting %s but got %s", i, c.filePath, filePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVCenterDriver_FindDatastore(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
_, datastore := sim.ChooseSimulatorPreCreatedDatastore()
|
||||
_, host := sim.ChooseSimulatorPreCreatedHost()
|
||||
|
||||
tc := []struct {
|
||||
name string
|
||||
datastore string
|
||||
host string
|
||||
fail bool
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "should find datastore when name is provided",
|
||||
datastore: datastore.Name,
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "should find datastore when only host is provided",
|
||||
host: host.Name,
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "should not find invalid datastore",
|
||||
datastore: "invalid",
|
||||
fail: true,
|
||||
},
|
||||
{
|
||||
name: "should not find invalid host",
|
||||
host: "invalid",
|
||||
fail: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
ds, err := sim.driver.FindDatastore(c.datastore, c.host)
|
||||
if c.fail {
|
||||
if err == nil {
|
||||
t.Fatalf("expected to fail")
|
||||
}
|
||||
if c.errMessage != "" && err.Error() != c.errMessage {
|
||||
t.Fatalf("unexpected error message %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if ds == nil {
|
||||
t.Fatalf("expected to find datastore")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVCenterDriver_MultipleDatastoreError(t *testing.T) {
|
||||
model := simulator.ESX()
|
||||
model.Datastore = 2
|
||||
sim, err := NewCustomVCenterSimulator(model)
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
_, host := sim.ChooseSimulatorPreCreatedHost()
|
||||
|
||||
_, err = sim.driver.FindDatastore("", host.Name)
|
||||
if err == nil {
|
||||
t.Fatalf("expected to fail")
|
||||
}
|
||||
if err.Error() != "Host has multiple datastores. Specify it explicitly" {
|
||||
t.Fatalf("unexpected error message %s", err.Error())
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
)
|
||||
|
||||
func TestAddStorageDevices(t *testing.T) {
|
||||
config := &StorageConfig{
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []Disk{
|
||||
{
|
||||
DiskSize: 3072,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
{
|
||||
DiskSize: 20480,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
noExistingDevices := object.VirtualDeviceList{}
|
||||
storageConfigSpec, err := config.AddStorageDevices(noExistingDevices)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected erro: %q", err.Error())
|
||||
}
|
||||
if len(storageConfigSpec) != 3 {
|
||||
t.Fatalf("Expecting VirtualDeviceList to have 3 storage devices but had %d", len(storageConfigSpec))
|
||||
}
|
||||
|
||||
existingDevices := object.VirtualDeviceList{}
|
||||
device, err := existingDevices.CreateNVMEController()
|
||||
existingDevices = append(existingDevices, device)
|
||||
|
||||
storageConfigSpec, err = config.AddStorageDevices(existingDevices)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected erro: %q", err.Error())
|
||||
}
|
||||
if len(storageConfigSpec) != 3 {
|
||||
t.Fatalf("Expecting VirtualDeviceList to have 3 storage devices but had %d", len(storageConfigSpec))
|
||||
}
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi"
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/session"
|
||||
"github.com/vmware/govmomi/simulator"
|
||||
"github.com/vmware/govmomi/vapi/rest"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
)
|
||||
|
||||
// Defines whether acceptance tests should be run
|
||||
const TestHostName = "esxi-1.vsphere65.test"
|
||||
|
||||
func newTestDriver(t *testing.T) Driver {
|
||||
username := os.Getenv("VSPHERE_USERNAME")
|
||||
if username == "" {
|
||||
username = "root"
|
||||
}
|
||||
password := os.Getenv("VSPHERE_PASSWORD")
|
||||
if password == "" {
|
||||
password = "jetbrains"
|
||||
}
|
||||
|
||||
d, err := NewDriver(&ConnectConfig{
|
||||
VCenterServer: "vcenter.vsphere65.test",
|
||||
Username: username,
|
||||
Password: password,
|
||||
InsecureConnection: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot connect: %v", err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func newVMName() string {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
return fmt.Sprintf("test-%v", rand.Intn(1000))
|
||||
}
|
||||
|
||||
type VCenterSimulator struct {
|
||||
model *simulator.Model
|
||||
server *simulator.Server
|
||||
driver *VCenterDriver
|
||||
}
|
||||
|
||||
func NewCustomVCenterSimulator(model *simulator.Model) (*VCenterSimulator, error) {
|
||||
sim := new(VCenterSimulator)
|
||||
sim.model = model
|
||||
|
||||
server, err := sim.NewSimulatorServer()
|
||||
if err != nil {
|
||||
sim.Close()
|
||||
return nil, err
|
||||
}
|
||||
sim.server = server
|
||||
|
||||
driver, err := sim.NewSimulatorDriver()
|
||||
if err != nil {
|
||||
sim.Close()
|
||||
return nil, err
|
||||
}
|
||||
sim.driver = driver
|
||||
return sim, nil
|
||||
}
|
||||
|
||||
func NewVCenterSimulator() (*VCenterSimulator, error) {
|
||||
model := simulator.VPX()
|
||||
model.Machine = 1
|
||||
return NewCustomVCenterSimulator(model)
|
||||
}
|
||||
|
||||
func (s *VCenterSimulator) Close() {
|
||||
if s.model != nil {
|
||||
s.model.Remove()
|
||||
}
|
||||
if s.server != nil {
|
||||
s.server.Close()
|
||||
}
|
||||
}
|
||||
|
||||
//Simulator shortcut to choose any pre created VM.
|
||||
func (s *VCenterSimulator) ChooseSimulatorPreCreatedVM() (VirtualMachine, *simulator.VirtualMachine) {
|
||||
machine := simulator.Map.Any("VirtualMachine").(*simulator.VirtualMachine)
|
||||
ref := machine.Reference()
|
||||
vm := s.driver.NewVM(&ref)
|
||||
return vm, machine
|
||||
}
|
||||
|
||||
//Simulator shortcut to choose any pre created Datastore.
|
||||
func (s *VCenterSimulator) ChooseSimulatorPreCreatedDatastore() (Datastore, *simulator.Datastore) {
|
||||
ds := simulator.Map.Any("Datastore").(*simulator.Datastore)
|
||||
ref := ds.Reference()
|
||||
datastore := s.driver.NewDatastore(&ref)
|
||||
return datastore, ds
|
||||
}
|
||||
|
||||
//Simulator shortcut to choose any pre created Host.
|
||||
func (s *VCenterSimulator) ChooseSimulatorPreCreatedHost() (*Host, *simulator.HostSystem) {
|
||||
h := simulator.Map.Any("HostSystem").(*simulator.HostSystem)
|
||||
ref := h.Reference()
|
||||
host := s.driver.NewHost(&ref)
|
||||
return host, h
|
||||
}
|
||||
|
||||
func (s *VCenterSimulator) NewSimulatorServer() (*simulator.Server, error) {
|
||||
err := s.model.Create()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.model.Service.RegisterEndpoints = true
|
||||
s.model.Service.TLS = new(tls.Config)
|
||||
s.model.Service.ServeMux = http.NewServeMux()
|
||||
return s.model.Service.NewServer(), nil
|
||||
}
|
||||
|
||||
func (s *VCenterSimulator) NewSimulatorDriver() (*VCenterDriver, error) {
|
||||
ctx := context.TODO()
|
||||
user := &url.Userinfo{}
|
||||
s.server.URL.User = user
|
||||
|
||||
soapClient := soap.NewClient(s.server.URL, true)
|
||||
vimClient, err := vim25.NewClient(ctx, soapClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vimClient.RoundTripper = session.KeepAlive(vimClient.RoundTripper, 10*time.Minute)
|
||||
client := &govmomi.Client{
|
||||
Client: vimClient,
|
||||
SessionManager: session.NewManager(vimClient),
|
||||
}
|
||||
|
||||
err = client.SessionManager.Login(ctx, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
finder := find.NewFinder(client.Client, false)
|
||||
datacenter, err := finder.DatacenterOrDefault(ctx, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finder.SetDatacenter(datacenter)
|
||||
|
||||
d := &VCenterDriver{
|
||||
ctx: ctx,
|
||||
client: client,
|
||||
vimClient: vimClient,
|
||||
restClient: &RestClient{
|
||||
client: rest.NewClient(vimClient),
|
||||
credentials: user,
|
||||
},
|
||||
datacenter: datacenter,
|
||||
finder: finder,
|
||||
}
|
||||
return d, nil
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package driver
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFolderAcc(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
d := newTestDriver(t)
|
||||
f, err := d.FindFolder("folder1/folder2")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find the default folder '%v': %v", "folder1/folder2", err)
|
||||
}
|
||||
path, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
if path != "folder1/folder2" {
|
||||
t.Errorf("Wrong folder. expected: 'folder1/folder2', got: '%v'", path)
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHostAcc(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
d := newTestDriver(t)
|
||||
host, err := d.FindHost(TestHostName)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find the default host '%v': %v", "datastore1", err)
|
||||
}
|
||||
|
||||
info, err := host.Info("name")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read host properties: %v", err)
|
||||
}
|
||||
if info.Name != TestHostName {
|
||||
t.Errorf("Wrong host name: expected '%v', got: '%v'", TestHostName, info.Name)
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package driver
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLibraryFilePath(t *testing.T) {
|
||||
tc := []struct {
|
||||
filePath string
|
||||
libraryName string
|
||||
libraryItemName string
|
||||
fileName string
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
filePath: "lib/item/file",
|
||||
libraryName: "lib",
|
||||
libraryItemName: "item",
|
||||
fileName: "file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
filePath: "/lib/item/file",
|
||||
libraryName: "lib",
|
||||
libraryItemName: "item",
|
||||
fileName: "file",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
filePath: "/lib/item/filedir/file",
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
filePath: "/lib/item",
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
filePath: "/lib",
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
libraryFilePath := &LibraryFilePath{path: c.filePath}
|
||||
if err := libraryFilePath.Validate(); err != nil {
|
||||
if c.valid {
|
||||
t.Fatalf("Expecting %s to be valid", c.filePath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
libraryName := libraryFilePath.GetLibraryName()
|
||||
if libraryName != c.libraryName {
|
||||
t.Fatalf("Expecting %s but got %s", c.libraryName, libraryName)
|
||||
}
|
||||
libraryItemName := libraryFilePath.GetLibraryItemName()
|
||||
if libraryItemName != c.libraryItemName {
|
||||
t.Fatalf("Expecting %s but got %s", c.libraryItemName, libraryItemName)
|
||||
}
|
||||
fileName := libraryFilePath.GetFileName()
|
||||
if fileName != c.fileName {
|
||||
t.Fatalf("Expecting %s but got %s", c.fileName, fileName)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package driver
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestResourcePoolAcc(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
d := newTestDriver(t)
|
||||
p, err := d.FindResourcePool("", "esxi-1.vsphere65.test", "pool1/pool2")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find the default resource pool '%v': %v", "pool1/pool2", err)
|
||||
}
|
||||
|
||||
path, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
if path != "pool1/pool2" {
|
||||
t.Errorf("Wrong folder. expected: 'pool1/pool2', got: '%v'", path)
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator"
|
||||
)
|
||||
|
||||
func TestVCenterDriver_FindResourcePool(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
res, err := sim.driver.FindResourcePool("", "DC0_H0", "")
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if res == nil {
|
||||
t.Fatalf("resource pool should not be nil")
|
||||
}
|
||||
expectedResourcePool := "Resources"
|
||||
if res.pool.Name() != expectedResourcePool {
|
||||
t.Fatalf("resource name expected %s but was %s", expectedResourcePool, res.pool.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestVCenterDriver_FindResourcePoolStandaloneESX(t *testing.T) {
|
||||
// standalone ESX host without any vCenter
|
||||
model := simulator.ESX()
|
||||
defer model.Remove()
|
||||
|
||||
opts := simulator.VPX()
|
||||
model.Datastore = opts.Datastore
|
||||
model.Machine = opts.Machine
|
||||
model.Autostart = opts.Autostart
|
||||
model.DelayConfig.Delay = opts.DelayConfig.Delay
|
||||
model.DelayConfig.MethodDelay = opts.DelayConfig.MethodDelay
|
||||
model.DelayConfig.DelayJitter = opts.DelayConfig.DelayJitter
|
||||
|
||||
sim, err := NewCustomVCenterSimulator(model)
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
res, err := sim.driver.FindResourcePool("", "localhost.localdomain", "")
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if res == nil {
|
||||
t.Fatalf("resource pool should not be nil")
|
||||
}
|
||||
expectedResourcePool := "Resources"
|
||||
if res.pool.Name() != expectedResourcePool {
|
||||
t.Fatalf("resource name expected %s but was %s", expectedResourcePool, res.pool.Name())
|
||||
}
|
||||
|
||||
// Invalid resource name should look for default resource pool
|
||||
res, err = sim.driver.FindResourcePool("", "localhost.localdomain", "invalid")
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if res == nil {
|
||||
t.Fatalf("resource pool should not be nil")
|
||||
}
|
||||
if res.pool.Name() != expectedResourcePool {
|
||||
t.Fatalf("resource name expected %s but was %s", expectedResourcePool, res.pool.Name())
|
||||
}
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestVirtualMachineDriver_FindAndAddSATAController(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||
|
||||
_, err = vm.FindSATAController()
|
||||
if err != nil && !strings.Contains(err.Error(), "no available SATA controller") {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("vm should not have sata controller")
|
||||
}
|
||||
|
||||
if err := vm.AddSATAController(); err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
|
||||
sc, err := vm.FindSATAController()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if sc == nil {
|
||||
t.Fatalf("SATA controller wasn't added properly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMachineDriver_CreateAndRemoveCdrom(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||
|
||||
// Add SATA Controller
|
||||
if err := vm.AddSATAController(); err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
|
||||
// Verify if controller was created
|
||||
sc, err := vm.FindSATAController()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if sc == nil {
|
||||
t.Fatalf("SATA controller wasn't added properly")
|
||||
}
|
||||
|
||||
// Create CDROM
|
||||
controller := sc.GetVirtualController()
|
||||
cdrom, err := vm.CreateCdrom(controller)
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if cdrom == nil {
|
||||
t.Fatalf("CDrom wasn't created properly")
|
||||
}
|
||||
|
||||
// Verify if CDROM was created
|
||||
devices, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
cdroms := devices.SelectByType((*types.VirtualCdrom)(nil))
|
||||
if len(cdroms) != 1 {
|
||||
t.Fatalf("unexpected numbers of cdrom: %d", len(cdroms))
|
||||
}
|
||||
|
||||
// Remove CDROM
|
||||
err = vm.RemoveCdroms()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
// Verify if CDROM was removed
|
||||
devices, err = vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
cdroms = devices.SelectByType((*types.VirtualCdrom)(nil))
|
||||
if len(cdroms) != 0 {
|
||||
t.Fatalf("unexpected numbers of cdrom: %d", len(cdroms))
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMachineDriver_EjectCdrom(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||
|
||||
// Add SATA Controller
|
||||
if err := vm.AddSATAController(); err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
|
||||
// Verify if controller was created
|
||||
sc, err := vm.FindSATAController()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if sc == nil {
|
||||
t.Fatalf("SATA controller wasn't added properly")
|
||||
}
|
||||
|
||||
// Create CDROM
|
||||
controller := sc.GetVirtualController()
|
||||
cdrom, err := vm.CreateCdrom(controller)
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
if cdrom == nil {
|
||||
t.Fatalf("CDrom wasn't created properly")
|
||||
}
|
||||
|
||||
// Verify if CDROM was created
|
||||
devices, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
cdroms := devices.SelectByType((*types.VirtualCdrom)(nil))
|
||||
if len(cdroms) != 1 {
|
||||
t.Fatalf("unexpected numbers of cdrom: %d", len(cdroms))
|
||||
}
|
||||
|
||||
// Remove CDROM
|
||||
err = vm.EjectCdroms()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
// Verify if CDROM was removed
|
||||
devices, err = vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
cdroms = devices.SelectByType((*types.VirtualCdrom)(nil))
|
||||
if len(cdroms) != 1 {
|
||||
t.Fatalf("unexpected numbers of cdrom: %d", len(cdroms))
|
||||
}
|
||||
cd, ok := cdroms[0].(*types.VirtualCdrom)
|
||||
if !ok {
|
||||
t.Fatalf("Wrong cdrom type")
|
||||
}
|
||||
if diff := cmp.Diff(cd.Backing, &types.VirtualCdromRemotePassthroughBackingInfo{}); diff != "" {
|
||||
t.Fatalf("Wrong cdrom backing info: %s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(cd.Connectable, &types.VirtualDeviceConnectInfo{}); diff != "" {
|
||||
t.Fatalf("Wrong cdrom connect info: %s", diff)
|
||||
}
|
||||
}
|
|
@ -1,312 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestVMAcc_clone(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
testCases := []struct {
|
||||
name string
|
||||
config *CloneConfig
|
||||
checkFunction func(*testing.T, VirtualMachine, *CloneConfig)
|
||||
}{
|
||||
{"Default", &CloneConfig{}, cloneDefaultCheck},
|
||||
{"LinkedClone", &CloneConfig{LinkedClone: true}, cloneLinkedCloneCheck},
|
||||
{"Folder", &CloneConfig{LinkedClone: true, Folder: "folder1/folder2"}, cloneFolderCheck},
|
||||
{"ResourcePool", &CloneConfig{LinkedClone: true, ResourcePool: "pool1/pool2"}, cloneResourcePoolCheck},
|
||||
{"Configure", &CloneConfig{LinkedClone: true}, configureCheck},
|
||||
{"Configure_RAMReserveAll", &CloneConfig{LinkedClone: true}, configureRAMReserveAllCheck},
|
||||
{"StartAndStop", &CloneConfig{LinkedClone: true}, startAndStopCheck},
|
||||
{"Template", &CloneConfig{LinkedClone: true}, templateCheck},
|
||||
{"Snapshot", &CloneConfig{}, snapshotCheck},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tc.config.Host = TestHostName
|
||||
tc.config.Name = newVMName()
|
||||
|
||||
templateName := "alpine"
|
||||
d := newTestDriver(t)
|
||||
|
||||
template, err := d.FindVM(templateName) // Don't destroy this VM!
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot find template vm '%v': %v", templateName, err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Clonning VM")
|
||||
vm, err := template.Clone(context.TODO(), tc.config)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot clone vm '%v': %v", templateName, err)
|
||||
}
|
||||
|
||||
defer destroyVM(t, vm, tc.config.Name)
|
||||
|
||||
log.Printf("[DEBUG] Running check function")
|
||||
tc.checkFunction(t, vm, tc.config)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func cloneDefaultCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
|
||||
d := vm.(*VirtualMachineDriver).driver
|
||||
|
||||
// Check that the clone can be found by its name
|
||||
if _, err := d.FindVM(config.Name); err != nil {
|
||||
t.Errorf("Cannot find created vm '%v': %v", config.Name, err)
|
||||
}
|
||||
|
||||
vmInfo, err := vm.Info("name", "parent", "runtime.host", "resourcePool", "datastore", "layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if vmInfo.Name != config.Name {
|
||||
t.Errorf("Invalid VM name: expected '%v', got '%v'", config.Name, vmInfo.Name)
|
||||
}
|
||||
|
||||
f := d.NewFolder(vmInfo.Parent)
|
||||
folderPath, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
if folderPath != "" {
|
||||
t.Errorf("Invalid folder: expected '/', got '%v'", folderPath)
|
||||
}
|
||||
|
||||
h := d.NewHost(vmInfo.Runtime.Host)
|
||||
hostInfo, err := h.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read host properties: ", err)
|
||||
}
|
||||
if hostInfo.Name != TestHostName {
|
||||
t.Errorf("Invalid host name: expected '%v', got '%v'", TestHostName, hostInfo.Name)
|
||||
}
|
||||
|
||||
p := d.NewResourcePool(vmInfo.ResourcePool)
|
||||
poolPath, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
if poolPath != "" {
|
||||
t.Errorf("Invalid resource pool: expected '/', got '%v'", poolPath)
|
||||
}
|
||||
|
||||
dsr := vmInfo.Datastore[0].Reference()
|
||||
ds := d.NewDatastore(&dsr)
|
||||
dsInfo, err := ds.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read datastore properties: ", err)
|
||||
}
|
||||
if dsInfo.Name != "datastore1" {
|
||||
t.Errorf("Invalid datastore name: expected '%v', got '%v'", "datastore1", dsInfo.Name)
|
||||
}
|
||||
|
||||
if len(vmInfo.LayoutEx.Disk[0].Chain) != 1 {
|
||||
t.Error("Not a full clone")
|
||||
}
|
||||
}
|
||||
|
||||
func configureCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
|
||||
log.Printf("[DEBUG] Configuring the vm")
|
||||
hwConfig := &HardwareConfig{
|
||||
CPUs: 2,
|
||||
CPUReservation: 1000,
|
||||
CPULimit: 1500,
|
||||
RAM: 2048,
|
||||
RAMReservation: 1024,
|
||||
MemoryHotAddEnabled: true,
|
||||
CpuHotAddEnabled: true,
|
||||
}
|
||||
err := vm.Configure(hwConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to configure VM: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Running checks")
|
||||
vmInfo, err := vm.Info("config")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
cpuSockets := vmInfo.Config.Hardware.NumCPU
|
||||
if cpuSockets != hwConfig.CPUs {
|
||||
t.Errorf("VM should have %v CPU sockets, got %v", hwConfig.CPUs, cpuSockets)
|
||||
}
|
||||
|
||||
cpuReservation := *vmInfo.Config.CpuAllocation.Reservation
|
||||
if cpuReservation != hwConfig.CPUReservation {
|
||||
t.Errorf("VM should have CPU reservation for %v Mhz, got %v", hwConfig.CPUReservation, cpuReservation)
|
||||
}
|
||||
|
||||
cpuLimit := *vmInfo.Config.CpuAllocation.Limit
|
||||
if cpuLimit != hwConfig.CPULimit {
|
||||
t.Errorf("VM should have CPU reservation for %v Mhz, got %v", hwConfig.CPULimit, cpuLimit)
|
||||
}
|
||||
|
||||
ram := vmInfo.Config.Hardware.MemoryMB
|
||||
if int64(ram) != hwConfig.RAM {
|
||||
t.Errorf("VM should have %v MB of RAM, got %v", hwConfig.RAM, ram)
|
||||
}
|
||||
|
||||
ramReservation := *vmInfo.Config.MemoryAllocation.Reservation
|
||||
if ramReservation != hwConfig.RAMReservation {
|
||||
t.Errorf("VM should have RAM reservation for %v MB, got %v", hwConfig.RAMReservation, ramReservation)
|
||||
}
|
||||
|
||||
cpuHotAdd := vmInfo.Config.CpuHotAddEnabled
|
||||
if *cpuHotAdd != hwConfig.CpuHotAddEnabled {
|
||||
t.Errorf("VM should have CPU hot add set to %v, got %v", hwConfig.CpuHotAddEnabled, cpuHotAdd)
|
||||
}
|
||||
|
||||
memoryHotAdd := vmInfo.Config.MemoryHotAddEnabled
|
||||
if *memoryHotAdd != hwConfig.MemoryHotAddEnabled {
|
||||
t.Errorf("VM should have Memroy hot add set to %v, got %v", hwConfig.MemoryHotAddEnabled, memoryHotAdd)
|
||||
}
|
||||
}
|
||||
|
||||
func configureRAMReserveAllCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
|
||||
log.Printf("[DEBUG] Configuring the vm")
|
||||
err := vm.Configure(&HardwareConfig{RAMReserveAll: true})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to configure VM: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Running checks")
|
||||
vmInfo, err := vm.Info("config")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if *vmInfo.Config.MemoryReservationLockedToMax != true {
|
||||
t.Errorf("VM should have all RAM reserved")
|
||||
}
|
||||
}
|
||||
|
||||
func cloneLinkedCloneCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
|
||||
vmInfo, err := vm.Info("layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if len(vmInfo.LayoutEx.Disk[0].Chain) != 2 {
|
||||
t.Error("Not a linked clone")
|
||||
}
|
||||
}
|
||||
|
||||
func cloneFolderCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
|
||||
vmInfo, err := vm.Info("parent")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
f := vm.(*VirtualMachineDriver).driver.NewFolder(vmInfo.Parent)
|
||||
path, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
if path != config.Folder {
|
||||
t.Errorf("Wrong folder. expected: %v, got: %v", config.Folder, path)
|
||||
}
|
||||
}
|
||||
|
||||
func cloneResourcePoolCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
|
||||
vmInfo, err := vm.Info("resourcePool")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
p := vm.(*VirtualMachineDriver).driver.NewResourcePool(vmInfo.ResourcePool)
|
||||
path, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
if path != config.ResourcePool {
|
||||
t.Errorf("Wrong folder. expected: %v, got: %v", config.ResourcePool, path)
|
||||
}
|
||||
}
|
||||
|
||||
func startAndStopCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
|
||||
stopper := startVM(t, vm, config.Name)
|
||||
defer stopper()
|
||||
|
||||
switch ip, err := vm.WaitForIP(context.TODO(), nil); {
|
||||
case err != nil:
|
||||
t.Errorf("Cannot obtain IP address from created vm '%v': %v", config.Name, err)
|
||||
case net.ParseIP(ip) == nil:
|
||||
t.Errorf("'%v' is not a valid ip address", ip)
|
||||
}
|
||||
|
||||
err := vm.StartShutdown()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to initiate guest shutdown: %v", err)
|
||||
}
|
||||
log.Printf("[DEBUG] Waiting max 1m0s for shutdown to complete")
|
||||
err = vm.WaitForShutdown(context.TODO(), 1*time.Minute)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to wait for giest shutdown: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func snapshotCheck(t *testing.T, vm VirtualMachine, config *CloneConfig) {
|
||||
stopper := startVM(t, vm, config.Name)
|
||||
defer stopper()
|
||||
|
||||
err := vm.CreateSnapshot("test-snapshot")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create snapshot: %v", err)
|
||||
}
|
||||
|
||||
vmInfo, err := vm.Info("layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
layers := len(vmInfo.LayoutEx.Disk[0].Chain)
|
||||
if layers != 2 {
|
||||
t.Errorf("VM should have a single snapshot. expected 2 disk layers, got %v", layers)
|
||||
}
|
||||
}
|
||||
|
||||
func templateCheck(t *testing.T, vm VirtualMachine, _ *CloneConfig) {
|
||||
err := vm.ConvertToTemplate()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to convert to template: %v", err)
|
||||
}
|
||||
vmInfo, err := vm.Info("config.template")
|
||||
if err != nil {
|
||||
t.Errorf("Cannot read VM properties: %v", err)
|
||||
} else if !vmInfo.Config.Template {
|
||||
t.Error("Not a template")
|
||||
}
|
||||
}
|
||||
|
||||
func startVM(t *testing.T, vm VirtualMachine, vmName string) (stopper func()) {
|
||||
log.Printf("[DEBUG] Starting the vm")
|
||||
if err := vm.PowerOn(); err != nil {
|
||||
t.Fatalf("Cannot start vm '%v': %v", vmName, err)
|
||||
}
|
||||
return func() {
|
||||
log.Printf("[DEBUG] Powering off the vm")
|
||||
if err := vm.PowerOff(); err != nil {
|
||||
t.Errorf("Cannot power off started vm '%v': %v", vmName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func destroyVM(t *testing.T, vm VirtualMachine, vmName string) {
|
||||
log.Printf("[DEBUG] Deleting the VM")
|
||||
if err := vm.Destroy(); err != nil {
|
||||
t.Errorf("!!! ERROR DELETING VM '%v': %v!!!", vmName, err)
|
||||
}
|
||||
|
||||
// Check that the clone is no longer exists
|
||||
if _, err := vm.(*VirtualMachineDriver).driver.FindVM(vmName); err == nil {
|
||||
t.Errorf("!!! STILL CAN FIND VM '%v'. IT MIGHT NOT HAVE BEEN DELETED !!!", vmName)
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVMAcc_create(t *testing.T) {
|
||||
t.Skip("Acceptance tests not configured yet.")
|
||||
testCases := []struct {
|
||||
name string
|
||||
config *CreateConfig
|
||||
checkFunction func(*testing.T, VirtualMachine, *CreateConfig)
|
||||
}{
|
||||
{"MinimalConfiguration", &CreateConfig{}, createDefaultCheck},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tc.config.Host = TestHostName
|
||||
tc.config.Name = newVMName()
|
||||
|
||||
d := newTestDriver(t)
|
||||
|
||||
log.Printf("[DEBUG] Creating VM")
|
||||
vm, err := d.CreateVM(tc.config)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create VM: %v", err)
|
||||
}
|
||||
|
||||
defer destroyVM(t, vm, tc.config.Name)
|
||||
|
||||
log.Printf("[DEBUG] Running check function")
|
||||
tc.checkFunction(t, vm, tc.config)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func createDefaultCheck(t *testing.T, vm VirtualMachine, config *CreateConfig) {
|
||||
d := vm.(*VirtualMachineDriver).driver
|
||||
|
||||
// Check that the clone can be found by its name
|
||||
if _, err := d.FindVM(config.Name); err != nil {
|
||||
t.Errorf("Cannot find created vm '%v': %v", config.Name, err)
|
||||
}
|
||||
|
||||
vmInfo, err := vm.Info("name", "parent", "runtime.host", "resourcePool", "datastore", "layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if vmInfo.Name != config.Name {
|
||||
t.Errorf("Invalid VM name: expected '%v', got '%v'", config.Name, vmInfo.Name)
|
||||
}
|
||||
|
||||
f := d.NewFolder(vmInfo.Parent)
|
||||
folderPath, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
if folderPath != "" {
|
||||
t.Errorf("Invalid folder: expected '/', got '%v'", folderPath)
|
||||
}
|
||||
|
||||
h := d.NewHost(vmInfo.Runtime.Host)
|
||||
hostInfo, err := h.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read host properties: ", err)
|
||||
}
|
||||
if hostInfo.Name != TestHostName {
|
||||
t.Errorf("Invalid host name: expected '%v', got '%v'", TestHostName, hostInfo.Name)
|
||||
}
|
||||
|
||||
p := d.NewResourcePool(vmInfo.ResourcePool)
|
||||
poolPath, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
if poolPath != "" {
|
||||
t.Errorf("Invalid resource pool: expected '/', got '%v'", poolPath)
|
||||
}
|
||||
|
||||
dsr := vmInfo.Datastore[0].Reference()
|
||||
ds := d.NewDatastore(&dsr)
|
||||
dsInfo, err := ds.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read datastore properties: ", err)
|
||||
}
|
||||
if dsInfo.Name != "datastore1" {
|
||||
t.Errorf("Invalid datastore name: expected 'datastore1', got '%v'", dsInfo.Name)
|
||||
}
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// ReconfigureFail changes the behavior of simulator.VirtualMachine
|
||||
type ReconfigureFail struct {
|
||||
*simulator.VirtualMachine
|
||||
}
|
||||
|
||||
// Override simulator.VirtualMachine.ReconfigVMTask to inject faults
|
||||
func (vm *ReconfigureFail) ReconfigVMTask(req *types.ReconfigVM_Task) soap.HasFault {
|
||||
task := simulator.CreateTask(req.This, "reconfigure", func(*simulator.Task) (types.AnyType, types.BaseMethodFault) {
|
||||
return nil, &types.TaskInProgress{}
|
||||
})
|
||||
|
||||
return &methods.ReconfigVM_TaskBody{
|
||||
Res: &types.ReconfigVM_TaskResponse{
|
||||
Returnval: task.Run(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMachineDriver_Configure(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
vm, machine := sim.ChooseSimulatorPreCreatedVM()
|
||||
|
||||
// Happy test
|
||||
hardwareConfig := &HardwareConfig{
|
||||
CPUs: 1,
|
||||
CpuCores: 1,
|
||||
CPUReservation: 2500,
|
||||
CPULimit: 1,
|
||||
RAM: 1024,
|
||||
RAMReserveAll: true,
|
||||
VideoRAM: 512,
|
||||
VGPUProfile: "grid_m10-8q",
|
||||
Firmware: "efi-secure",
|
||||
ForceBIOSSetup: true,
|
||||
}
|
||||
if err = vm.Configure(hardwareConfig); err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
|
||||
//Fail test
|
||||
//Wrap the existing vm object with the mocked reconfigure task which will return a fault
|
||||
simulator.Map.Put(&ReconfigureFail{machine})
|
||||
if err = vm.Configure(&HardwareConfig{}); err == nil {
|
||||
t.Fatalf("Configure should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMachineDriver_CreateVMWithMultipleDisks(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
_, datastore := sim.ChooseSimulatorPreCreatedDatastore()
|
||||
|
||||
config := &CreateConfig{
|
||||
Name: "mock name",
|
||||
Host: "DC0_H0",
|
||||
Datastore: datastore.Name,
|
||||
NICs: []NIC{
|
||||
{
|
||||
Network: "VM Network",
|
||||
NetworkCard: "vmxnet3",
|
||||
},
|
||||
},
|
||||
StorageConfig: StorageConfig{
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []Disk{
|
||||
{
|
||||
DiskSize: 3072,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
{
|
||||
DiskSize: 20480,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vm, err := sim.driver.CreateVM(config)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
devices, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
var disks []*types.VirtualDisk
|
||||
for _, device := range devices {
|
||||
switch d := device.(type) {
|
||||
case *types.VirtualDisk:
|
||||
disks = append(disks, d)
|
||||
}
|
||||
}
|
||||
|
||||
if len(disks) != 2 {
|
||||
t.Fatalf("unexpected number of devices")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMachineDriver_CloneWithPrimaryDiskResize(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
_, datastore := sim.ChooseSimulatorPreCreatedDatastore()
|
||||
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||
|
||||
config := &CloneConfig{
|
||||
Name: "mock name",
|
||||
Host: "DC0_H0",
|
||||
Datastore: datastore.Name,
|
||||
PrimaryDiskSize: 204800,
|
||||
StorageConfig: StorageConfig{
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []Disk{
|
||||
{
|
||||
DiskSize: 3072,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
{
|
||||
DiskSize: 20480,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
clonedVM, err := vm.Clone(context.TODO(), config)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
devices, err := clonedVM.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
var disks []*types.VirtualDisk
|
||||
for _, device := range devices {
|
||||
switch d := device.(type) {
|
||||
case *types.VirtualDisk:
|
||||
disks = append(disks, d)
|
||||
}
|
||||
}
|
||||
|
||||
if len(disks) != 3 {
|
||||
t.Fatalf("unexpected number of devices")
|
||||
}
|
||||
|
||||
if disks[0].CapacityInKB != config.PrimaryDiskSize*1024 {
|
||||
t.Fatalf("unexpected disk size for primary disk: %d", disks[0].CapacityInKB)
|
||||
}
|
||||
if disks[1].CapacityInKB != config.StorageConfig.Storage[0].DiskSize*1024 {
|
||||
t.Fatalf("unexpected disk size for primary disk: %d", disks[1].CapacityInKB)
|
||||
}
|
||||
if disks[2].CapacityInKB != config.StorageConfig.Storage[1].DiskSize*1024 {
|
||||
t.Fatalf("unexpected disk size for primary disk: %d", disks[2].CapacityInKB)
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "vsphere-iso",
|
||||
"CPUs": 1,
|
||||
"RAM": 512,
|
||||
"RAM_reserve_all": true,
|
||||
"boot_command": [
|
||||
"root<enter><wait>",
|
||||
"mount -t vfat /dev/fd0 /media/floppy<enter><wait>",
|
||||
"setup-alpine -f /media/floppy/answerfile<enter>",
|
||||
"<wait5>",
|
||||
"jetbrains<enter>",
|
||||
"jetbrains<enter>",
|
||||
"<wait5>",
|
||||
"y<enter>",
|
||||
"<wait10><wait10><wait10><wait10>",
|
||||
"reboot<enter>",
|
||||
"<wait10><wait10>",
|
||||
"root<enter>",
|
||||
"jetbrains<enter><wait>",
|
||||
"mount -t vfat /dev/fd0 /media/floppy<enter><wait>",
|
||||
"/media/floppy/SETUP.SH<enter>"
|
||||
],
|
||||
"boot_wait": "15s",
|
||||
"disk_controller_type": "pvscsi",
|
||||
"floppy_files": [
|
||||
"{{template_dir}}/answerfile",
|
||||
"{{template_dir}}/setup.sh"
|
||||
],
|
||||
"guest_os_type": "other3xLinux64Guest",
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
"insecure_connection": true,
|
||||
"iso_paths": [
|
||||
"[datastore1] ISO/alpine-standard-3.8.2-x86_64.iso"
|
||||
],
|
||||
"network_adapters": [
|
||||
{
|
||||
"network_card": "vmxnet3"
|
||||
}
|
||||
],
|
||||
"password": "jetbrains",
|
||||
"ssh_password": "jetbrains",
|
||||
"ssh_username": "root",
|
||||
"storage": [
|
||||
{
|
||||
"disk_size": 1024,
|
||||
"disk_thin_provisioned": true
|
||||
}
|
||||
],
|
||||
"username": "root",
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"vm_name": "alpine-{{timestamp}}"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"inline": [
|
||||
"ls /"
|
||||
],
|
||||
"type": "shell"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
# "timestamp" template function replacement
|
||||
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
|
||||
|
||||
# source blocks are analogous to the "builders" in json templates. They are used
|
||||
# in build blocks. A build block runs provisioners and post-processors on a
|
||||
# source. Read the documentation for source blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
|
||||
source "vsphere-iso" "autogenerated_1" {
|
||||
CPUs = 1
|
||||
RAM = 512
|
||||
RAM_reserve_all = true
|
||||
boot_command = ["root<enter><wait>", "mount -t vfat /dev/fd0 /media/floppy<enter><wait>", "setup-alpine -f /media/floppy/answerfile<enter>", "<wait5>", "jetbrains<enter>", "jetbrains<enter>", "<wait5>", "y<enter>", "<wait10><wait10><wait10><wait10>", "reboot<enter>", "<wait10><wait10>", "root<enter>", "jetbrains<enter><wait>", "mount -t vfat /dev/fd0 /media/floppy<enter><wait>", "/media/floppy/SETUP.SH<enter>"]
|
||||
boot_wait = "15s"
|
||||
disk_controller_type = ["pvscsi"]
|
||||
floppy_files = ["${path.root}/answerfile", "${path.root}/setup.sh"]
|
||||
guest_os_type = "other3xLinux64Guest"
|
||||
host = "esxi-1.vsphere65.test"
|
||||
insecure_connection = true
|
||||
iso_paths = ["[datastore1] ISO/alpine-standard-3.8.2-x86_64.iso"]
|
||||
network_adapters {
|
||||
network_card = "vmxnet3"
|
||||
}
|
||||
password = "jetbrains"
|
||||
ssh_password = "jetbrains"
|
||||
ssh_username = "root"
|
||||
storage {
|
||||
disk_size = 1024
|
||||
disk_thin_provisioned = true
|
||||
}
|
||||
username = "root"
|
||||
vcenter_server = "vcenter.vsphere65.test"
|
||||
vm_name = "alpine-${local.timestamp}"
|
||||
}
|
||||
|
||||
# a build block invokes sources and runs provisioning steps on them. The
|
||||
# documentation for build blocks can be found here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
|
||||
build {
|
||||
sources = ["source.vsphere-iso.autogenerated_1"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = ["ls /"]
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
KEYMAPOPTS="us us"
|
||||
HOSTNAMEOPTS="-n alpine"
|
||||
INTERFACESOPTS="auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet dhcp
|
||||
hostname alpine
|
||||
"
|
||||
TIMEZONEOPTS="-z UTC"
|
||||
PROXYOPTS="none"
|
||||
APKREPOSOPTS="http://mirror.yandex.ru/mirrors/alpine/v3.8/main"
|
||||
SSHDOPTS="-c openssh"
|
||||
NTPOPTS="-c none"
|
||||
DISKOPTS="-m sys /dev/sda"
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
apk add libressl
|
||||
apk add open-vm-tools
|
||||
rc-update add open-vm-tools
|
||||
/etc/init.d/open-vm-tools start
|
||||
|
||||
cat >/usr/local/bin/shutdown <<EOF
|
||||
#!/bin/sh
|
||||
poweroff
|
||||
EOF
|
||||
chmod +x /usr/local/bin/shutdown
|
||||
|
||||
sed -i "/#PermitRootLogin/c\PermitRootLogin yes" /etc/ssh/sshd_config
|
||||
mkdir ~/.ssh
|
||||
wget https://raw.githubusercontent.com/jetbrains-infra/packer-builder-vsphere/master/test/test-key.pub -O ~/.ssh/authorized_keys
|
||||
/etc/init.d/sshd restart
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "vsphere-clone",
|
||||
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"username": "root",
|
||||
"password": "jetbrains",
|
||||
"insecure_connection": "true",
|
||||
|
||||
"template": "alpine",
|
||||
"vm_name": "alpine-clone-{{timestamp}}",
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
|
||||
"communicator": "none"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
# "timestamp" template function replacement
|
||||
locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }
|
||||
|
||||
# source blocks are analogous to the "builders" in json templates. They are used
|
||||
# in build blocks. A build block runs provisioners and post-processors on a
|
||||
# source. Read the documentation for source blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
|
||||
source "vsphere-clone" "example_clone" {
|
||||
communicator = "none"
|
||||
host = "esxi-1.vsphere65.test"
|
||||
insecure_connection = "true"
|
||||
password = "jetbrains"
|
||||
template = "alpine"
|
||||
username = "root"
|
||||
vcenter_server = "vcenter.vsphere65.test"
|
||||
vm_name = "alpine-clone-${local.timestamp}"
|
||||
}
|
||||
|
||||
# a build block invokes sources and runs provisioning steps on them. The
|
||||
# documentation for build blocks can be found here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
|
||||
build {
|
||||
sources = ["source.vsphere-clone.example_clone"]
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func main() {
|
||||
d, err := driver.NewDriver(&driver.ConnectConfig{
|
||||
VCenterServer: "vcenter.vsphere65.test",
|
||||
Username: "root",
|
||||
Password: "jetbrains",
|
||||
InsecureConnection: true,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ds, err := d.FindDatastore("", "esxi-1.vsphere65.test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(ds.Name())
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "vsphere-iso",
|
||||
"CPUs": 1,
|
||||
"RAM": 4096,
|
||||
"boot_command": [
|
||||
"<enter><wait5>",
|
||||
"<leftCtrlOn><f2><leftCtrlOff>u<enter>t<enter><wait5>",
|
||||
"/Volumes/setup/setup.sh<enter>"
|
||||
],
|
||||
"boot_wait": "4m",
|
||||
"cdrom_type": "sata",
|
||||
"configuration_parameters": {
|
||||
"ich7m.present": "TRUE",
|
||||
"smc.present": "TRUE"
|
||||
},
|
||||
"guest_os_type": "darwin16_64Guest",
|
||||
"host": "esxi-mac.vsphere65.test",
|
||||
"insecure_connection": "true",
|
||||
"iso_checksum": "file:///{{template_dir}}/setup/out/sha256sums",
|
||||
"iso_paths": [
|
||||
"[datastore-mac] ISO/macOS 10.13.3.iso",
|
||||
"[datastore-mac] ISO/VMware Tools/10.2.0/darwin.iso"
|
||||
],
|
||||
"iso_urls": [
|
||||
"{{template_dir}}/setup/out/setup.iso"
|
||||
],
|
||||
"network_adapters": [
|
||||
{
|
||||
"network_card": "e1000e"
|
||||
}
|
||||
],
|
||||
"password": "jetbrains",
|
||||
"ssh_password": "jetbrains",
|
||||
"ssh_username": "jetbrains",
|
||||
"storage": [
|
||||
{
|
||||
"disk_size": 32768,
|
||||
"disk_thin_provisioned": true
|
||||
}
|
||||
],
|
||||
"usb_controller": true,
|
||||
"username": "root",
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"vm_name": "macos-packer"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
# source blocks are analogous to the "builders" in json templates. They are used
|
||||
# in build blocks. A build block runs provisioners and post-processors on a
|
||||
# source. Read the documentation for source blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
|
||||
source "vsphere-iso" "example_osx" {
|
||||
CPUs = 1
|
||||
RAM = 4096
|
||||
boot_command = ["<enter><wait5>", "<leftCtrlOn><f2><leftCtrlOff>u<enter>t<enter><wait5>", "/Volumes/setup/setup.sh<enter>"]
|
||||
boot_wait = "4m"
|
||||
cdrom_type = "sata"
|
||||
configuration_parameters = {
|
||||
"ich7m.present" = "TRUE"
|
||||
"smc.present" = "TRUE"
|
||||
}
|
||||
guest_os_type = "darwin16_64Guest"
|
||||
host = "esxi-mac.vsphere65.test"
|
||||
insecure_connection = "true"
|
||||
iso_checksum = "file:///${path.root}/setup/out/sha256sums"
|
||||
iso_paths = ["[datastore-mac] ISO/macOS 10.13.3.iso", "[datastore-mac] ISO/VMware Tools/10.2.0/darwin.iso"]
|
||||
iso_urls = ["${path.root}/setup/out/setup.iso"]
|
||||
network_adapters {
|
||||
network_card = "e1000e"
|
||||
}
|
||||
password = "jetbrains"
|
||||
ssh_password = "jetbrains"
|
||||
ssh_username = "jetbrains"
|
||||
storage {
|
||||
disk_size = 32768
|
||||
disk_thin_provisioned = true
|
||||
}
|
||||
usb_controller = ["usb"]
|
||||
username = "root"
|
||||
vcenter_server = "vcenter.vsphere65.test"
|
||||
vm_name = "macos-packer"
|
||||
}
|
||||
|
||||
# a build block invokes sources and runs provisioning steps on them. The
|
||||
# documentation for build blocks can be found here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
|
||||
build {
|
||||
sources = ["source.vsphere-iso.example_osx"]
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
out/
|
|
@ -1,15 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -eux
|
||||
|
||||
# Based on
|
||||
# https://gist.github.com/agentsim/00cc38c693e7d0e1b36a2080870d955b#gistcomment-2304505
|
||||
|
||||
mkdir -p out
|
||||
|
||||
hdiutil create -o out/HighSierra.cdr -size 5530m -layout SPUD -fs HFS+J
|
||||
hdiutil attach out/HighSierra.cdr.dmg -noverify -mountpoint /Volumes/install_build
|
||||
sudo /Applications/Install\ macOS\ High\ Sierra.app/Contents/Resources/createinstallmedia --volume /Volumes/install_build --nointeraction
|
||||
hdiutil detach /Volumes/Install\ macOS\ High\ Sierra
|
||||
hdiutil convert out/HighSierra.cdr.dmg -format UDTO -o out/HighSierra.iso
|
||||
mv out/HighSierra.iso.cdr out/HighSierra.iso
|
||||
rm out/HighSierra.cdr.dmg
|
|
@ -1,27 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -eux
|
||||
|
||||
mkdir -p out/pkgroot
|
||||
rm -rf /out/pkgroot/*
|
||||
|
||||
mkdir -p out/scripts
|
||||
rm -rf /out/scripts/*
|
||||
cp postinstall out/scripts/
|
||||
|
||||
pkgbuild \
|
||||
--identifier io.packer.install \
|
||||
--root out/pkgroot \
|
||||
--scripts out/scripts \
|
||||
out/postinstall.pkg
|
||||
|
||||
mkdir -p out/iso
|
||||
rm -rf out/iso/*
|
||||
cp setup.sh out/iso/
|
||||
chmod +x out/iso/setup.sh
|
||||
|
||||
productbuild --package out/postinstall.pkg out/iso/postinstall.pkg
|
||||
|
||||
rm -f out/setup.iso
|
||||
hdiutil makehybrid -iso -joliet -default-volume-name setup -o out/setup.iso out/iso
|
||||
cd out
|
||||
shasum -a 256 setup.iso >sha256sums
|
|
@ -1,25 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -eux
|
||||
# debug output in /var/log/install.log
|
||||
|
||||
# Create user account
|
||||
USERNAME=jetbrains
|
||||
PASSWORD=jetbrains
|
||||
dscl . -create "/Users/${USERNAME}"
|
||||
dscl . -create "/Users/${USERNAME}" UserShell /bin/bash
|
||||
dscl . -create "/Users/${USERNAME}" RealName "${USERNAME}"
|
||||
dscl . -create "/Users/${USERNAME}" UniqueID 510
|
||||
dscl . -create "/Users/${USERNAME}" PrimaryGroupID 20
|
||||
dscl . -create "/Users/${USERNAME}" NFSHomeDirectory "/Users/${USERNAME}"
|
||||
dscl . -passwd "/Users/${USERNAME}" "${PASSWORD}"
|
||||
dscl . -append /Groups/admin GroupMembership "${USERNAME}"
|
||||
createhomedir -c
|
||||
|
||||
# Start VMware Tools daemon explicitly
|
||||
launchctl load /Library/LaunchDaemons/com.vmware.launchd.tools.plist
|
||||
|
||||
# Enable SSH
|
||||
systemsetup -setremotelogin on
|
||||
|
||||
# Disable the welcome screen
|
||||
touch "$3/private/var/db/.AppleSetupDone"
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -eux
|
||||
|
||||
# Format partition
|
||||
diskutil eraseDisk JHFS+ Disk disk0
|
||||
|
||||
# Packages are installed in reversed order - why?
|
||||
"/Volumes/Image Volume/Install macOS High Sierra.app/Contents/Resources/startosinstall" \
|
||||
--volume /Volumes/Disk \
|
||||
--converttoapfs no \
|
||||
--agreetolicense \
|
||||
--installpackage "/Volumes/setup/postinstall.pkg" \
|
||||
--installpackage "/Volumes/VMware Tools/Install VMware Tools.app/Contents/Resources/VMware Tools.pkg"
|
|
@ -1,16 +0,0 @@
|
|||
d-i passwd/user-fullname string jetbrains
|
||||
d-i passwd/username string jetbrains
|
||||
d-i passwd/user-password password jetbrains
|
||||
d-i passwd/user-password-again password jetbrains
|
||||
d-i user-setup/allow-password-weak boolean true
|
||||
|
||||
d-i partman-auto/disk string /dev/sda
|
||||
d-i partman-auto/method string regular
|
||||
d-i partman-partitioning/confirm_write_new_label boolean true
|
||||
d-i partman/choose_partition select finish
|
||||
d-i partman/confirm boolean true
|
||||
d-i partman/confirm_nooverwrite boolean true
|
||||
|
||||
d-i pkgsel/include string open-vm-tools openssh-server
|
||||
|
||||
d-i finish-install/reboot_in_progress note
|
|
@ -1,63 +0,0 @@
|
|||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "vsphere-iso",
|
||||
"CPUs": 1,
|
||||
"RAM": 1024,
|
||||
"RAM_reserve_all": true,
|
||||
"boot_command": [
|
||||
"<enter><wait><f6><wait><esc><wait>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs>",
|
||||
"/install/vmlinuz",
|
||||
" initrd=/install/initrd.gz",
|
||||
" priority=critical",
|
||||
" locale=en_US",
|
||||
" file=/media/preseed.cfg",
|
||||
"<enter>"
|
||||
],
|
||||
"disk_controller_type": "pvscsi",
|
||||
"floppy_files": [
|
||||
"{{template_dir}}/preseed.cfg"
|
||||
],
|
||||
"guest_os_type": "ubuntu64Guest",
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
"insecure_connection": true,
|
||||
"iso_paths": [
|
||||
"[datastore1] ISO/ubuntu-16.04.3-server-amd64.iso"
|
||||
],
|
||||
"network_adapters": [
|
||||
{
|
||||
"network_card": "vmxnet3"
|
||||
}
|
||||
],
|
||||
"password": "jetbrains",
|
||||
"ssh_password": "jetbrains",
|
||||
"ssh_username": "jetbrains",
|
||||
"storage": [
|
||||
{
|
||||
"disk_size": 32768,
|
||||
"disk_thin_provisioned": true
|
||||
}
|
||||
],
|
||||
"username": "root",
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"vm_name": "example-ubuntu"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"inline": [
|
||||
"ls /"
|
||||
],
|
||||
"type": "shell"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
# source blocks are analogous to the "builders" in json templates. They are used
|
||||
# in build blocks. A build block runs provisioners and post-processors on a
|
||||
# source. Read the documentation for source blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
|
||||
source "vsphere-iso" "example" {
|
||||
CPUs = 1
|
||||
RAM = 1024
|
||||
RAM_reserve_all = true
|
||||
boot_command = ["<enter><wait><f6><wait><esc><wait>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs><bs><bs><bs><bs><bs><bs><bs>",
|
||||
"<bs><bs><bs>", "/install/vmlinuz",
|
||||
" initrd=/install/initrd.gz", " priority=critical",
|
||||
" locale=en_US", " file=/media/preseed.cfg",
|
||||
"<enter>"]
|
||||
disk_controller_type = ["pvscsi"]
|
||||
floppy_files = ["${path.root}/preseed.cfg"]
|
||||
guest_os_type = "ubuntu64Guest"
|
||||
host = "esxi-1.vsphere65.test"
|
||||
insecure_connection = true
|
||||
iso_paths = ["[datastore1] ISO/ubuntu-16.04.3-server-amd64.iso"]
|
||||
network_adapters {
|
||||
network_card = "vmxnet3"
|
||||
}
|
||||
password = "jetbrains"
|
||||
ssh_password = "jetbrains"
|
||||
ssh_username = "jetbrains"
|
||||
storage {
|
||||
disk_size = 32768
|
||||
disk_thin_provisioned = true
|
||||
}
|
||||
username = "root"
|
||||
vcenter_server = "vcenter.vsphere65.test"
|
||||
vm_name = "example-ubuntu"
|
||||
}
|
||||
|
||||
# a build block invokes sources and runs provisioning steps on them. The
|
||||
# documentation for build blocks can be found here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
|
||||
build {
|
||||
sources = ["source.vsphere-iso.example"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = ["ls /"]
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
|
@ -1,122 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
<settings pass="windowsPE">
|
||||
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<UILanguage>en-US</UILanguage>
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<DriverPaths>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="A">
|
||||
<!-- pvscsi-Windows8.flp -->
|
||||
<Path>B:\</Path>
|
||||
</PathAndCredentials>
|
||||
</DriverPaths>
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<UserData>
|
||||
<AcceptEula>true</AcceptEula>
|
||||
|
||||
<!-- Retail image requires a key
|
||||
<ProductKey>
|
||||
<Key>XXXXX-XXXXX-XXXXX-XXXXX-XXXXX</Key>
|
||||
</ProductKey>
|
||||
-->
|
||||
</UserData>
|
||||
|
||||
<ImageInstall>
|
||||
<OSImage>
|
||||
<InstallFrom>
|
||||
<MetaData wcm:action="add">
|
||||
<Key>/IMAGE/NAME</Key>
|
||||
<Value>Windows 10 Pro</Value>
|
||||
</MetaData>
|
||||
</InstallFrom>
|
||||
<InstallToAvailablePartition>true</InstallToAvailablePartition>
|
||||
</OSImage>
|
||||
</ImageInstall>
|
||||
|
||||
<DiskConfiguration>
|
||||
<Disk wcm:action="add">
|
||||
<DiskID>0</DiskID>
|
||||
<CreatePartitions>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Extend>true</Extend>
|
||||
<Type>Primary</Type>
|
||||
</CreatePartition>
|
||||
</CreatePartitions>
|
||||
</Disk>
|
||||
</DiskConfiguration>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<settings pass="offlineServicing">
|
||||
<component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<!-- Disable user account control -->
|
||||
<EnableLUA>false</EnableLUA>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<settings pass="specialize">
|
||||
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<RunSynchronous>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<!-- Install VMware Tools from windows.iso -->
|
||||
<Path>a:\vmtools.cmd</Path>
|
||||
<WillReboot>Always</WillReboot>
|
||||
</RunSynchronousCommand>
|
||||
</RunSynchronous>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<OOBE>
|
||||
<!-- Privacy settings -->
|
||||
<ProtectYourPC>3</ProtectYourPC>
|
||||
</OOBE>
|
||||
|
||||
<!--
|
||||
<TimeZone>Russian Standard Time</TimeZone>
|
||||
-->
|
||||
|
||||
<UserAccounts>
|
||||
<LocalAccounts>
|
||||
<LocalAccount wcm:action="add">
|
||||
<Name>jetbrains</Name>
|
||||
<Password>
|
||||
<Value>jetbrains</Value>
|
||||
<PlainText>true</PlainText>
|
||||
</Password>
|
||||
<Group>Administrators</Group>
|
||||
</LocalAccount>
|
||||
</LocalAccounts>
|
||||
</UserAccounts>
|
||||
|
||||
<AutoLogon>
|
||||
<Enabled>true</Enabled>
|
||||
<Username>jetbrains</Username>
|
||||
<Password>
|
||||
<Value>jetbrains</Value>
|
||||
<PlainText>true</PlainText>
|
||||
</Password>
|
||||
<LogonCount>1</LogonCount>
|
||||
</AutoLogon>
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<!-- Enable WinRM service -->
|
||||
<CommandLine>powershell -ExecutionPolicy Bypass -File a:\setup.ps1</CommandLine>
|
||||
<RequiresUserInput>true</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
</component>
|
||||
</settings>
|
||||
</unattend>
|
|
@ -1,15 +0,0 @@
|
|||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Switch network connection to private mode
|
||||
# Required for WinRM firewall rules
|
||||
$profile = Get-NetConnectionProfile
|
||||
Set-NetConnectionProfile -Name $profile.Name -NetworkCategory Private
|
||||
|
||||
# Enable WinRM service
|
||||
winrm quickconfig -quiet
|
||||
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
|
||||
winrm set winrm/config/service/auth '@{Basic="true"}'
|
||||
|
||||
# Reset auto logon count
|
||||
# https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-autologon-logoncount#logoncount-known-issue
|
||||
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name AutoLogonCount -Value 0
|
|
@ -1,2 +0,0 @@
|
|||
@rem Silent mode, basic UI, no reboot
|
||||
e:\setup64 /s /v "/qb REBOOT=R"
|
|
@ -1,48 +0,0 @@
|
|||
{
|
||||
"builders": [
|
||||
{
|
||||
"type": "vsphere-iso",
|
||||
"CPUs": 1,
|
||||
"RAM": 4096,
|
||||
"RAM_reserve_all": true,
|
||||
"communicator": "winrm",
|
||||
"disk_controller_type": "pvscsi",
|
||||
"floppy_files": [
|
||||
"{{template_dir}}/setup/"
|
||||
],
|
||||
"floppy_img_path": "[datastore1] ISO/VMware Tools/10.2.0/pvscsi-Windows8.flp",
|
||||
"guest_os_type": "windows9_64Guest",
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
"insecure_connection": "true",
|
||||
"iso_paths": [
|
||||
"[datastore1] ISO/en_windows_10_multi-edition_vl_version_1709_updated_dec_2017_x64_dvd_100406172.iso",
|
||||
"[datastore1] ISO/VMware Tools/10.2.0/windows.iso"
|
||||
],
|
||||
"network_adapters": [
|
||||
{
|
||||
"network_card": "vmxnet3"
|
||||
}
|
||||
],
|
||||
"password": "jetbrains",
|
||||
"storage": [
|
||||
{
|
||||
"disk_size": 32768,
|
||||
"disk_thin_provisioned": true
|
||||
}
|
||||
],
|
||||
"username": "root",
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"vm_name": "example-windows",
|
||||
"winrm_password": "jetbrains",
|
||||
"winrm_username": "jetbrains"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"inline": [
|
||||
"dir c:\\"
|
||||
],
|
||||
"type": "windows-shell"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
# source blocks are generated from your builders; a source can be referenced in
|
||||
# build blocks. A build block runs provisioner and post-processors on a
|
||||
# source. Read the documentation for source blocks here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/source
|
||||
source "vsphere-iso" "example_windows" {
|
||||
CPUs = 1
|
||||
RAM = 4096
|
||||
RAM_reserve_all = true
|
||||
communicator = "winrm"
|
||||
disk_controller_type = ["pvscsi"]
|
||||
floppy_files = ["${path.root}/setup/"]
|
||||
floppy_img_path = "[datastore1] ISO/VMware Tools/10.2.0/pvscsi-Windows8.flp"
|
||||
guest_os_type = "windows9_64Guest"
|
||||
host = "esxi-1.vsphere65.test"
|
||||
insecure_connection = "true"
|
||||
iso_paths = ["[datastore1] ISO/en_windows_10_multi-edition_vl_version_1709_updated_dec_2017_x64_dvd_100406172.iso", "[datastore1] ISO/VMware Tools/10.2.0/windows.iso"]
|
||||
network_adapters {
|
||||
network_card = "vmxnet3"
|
||||
}
|
||||
password = "jetbrains"
|
||||
storage {
|
||||
disk_size = 32768
|
||||
disk_thin_provisioned = true
|
||||
}
|
||||
username = "root"
|
||||
vcenter_server = "vcenter.vsphere65.test"
|
||||
vm_name = "example-windows"
|
||||
winrm_password = "jetbrains"
|
||||
winrm_username = "jetbrains"
|
||||
}
|
||||
|
||||
# a build block invokes sources and runs provisioning steps on them. The
|
||||
# documentation for build blocks can be found here:
|
||||
# https://www.packer.io/docs/templates/hcl_templates/blocks/build
|
||||
build {
|
||||
sources = ["source.vsphere-iso.example_windows"]
|
||||
|
||||
provisioner "windows-shell" {
|
||||
inline = ["dir c:\\"]
|
||||
}
|
||||
}
|
|
@ -1,568 +0,0 @@
|
|||
package iso
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
builderT "github.com/hashicorp/packer/acctest"
|
||||
commonT "github.com/hashicorp/packer/builder/vsphere/common/testing"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
func TestISOBuilderAcc_default(t *testing.T) {
|
||||
config := defaultConfig()
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: commonT.RenderConfig(config),
|
||||
Check: checkDefault(t, config["vm_name"].(string), config["host"].(string), "datastore1"),
|
||||
})
|
||||
}
|
||||
|
||||
func defaultConfig() map[string]interface{} {
|
||||
username := os.Getenv("VSPHERE_USERNAME")
|
||||
if username == "" {
|
||||
username = "root"
|
||||
}
|
||||
password := os.Getenv("VSPHERE_PASSWORD")
|
||||
if password == "" {
|
||||
password = "jetbrains"
|
||||
}
|
||||
|
||||
config := map[string]interface{}{
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"username": username,
|
||||
"password": password,
|
||||
"insecure_connection": true,
|
||||
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
|
||||
"ssh_username": "root",
|
||||
"ssh_password": "jetbrains",
|
||||
|
||||
"vm_name": commonT.NewVMName(),
|
||||
"storage": map[string]interface{}{
|
||||
"disk_size": 2048,
|
||||
},
|
||||
|
||||
"communicator": "none", // do not start the VM without any bootable devices
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func checkDefault(t *testing.T, name string, host string, datastore string) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("name", "parent", "runtime.host", "resourcePool", "datastore", "layoutEx.disk", "config.firmware")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
if vmInfo.Name != name {
|
||||
t.Errorf("Invalid VM name: expected '%v', got '%v'", name, vmInfo.Name)
|
||||
}
|
||||
|
||||
f := d.NewFolder(vmInfo.Parent)
|
||||
folderPath, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
if folderPath != "" {
|
||||
t.Errorf("Invalid folder: expected '/', got '%v'", folderPath)
|
||||
}
|
||||
|
||||
h := d.NewHost(vmInfo.Runtime.Host)
|
||||
hostInfo, err := h.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read host properties: ", err)
|
||||
}
|
||||
if hostInfo.Name != host {
|
||||
t.Errorf("Invalid host name: expected '%v', got '%v'", host, hostInfo.Name)
|
||||
}
|
||||
|
||||
p := d.NewResourcePool(vmInfo.ResourcePool)
|
||||
poolPath, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
if poolPath != "" {
|
||||
t.Errorf("Invalid resource pool: expected '/', got '%v'", poolPath)
|
||||
}
|
||||
|
||||
dsr := vmInfo.Datastore[0].Reference()
|
||||
ds := d.NewDatastore(&dsr)
|
||||
dsInfo, err := ds.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read datastore properties: ", err)
|
||||
}
|
||||
if dsInfo.Name != datastore {
|
||||
t.Errorf("Invalid datastore name: expected '%v', got '%v'", datastore, dsInfo.Name)
|
||||
}
|
||||
|
||||
fw := vmInfo.Config.Firmware
|
||||
if fw != "bios" {
|
||||
t.Errorf("Invalid firmware: expected 'bios', got '%v'", fw)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_notes(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: notesConfig(),
|
||||
Check: checkNotes(t),
|
||||
})
|
||||
}
|
||||
|
||||
func notesConfig() string {
|
||||
config := defaultConfig()
|
||||
config["notes"] = "test"
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkNotes(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("config.annotation")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
notes := vmInfo.Config.Annotation
|
||||
if notes != "test" {
|
||||
t.Errorf("notes should be 'test'")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_hardware(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: hardwareConfig(),
|
||||
Check: checkHardware(t),
|
||||
})
|
||||
}
|
||||
|
||||
func hardwareConfig() string {
|
||||
config := defaultConfig()
|
||||
config["CPUs"] = 2
|
||||
config["cpu_cores"] = 2
|
||||
config["CPU_reservation"] = 1000
|
||||
config["CPU_limit"] = 1500
|
||||
config["RAM"] = 2048
|
||||
config["RAM_reservation"] = 1024
|
||||
config["NestedHV"] = true
|
||||
config["firmware"] = "efi"
|
||||
config["video_ram"] = 8192
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkHardware(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
vmInfo, err := vm.Info("config")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
cpuSockets := vmInfo.Config.Hardware.NumCPU
|
||||
if cpuSockets != 2 {
|
||||
t.Errorf("VM should have 2 CPU sockets, got %v", cpuSockets)
|
||||
}
|
||||
|
||||
cpuCores := vmInfo.Config.Hardware.NumCoresPerSocket
|
||||
if cpuCores != 2 {
|
||||
t.Errorf("VM should have 2 CPU cores per socket, got %v", cpuCores)
|
||||
}
|
||||
|
||||
cpuReservation := *vmInfo.Config.CpuAllocation.Reservation
|
||||
if cpuReservation != 1000 {
|
||||
t.Errorf("VM should have CPU reservation for 1000 Mhz, got %v", cpuReservation)
|
||||
}
|
||||
|
||||
cpuLimit := *vmInfo.Config.CpuAllocation.Limit
|
||||
if cpuLimit != 1500 {
|
||||
t.Errorf("VM should have CPU reservation for 1500 Mhz, got %v", cpuLimit)
|
||||
}
|
||||
|
||||
ram := vmInfo.Config.Hardware.MemoryMB
|
||||
if ram != 2048 {
|
||||
t.Errorf("VM should have 2048 MB of RAM, got %v", ram)
|
||||
}
|
||||
|
||||
ramReservation := *vmInfo.Config.MemoryAllocation.Reservation
|
||||
if ramReservation != 1024 {
|
||||
t.Errorf("VM should have RAM reservation for 1024 MB, got %v", ramReservation)
|
||||
}
|
||||
|
||||
nestedHV := vmInfo.Config.NestedHVEnabled
|
||||
if !*nestedHV {
|
||||
t.Errorf("VM should have NestedHV enabled, got %v", nestedHV)
|
||||
}
|
||||
|
||||
fw := vmInfo.Config.Firmware
|
||||
if fw != "efi" {
|
||||
t.Errorf("Invalid firmware: expected 'efi', got '%v'", fw)
|
||||
}
|
||||
|
||||
l, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM devices: %v", err)
|
||||
}
|
||||
c := l.PickController((*types.VirtualIDEController)(nil))
|
||||
if c == nil {
|
||||
t.Errorf("VM should have IDE controller")
|
||||
}
|
||||
s := l.PickController((*types.VirtualAHCIController)(nil))
|
||||
if s != nil {
|
||||
t.Errorf("VM should have no SATA controllers")
|
||||
}
|
||||
|
||||
v := l.SelectByType((*types.VirtualMachineVideoCard)(nil))
|
||||
if len(v) != 1 {
|
||||
t.Errorf("VM should have one video card")
|
||||
}
|
||||
if v[0].(*types.VirtualMachineVideoCard).VideoRamSizeInKB != 8192 {
|
||||
t.Errorf("Video RAM should be equal 8192")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_limit(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: limitConfig(),
|
||||
Check: checkLimit(t),
|
||||
})
|
||||
}
|
||||
|
||||
func limitConfig() string {
|
||||
config := defaultConfig()
|
||||
config["CPUs"] = 1 // hardware is customized, but CPU limit is not specified explicitly
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkLimit(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
vmInfo, err := vm.Info("config.cpuAllocation")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
limit := *vmInfo.Config.CpuAllocation.Limit
|
||||
if limit != -1 { // must be unlimited
|
||||
t.Errorf("Invalid CPU limit: expected '%v', got '%v'", -1, limit)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_sata(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: sataConfig(),
|
||||
Check: checkSata(t),
|
||||
})
|
||||
}
|
||||
|
||||
func sataConfig() string {
|
||||
config := defaultConfig()
|
||||
config["cdrom_type"] = "sata"
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkSata(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
l, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM devices: %v", err)
|
||||
}
|
||||
|
||||
c := l.PickController((*types.VirtualAHCIController)(nil))
|
||||
if c == nil {
|
||||
t.Errorf("VM has no SATA controllers")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_cdrom(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: cdromConfig(),
|
||||
})
|
||||
}
|
||||
|
||||
func cdromConfig() string {
|
||||
config := defaultConfig()
|
||||
config["iso_paths"] = []string{
|
||||
"[datastore1] test0.iso",
|
||||
"[datastore1] test1.iso",
|
||||
}
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_networkCard(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: networkCardConfig(),
|
||||
Check: checkNetworkCard(t),
|
||||
})
|
||||
}
|
||||
|
||||
func networkCardConfig() string {
|
||||
config := defaultConfig()
|
||||
config["network_adapters"] = map[string]interface{}{
|
||||
"network_card": "vmxnet3",
|
||||
}
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func checkNetworkCard(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
devices, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
netCards := devices.SelectByType((*types.VirtualEthernetCard)(nil))
|
||||
if len(netCards) == 0 {
|
||||
t.Fatalf("Cannot find the network card")
|
||||
}
|
||||
if len(netCards) > 1 {
|
||||
t.Fatalf("Found several network catds")
|
||||
}
|
||||
if _, ok := netCards[0].(*types.VirtualVmxnet3); !ok {
|
||||
t.Errorf("The network card type is not the expected one (vmxnet3)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_createFloppy(t *testing.T) {
|
||||
tmpFile, err := ioutil.TempFile("", "packer-vsphere-iso-test")
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating temp file: %v", err)
|
||||
}
|
||||
_, err = fmt.Fprint(tmpFile, "Hello, World!")
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating temp file: %v", err)
|
||||
}
|
||||
err = tmpFile.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating temp file: %v", err)
|
||||
}
|
||||
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: createFloppyConfig(tmpFile.Name()),
|
||||
})
|
||||
}
|
||||
|
||||
func createFloppyConfig(filePath string) string {
|
||||
config := defaultConfig()
|
||||
config["floppy_files"] = []string{filePath}
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_full(t *testing.T) {
|
||||
config := fullConfig()
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: commonT.RenderConfig(config),
|
||||
Check: checkFull(t),
|
||||
})
|
||||
}
|
||||
|
||||
func fullConfig() map[string]interface{} {
|
||||
username := os.Getenv("VSPHERE_USERNAME")
|
||||
if username == "" {
|
||||
username = "root"
|
||||
}
|
||||
password := os.Getenv("VSPHERE_PASSWORD")
|
||||
if password == "" {
|
||||
password = "jetbrains"
|
||||
}
|
||||
|
||||
config := map[string]interface{}{
|
||||
"vcenter_server": "vcenter.vsphere65.test",
|
||||
"username": username,
|
||||
"password": password,
|
||||
"insecure_connection": true,
|
||||
|
||||
"vm_name": commonT.NewVMName(),
|
||||
"host": "esxi-1.vsphere65.test",
|
||||
|
||||
"RAM": 512,
|
||||
"disk_controller_type": []string{
|
||||
"pvscsi",
|
||||
},
|
||||
"storage": map[string]interface{}{
|
||||
"disk_size": 1024,
|
||||
"disk_thin_provisioned": true,
|
||||
},
|
||||
"network_adapters": map[string]interface{}{
|
||||
"network_card": "vmxnet3",
|
||||
},
|
||||
"guest_os_type": "other3xLinux64Guest",
|
||||
|
||||
"iso_paths": []string{
|
||||
"[datastore1] ISO/alpine-standard-3.8.2-x86_64.iso",
|
||||
},
|
||||
"floppy_files": []string{
|
||||
"../examples/alpine/answerfile",
|
||||
"../examples/alpine/setup.sh",
|
||||
},
|
||||
|
||||
"boot_wait": "20s",
|
||||
"boot_command": []string{
|
||||
"root<enter><wait>",
|
||||
"mount -t vfat /dev/fd0 /media/floppy<enter><wait>",
|
||||
"setup-alpine -f /media/floppy/answerfile<enter>",
|
||||
"<wait5>",
|
||||
"jetbrains<enter>",
|
||||
"jetbrains<enter>",
|
||||
"<wait5>",
|
||||
"y<enter>",
|
||||
"<wait10><wait10><wait10><wait10>",
|
||||
"reboot<enter>",
|
||||
"<wait10><wait10><wait10>",
|
||||
"root<enter>",
|
||||
"jetbrains<enter><wait>",
|
||||
"mount -t vfat /dev/fd0 /media/floppy<enter><wait>",
|
||||
"/media/floppy/SETUP.SH<enter>",
|
||||
},
|
||||
|
||||
"ssh_username": "root",
|
||||
"ssh_password": "jetbrains",
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func checkFull(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("config.bootOptions")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
order := vmInfo.Config.BootOptions.BootOrder
|
||||
if order != nil {
|
||||
t.Errorf("Boot order must be empty")
|
||||
}
|
||||
|
||||
devices, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read devices: %v", err)
|
||||
}
|
||||
cdroms := devices.SelectByType((*types.VirtualCdrom)(nil))
|
||||
for _, cd := range cdroms {
|
||||
_, ok := cd.(*types.VirtualCdrom).Backing.(*types.VirtualCdromRemotePassthroughBackingInfo)
|
||||
if !ok {
|
||||
t.Errorf("wrong cdrom backing")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_bootOrder(t *testing.T) {
|
||||
config := fullConfig()
|
||||
config["boot_order"] = "disk,cdrom,floppy"
|
||||
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: commonT.RenderConfig(config),
|
||||
Check: checkBootOrder(t),
|
||||
})
|
||||
}
|
||||
|
||||
func checkBootOrder(t *testing.T) builderT.TestCheckFunc {
|
||||
return func(artifacts []packersdk.Artifact) error {
|
||||
d := commonT.TestConn(t)
|
||||
vm := commonT.GetVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := vm.Info("config.bootOptions")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
order := vmInfo.Config.BootOptions.BootOrder
|
||||
if order == nil {
|
||||
t.Errorf("Boot order must not be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_cluster(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: clusterConfig(),
|
||||
})
|
||||
}
|
||||
|
||||
func clusterConfig() string {
|
||||
config := defaultConfig()
|
||||
config["cluster"] = "cluster1"
|
||||
config["host"] = "esxi-2.vsphere65.test"
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
||||
|
||||
func TestISOBuilderAcc_clusterDRS(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
Builder: &Builder{},
|
||||
Template: clusterDRSConfig(),
|
||||
})
|
||||
}
|
||||
|
||||
func clusterDRSConfig() string {
|
||||
config := defaultConfig()
|
||||
config["cluster"] = "cluster2"
|
||||
config["host"] = ""
|
||||
config["datastore"] = "datastore3" // bug #183
|
||||
config["network_adapters"] = map[string]interface{}{
|
||||
"network": "VM Network",
|
||||
}
|
||||
|
||||
return commonT.RenderConfig(config)
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package iso
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func basicStateBag() *multistep.BasicStateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
return state
|
||||
}
|
|
@ -1,417 +0,0 @@
|
|||
package iso
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
"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) {
|
||||
// Empty config - check defaults
|
||||
config := &CreateConfig{
|
||||
// Storage is required
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if errs := config.Prepare(); len(errs) != 0 {
|
||||
t.Fatalf("Config preprare should not fail: %s", errs[0])
|
||||
}
|
||||
if config.GuestOSType != "otherGuest" {
|
||||
t.Fatalf("GuestOSType should default to 'otherGuest'")
|
||||
}
|
||||
if len(config.StorageConfig.DiskControllerType) != 1 {
|
||||
t.Fatalf("DiskControllerType should have at least one element as default")
|
||||
}
|
||||
|
||||
// Data validation
|
||||
tc := []struct {
|
||||
name string
|
||||
config *CreateConfig
|
||||
fail bool
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "Storage validate disk_size",
|
||||
config: &CreateConfig{
|
||||
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: &CreateConfig{
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskControllerIndex: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "storage[0].'disk_controller_index' references an unknown disk controller",
|
||||
},
|
||||
{
|
||||
name: "USBController validate 'usb' and 'xhci' can be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"usb", "xhci"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "USBController validate '1' and '0' can be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"1", "0"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "USBController validate 'true' and 'false' can be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"true", "false"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
name: "USBController validate 'true' and 'usb' cannot be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"true", "usb"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "there can only be one usb controller and one xhci controller",
|
||||
},
|
||||
{
|
||||
name: "USBController validate '1' and 'usb' cannot be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"1", "usb"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "there can only be one usb controller and one xhci controller",
|
||||
},
|
||||
{
|
||||
name: "USBController validate 'xhci' cannot be set more that once",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"xhci", "xhci"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "there can only be one usb controller and one xhci controller",
|
||||
},
|
||||
{
|
||||
name: "USBController validate unknown value cannot be set",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"unknown"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "usb_controller[0] references an unknown usb controller",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
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 := basicStateBag()
|
||||
driverMock := driver.NewDriverMock()
|
||||
state.Put("driver", driverMock)
|
||||
step := basicStepCreateVM()
|
||||
step.Force = true
|
||||
vmPath := path.Join(step.Location.Folder, step.Location.VMName)
|
||||
|
||||
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.CreateVMCalled {
|
||||
t.Fatalf("driver.CreateVM should be called.")
|
||||
}
|
||||
if diff := cmp.Diff(driverMock.CreateConfig, 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 TestStepCreateVM_RunHalt(t *testing.T) {
|
||||
state := basicStateBag()
|
||||
step := basicStepCreateVM()
|
||||
|
||||
// PreCleanVM fails
|
||||
driverMock := driver.NewDriverMock()
|
||||
driverMock.PreCleanShouldFail = true
|
||||
state.Put("driver", driverMock)
|
||||
if action := step.Run(context.TODO(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("Step should halt.")
|
||||
}
|
||||
if !driverMock.PreCleanVMCalled {
|
||||
t.Fatalf("driver.PreCleanVM should be called")
|
||||
}
|
||||
|
||||
// CreateVM fails
|
||||
driverMock = driver.NewDriverMock()
|
||||
driverMock.CreateVMShouldFail = true
|
||||
state.Put("driver", driverMock)
|
||||
if action := step.Run(context.TODO(), state); action != multistep.ActionHalt {
|
||||
t.Fatalf("Step should halt.")
|
||||
}
|
||||
if !driverMock.PreCleanVMCalled {
|
||||
t.Fatalf("driver.PreCleanVM should be called")
|
||||
}
|
||||
if !driverMock.CreateVMCalled {
|
||||
t.Fatalf("driver.PreCleanVM should be called")
|
||||
}
|
||||
if _, ok := state.GetOk("vm"); ok {
|
||||
t.Fatal("state should not contain a VM")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateVM_Cleanup(t *testing.T) {
|
||||
state := basicStateBag()
|
||||
step := basicStepCreateVM()
|
||||
vm := new(driver.VirtualMachineMock)
|
||||
state.Put("vm", vm)
|
||||
|
||||
// Clean up when state is cancelled
|
||||
state.Put(multistep.StateCancelled, true)
|
||||
step.Cleanup(state)
|
||||
if !vm.DestroyCalled {
|
||||
t.Fatalf("vm.Destroy should be called")
|
||||
}
|
||||
vm.DestroyCalled = false
|
||||
state.Remove(multistep.StateCancelled)
|
||||
|
||||
// Clean up when state is halted
|
||||
state.Put(multistep.StateHalted, true)
|
||||
step.Cleanup(state)
|
||||
if !vm.DestroyCalled {
|
||||
t.Fatalf("vm.Destroy should be called")
|
||||
}
|
||||
vm.DestroyCalled = false
|
||||
state.Remove(multistep.StateHalted)
|
||||
|
||||
// Clean up when state is destroy_vm is set
|
||||
state.Put("destroy_vm", true)
|
||||
step.Cleanup(state)
|
||||
if !vm.DestroyCalled {
|
||||
t.Fatalf("vm.Destroy should be called")
|
||||
}
|
||||
vm.DestroyCalled = false
|
||||
state.Remove("destroy_vm")
|
||||
|
||||
// Don't clean up if state is not set with previous values
|
||||
step.Cleanup(state)
|
||||
if vm.DestroyCalled {
|
||||
t.Fatalf("vm.Destroy should not be called")
|
||||
}
|
||||
|
||||
// Destroy fail
|
||||
errorBuffer := &strings.Builder{}
|
||||
ui := &packersdk.BasicUi{
|
||||
Reader: strings.NewReader(""),
|
||||
Writer: ioutil.Discard,
|
||||
ErrorWriter: errorBuffer,
|
||||
}
|
||||
state.Put("ui", ui)
|
||||
state.Put(multistep.StateCancelled, true)
|
||||
vm.DestroyError = errors.New("destroy failed")
|
||||
|
||||
step.Cleanup(state)
|
||||
if !vm.DestroyCalled {
|
||||
t.Fatalf("vm.Destroy should be called")
|
||||
}
|
||||
if !strings.Contains(errorBuffer.String(), vm.DestroyError.Error()) {
|
||||
t.Fatalf("Destroy should fail with error message '%s' but failed with '%s'", vm.DestroyError.Error(), errorBuffer.String())
|
||||
}
|
||||
vm.DestroyCalled = false
|
||||
state.Remove(multistep.StateCancelled)
|
||||
|
||||
// Should not destroy if VM is not set
|
||||
state.Remove("vm")
|
||||
state.Put(multistep.StateCancelled, true)
|
||||
step.Cleanup(state)
|
||||
if vm.DestroyCalled {
|
||||
t.Fatalf("vm.Destroy should not be called")
|
||||
}
|
||||
}
|
||||
|
||||
func basicStepCreateVM() *StepCreateVM {
|
||||
step := &StepCreateVM{
|
||||
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() *CreateConfig {
|
||||
return &CreateConfig{
|
||||
Version: 1,
|
||||
GuestOSType: "ubuntu64Guest",
|
||||
StorageConfig: common.StorageConfig{
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskThinProvisioned: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
NICs: []NIC{
|
||||
{
|
||||
Network: "VM Network",
|
||||
NetworkCard: "vmxnet3",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func driverCreateConfig(config *CreateConfig, location *common.LocationConfig) *driver.CreateConfig {
|
||||
var networkCards []driver.NIC
|
||||
for _, nic := range config.NICs {
|
||||
networkCards = append(networkCards, driver.NIC{
|
||||
Network: nic.Network,
|
||||
NetworkCard: nic.NetworkCard,
|
||||
MacAddress: nic.MacAddress,
|
||||
Passthrough: nic.Passthrough,
|
||||
})
|
||||
}
|
||||
|
||||
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.CreateConfig{
|
||||
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,
|
||||
GuestOS: config.GuestOSType,
|
||||
NICs: networkCards,
|
||||
USBController: config.USBController,
|
||||
Version: config.Version,
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
dev tun
|
||||
persist-tun
|
||||
persist-key
|
||||
cipher AES-256-CBC
|
||||
ncp-ciphers AES-256-GCM:AES-128-GCM
|
||||
auth SHA1
|
||||
tls-client
|
||||
client
|
||||
resolv-retry infinite
|
||||
remote 91.132.204.28 2000 tcp-client
|
||||
remote-cert-tls server
|
||||
|
||||
pkcs12 lab.p12
|
||||
|
||||
<tls-auth>
|
||||
#
|
||||
# 2048 bit OpenVPN static key
|
||||
#
|
||||
-----BEGIN OpenVPN Static key V1-----
|
||||
6c9efab783fc2ee1a558bcedeaf92f8d
|
||||
85322bc05432fbb00745fcd00bb48857
|
||||
77cbf0c82462726a848657c56b62f6fd
|
||||
b9b1622c633188e848ce78c1b4476e9f
|
||||
938338532c79784f36d80156e3b29bcf
|
||||
493e64c393ee216b776c7a5d62c03aa8
|
||||
5fc5fea73990612f07660988da133b61
|
||||
34c847e67f65b8af407ae0b2761de402
|
||||
49ede990747659a878acaaf8fa1a6201
|
||||
1aa8ec5aeb01ccf50d1dc6e675dea291
|
||||
8d4c199c1c126fee9c112ce16c736159
|
||||
3234d5eaea167f5e60d01ad618fd33bb
|
||||
c262fb3d5227933d6149e45ab0246d58
|
||||
5f5d66d835fbfc8e8d51e0462194d835
|
||||
8f66f166ccef5616abba26dd38046a87
|
||||
9476359e2dc7a5b4dc045e3fbe39d6e6
|
||||
-----END OpenVPN Static key V1-----
|
||||
</tls-auth>
|
||||
key-direction 1
|
Binary file not shown.
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA2J9w3cbqMJSDTCUtFW3qRHhqgXbSOW32anqEWQYvW48WKXJm
|
||||
ZmuuSViC0tcAMCnX8pu5YGlAMCi5RBDtdoE9mZzUCfE4Q1Om42S2jKRrSSbhU9Ts
|
||||
8jTRL0V81Tja64SEt5l1dDHS5sgNJy8C4nWaWob1HT+YloPEllj80ogwoQoL3ufp
|
||||
r5me/TOrA3ApHXewWm0feBkkkuN6NkL1Z9sILCstLrjD+RVEOvI/wrHZEaLpYJ4P
|
||||
LgS8LmTNKaFafmqwgcC4VcA4kVbhxw9X385v+mQLqpiOJa+vS51dT2qINEw+80Y+
|
||||
HL7k7OIZTLg803wubI3rUZQ/2PX/STBq1zO9RwIDAQABAoIBAAmrDBGJ6Dfk2PtU
|
||||
CXAUaMlHipFeqUFQ7BeSgkeq5AA1IasV5QYbNjslzSj12ZdMtsuoMZzg9bFwj9w+
|
||||
2SpZ2FL70ebjsjwnBqLNguxCBlvMdXAVZ8Hjo5Z1hn3JvNOYJYhAPCLEeoI8WYHv
|
||||
MjTDRPFXZqc4iGnnVaXUMOyAkZMOV6sMQzvuJad4x7gvQGRhCgcdnFdGbVs+MZQc
|
||||
WPI6cO6imj27F6rJK3W6s5XcSjDbkpytf2wUuWYgck93Fdm3kYy3ER6B3P/MiM95
|
||||
qGRmg6OuEYbXAr4ytamjKUThl83SGvDS89N5SIjS5rgrEBgrOFBgMhjG/ibaxbrh
|
||||
c84oplECgYEA+vyI4VUYgce8voYmdDijlM/NwPbCpD3SGiyXIYcDN1i/CUdDhBYh
|
||||
z4982H6I1b2cg+veBWICro9Dp20CpfGtXT6Y3o1yNWkbKlosd+f2Us10fG1gkcyI
|
||||
TiZCYaJPrtdoTT0vMKbdUbkgn0FLNbW1TCh5FQ7K7RXhDonb9BbsTzkCgYEA3PMu
|
||||
bv/MgaET654GAItudazJmh4FfR905w59yVNJfe+7iG/f5zzv7vIpaERvBo245hcu
|
||||
IaO8QbW5OKYuCaNIjGOSd1uxN5ytcOHcf1bmjS+WRQdu/FR5v9BM0BY66NFjqKMb
|
||||
dZLXVZPnU3EOqCKmi9SI2VOVKrDL5XzMOHhL8H8CgYBFJh5wNomx993AgCVID/LB
|
||||
pR8C8vldVsrz+yUIT7JLJWA8pi2rzo0yKk4zN2lrufnNPsbEpOQoQ8BX+GiqX5Ns
|
||||
BTsI1d+JZ5Pcb0uhHX94ALL/NQNOKBPFtDTFwXpCqYZLAXhm5xJC2cZrGgommhGB
|
||||
EgWKD7FI8KY44zJ+ZXJlwQKBgGvw/eFKZI17tPCp3cLMW2VvyXnaatIK2SC8SqVd
|
||||
ZAz7XoG0Lg2ZDpqMgcAnlpn8CLWX43iZtjHf5qIPRXR96cZ0KqzXBcfmajE4lnE7
|
||||
chzNf7sve4AYgPY9fBk4kwUEroxHSvXwi/SJ8jwogoGPlA/CAC00ES6u+p2dj2OT
|
||||
GX5fAoGBAM6saTeyjAjLDE/vlPM9OButsoj5CJg7DklRgrRuRyygbyRBudafslnl
|
||||
8e4+4mlXEBwKDnrDTtXFhX1Ur95/w/4GjyFXO/TB/Tmn+vaEBQTzgViKc2cJ/yay
|
||||
ttiF6oJh9EjCaFDTz5P11wX7DajRux/2tUcBXX/C3FcGhNEkVb2P
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -1 +0,0 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYn3DdxuowlINMJS0VbepEeGqBdtI5bfZqeoRZBi9bjxYpcmZma65JWILS1wAwKdfym7lgaUAwKLlEEO12gT2ZnNQJ8ThDU6bjZLaMpGtJJuFT1OzyNNEvRXzVONrrhIS3mXV0MdLmyA0nLwLidZpahvUdP5iWg8SWWPzSiDChCgve5+mvmZ79M6sDcCkdd7BabR94GSSS43o2QvVn2wgsKy0uuMP5FUQ68j/CsdkRoulgng8uBLwuZM0poVp+arCBwLhVwDiRVuHHD1ffzm/6ZAuqmI4lr69LnV1Paog0TD7zRj4cvuTs4hlMuDzTfC5sjetRlD/Y9f9JMGrXM71H
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var VSpherePluginVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
VSpherePluginVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -56,8 +56,6 @@ import (
|
|||
virtualboxvmbuilder "github.com/hashicorp/packer/builder/virtualbox/vm"
|
||||
vmwareisobuilder "github.com/hashicorp/packer/builder/vmware/iso"
|
||||
vmwarevmxbuilder "github.com/hashicorp/packer/builder/vmware/vmx"
|
||||
vsphereclonebuilder "github.com/hashicorp/packer/builder/vsphere/clone"
|
||||
vsphereisobuilder "github.com/hashicorp/packer/builder/vsphere/iso"
|
||||
yandexbuilder "github.com/hashicorp/packer/builder/yandex"
|
||||
alicloudimportpostprocessor "github.com/hashicorp/packer/post-processor/alicloud-import"
|
||||
artificepostprocessor "github.com/hashicorp/packer/post-processor/artifice"
|
||||
|
@ -71,8 +69,6 @@ import (
|
|||
ucloudimportpostprocessor "github.com/hashicorp/packer/post-processor/ucloud-import"
|
||||
vagrantpostprocessor "github.com/hashicorp/packer/post-processor/vagrant"
|
||||
vagrantcloudpostprocessor "github.com/hashicorp/packer/post-processor/vagrant-cloud"
|
||||
vspherepostprocessor "github.com/hashicorp/packer/post-processor/vsphere"
|
||||
vspheretemplatepostprocessor "github.com/hashicorp/packer/post-processor/vsphere-template"
|
||||
yandexexportpostprocessor "github.com/hashicorp/packer/post-processor/yandex-export"
|
||||
yandeximportpostprocessor "github.com/hashicorp/packer/post-processor/yandex-import"
|
||||
ansibleprovisioner "github.com/hashicorp/packer/provisioner/ansible"
|
||||
|
@ -143,8 +139,6 @@ var Builders = map[string]packersdk.Builder{
|
|||
"virtualbox-vm": new(virtualboxvmbuilder.Builder),
|
||||
"vmware-iso": new(vmwareisobuilder.Builder),
|
||||
"vmware-vmx": new(vmwarevmxbuilder.Builder),
|
||||
"vsphere-clone": new(vsphereclonebuilder.Builder),
|
||||
"vsphere-iso": new(vsphereisobuilder.Builder),
|
||||
"yandex": new(yandexbuilder.Builder),
|
||||
}
|
||||
|
||||
|
@ -182,8 +176,6 @@ var PostProcessors = map[string]packersdk.PostProcessor{
|
|||
"ucloud-import": new(ucloudimportpostprocessor.PostProcessor),
|
||||
"vagrant": new(vagrantpostprocessor.PostProcessor),
|
||||
"vagrant-cloud": new(vagrantcloudpostprocessor.PostProcessor),
|
||||
"vsphere": new(vspherepostprocessor.PostProcessor),
|
||||
"vsphere-template": new(vspheretemplatepostprocessor.PostProcessor),
|
||||
"yandex-export": new(yandexexportpostprocessor.PostProcessor),
|
||||
"yandex-import": new(yandeximportpostprocessor.PostProcessor),
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ import (
|
|||
dockerpushpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-push"
|
||||
dockersavepostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-save"
|
||||
dockertagpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-tag"
|
||||
vsphereclonebuilder "github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone"
|
||||
vsphereisobuilder "github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso"
|
||||
vspherepostprocessor "github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere"
|
||||
vspheretemplatepostprocessor "github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template"
|
||||
)
|
||||
|
||||
// VendoredDatasources are datasource components that were once bundled with the
|
||||
|
@ -38,6 +42,8 @@ var VendoredBuilders = map[string]packersdk.Builder{
|
|||
"amazon-ebssurrogate": new(amazonebssurrogatebuilder.Builder),
|
||||
"amazon-ebsvolume": new(amazonebsvolumebuilder.Builder),
|
||||
"amazon-instance": new(amazoninstancebuilder.Builder),
|
||||
"vsphere-clone": new(vsphereclonebuilder.Builder),
|
||||
"vsphere-iso": new(vsphereisobuilder.Builder),
|
||||
}
|
||||
|
||||
// VendoredProvisioners are provisioner components that were once bundled with the
|
||||
|
@ -53,6 +59,8 @@ var VendoredPostProcessors = map[string]packersdk.PostProcessor{
|
|||
"docker-tag": new(dockertagpostprocessor.PostProcessor),
|
||||
"exoscale-import": new(exoscaleimportpostprocessor.PostProcessor),
|
||||
"amazon-import": new(anazibimportpostprocessor.PostProcessor),
|
||||
"vsphere": new(vspherepostprocessor.PostProcessor),
|
||||
"vsphere-template": new(vspheretemplatepostprocessor.PostProcessor),
|
||||
}
|
||||
|
||||
// Upon init lets load up any plugins that were vendored manually into the default
|
||||
|
|
6
go.mod
6
go.mod
|
@ -52,7 +52,8 @@ require (
|
|||
github.com/hashicorp/hcl/v2 v2.9.1
|
||||
github.com/hashicorp/packer-plugin-amazon v0.0.1
|
||||
github.com/hashicorp/packer-plugin-docker v0.0.7
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.3-0.20210407132324-af39c7839daf
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.3
|
||||
github.com/hashicorp/packer-plugin-vsphere v0.0.0-20210415100050-d0269b5646e6
|
||||
github.com/hashicorp/vault/api v1.0.4
|
||||
github.com/hetznercloud/hcloud-go v1.15.1
|
||||
github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4
|
||||
|
@ -83,14 +84,13 @@ require (
|
|||
github.com/ucloud/ucloud-sdk-go v0.16.3
|
||||
github.com/ufilesdk-dev/ufile-gosdk v0.0.0-20190830075812-b4dbc4ef43a6
|
||||
github.com/ulikunitz/xz v0.5.6
|
||||
github.com/vmware/govmomi v0.23.1
|
||||
github.com/vmware/govmomi v0.24.1
|
||||
github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20200915125933-33de72a328bd
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20200921111412-ef15ded2014c
|
||||
github.com/zclconf/go-cty v1.8.1
|
||||
github.com/zclconf/go-cty-yaml v1.0.1
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
||||
golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2
|
||||
golang.org/x/mod v0.3.0
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
||||
|
|
12
go.sum
12
go.sum
|
@ -448,8 +448,10 @@ github.com/hashicorp/packer-plugin-sdk v0.0.14/go.mod h1:tNb3XzJPnjMl3QuUdKmF47B
|
|||
github.com/hashicorp/packer-plugin-sdk v0.1.0/go.mod h1:CFsC20uZjtER/EnTn/CSMKD0kEdkqOVev8mtOmfnZiI=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.1/go.mod h1:1d3nqB9LUsXMQaNUiL67Q+WYEtjsVcLNTX8ikVlpBrc=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.2/go.mod h1:KRjczE1/c9NV5Re+PXt3myJsVTI/FxEHpZjRjOH0Fug=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.3-0.20210407132324-af39c7839daf h1:0DBlIExTDefzbfkOl213QtgJsVJXWdgW/aIQIvYUMzs=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.3-0.20210407132324-af39c7839daf/go.mod h1:xePpgQgQYv/bamiypx3hH9ukidxDdcN8q0R0wLi8IEQ=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.3 h1:oHTVlgoX2piUzL54+LBo9uIMfW+L/kY7or83dDStdIY=
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.3/go.mod h1:xePpgQgQYv/bamiypx3hH9ukidxDdcN8q0R0wLi8IEQ=
|
||||
github.com/hashicorp/packer-plugin-vsphere v0.0.0-20210415100050-d0269b5646e6 h1:pOv7Apd4P3KEpNBHLV4E7tKlwHoInCU/bnPVadGSDxY=
|
||||
github.com/hashicorp/packer-plugin-vsphere v0.0.0-20210415100050-d0269b5646e6/go.mod h1:XMhsLDDT7sD2BWaruLvGPynnn4IqdbrfvuKhb1GK1RI=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hashicorp/serf v0.9.2 h1:yJoyfZXo4Pk2p/M/viW+YLibBFiIbKoP79gu7kDAFP0=
|
||||
github.com/hashicorp/serf v0.9.2/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
|
@ -695,8 +697,9 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+
|
|||
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/vmware/govmomi v0.23.1 h1:vU09hxnNR/I7e+4zCJvW+5vHu5dO64Aoe2Lw7Yi/KRg=
|
||||
github.com/vmware/govmomi v0.23.1/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc=
|
||||
github.com/vmware/govmomi v0.24.1 h1:ecVvrxF28/5g738gLTiYgc62fpGfIPRKheQ1Dj1p35w=
|
||||
github.com/vmware/govmomi v0.24.1/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc=
|
||||
github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk=
|
||||
github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0 h1:NJrcIkdzq0C3I8ypAZwFE9RHtGbfp+mJvqIcoFATZuk=
|
||||
github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0/go.mod h1:sBh287mCRwCz6zyXHMmw7sSZGPohVpnx+o+OY4M+i3A=
|
||||
|
@ -773,8 +776,9 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI
|
|||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20191130191448-5c0e7e404af8/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ=
|
||||
golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2 h1:3HADozU50HyrJ2jklLtr3xr0itFkz9u4LxCJhqKVdjI=
|
||||
golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 h1:h+GZ3ubjuWaQjGe8owMGcmMVCqs0xYJtRG5y2bpHaqU=
|
||||
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package vsphere_template
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getTestConfig() Config {
|
||||
return Config{
|
||||
Username: "me",
|
||||
Password: "notpassword",
|
||||
Host: "myhost",
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigure_Good(t *testing.T) {
|
||||
var p PostProcessor
|
||||
|
||||
config := getTestConfig()
|
||||
|
||||
err := p.Configure(config)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigure_ReRegisterVM(t *testing.T) {
|
||||
var p PostProcessor
|
||||
|
||||
config := getTestConfig()
|
||||
|
||||
err := p.Configure(config)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err)
|
||||
}
|
||||
|
||||
if p.config.ReregisterVM.False() {
|
||||
t.Errorf("This should default to unset, not false.")
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var VSphereTemplatePostprocessorVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
VSphereTemplatePostprocessorVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package vsphere
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func TestArtifact_ImplementsArtifact(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Artifact{}
|
||||
if _, ok := raw.(packersdk.Artifact); !ok {
|
||||
t.Fatalf("Artifact should be a Artifact")
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifact_Id(t *testing.T) {
|
||||
artifact := NewArtifact("datastore", "vmfolder", "vmname", nil)
|
||||
if artifact.Id() != "datastore::vmfolder::vmname" {
|
||||
t.Fatalf("must return datastore, vmfolder and vmname splitted by :: as Id")
|
||||
}
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
package vsphere
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getTestConfig() Config {
|
||||
return Config{
|
||||
Username: "me",
|
||||
Password: "notpassword",
|
||||
Host: "myhost",
|
||||
Datacenter: "mydc",
|
||||
Cluster: "mycluster",
|
||||
VMName: "my vm",
|
||||
Datastore: "my datastore",
|
||||
Insecure: true,
|
||||
DiskMode: "thin",
|
||||
VMFolder: "my folder",
|
||||
}
|
||||
}
|
||||
|
||||
func TestArgs(t *testing.T) {
|
||||
var p PostProcessor
|
||||
|
||||
p.config = getTestConfig()
|
||||
|
||||
source := "something.vmx"
|
||||
ovftool_uri := fmt.Sprintf("vi://%s:%s@%s/%s/host/%s",
|
||||
url.QueryEscape(p.config.Username),
|
||||
url.QueryEscape(p.config.Password),
|
||||
p.config.Host,
|
||||
p.config.Datacenter,
|
||||
p.config.Cluster)
|
||||
|
||||
if p.config.ResourcePool != "" {
|
||||
ovftool_uri += "/Resources/" + p.config.ResourcePool
|
||||
}
|
||||
|
||||
args, err := p.BuildArgs(source, ovftool_uri)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err)
|
||||
}
|
||||
|
||||
t.Logf("ovftool %s", strings.Join(args, " "))
|
||||
}
|
||||
|
||||
func TestGenerateURI_Basic(t *testing.T) {
|
||||
var p PostProcessor
|
||||
|
||||
p.config = getTestConfig()
|
||||
|
||||
uri, err := p.generateURI()
|
||||
if err != nil {
|
||||
t.Fatalf("had error: %s", err)
|
||||
}
|
||||
expected_uri := "vi://me:notpassword@myhost/mydc/host/mycluster"
|
||||
if uri.String() != expected_uri {
|
||||
t.Fatalf("URI did not match. Recieved: %s. Expected: %s", uri, expected_uri)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateURI_PasswordEscapes(t *testing.T) {
|
||||
type escapeCases struct {
|
||||
Input string
|
||||
Expected string
|
||||
}
|
||||
|
||||
cases := []escapeCases{
|
||||
{`this has spaces`, `this%20has%20spaces`},
|
||||
{`exclaimation_!`, `exclaimation_%21`},
|
||||
{`hash_#_dollar_$`, `hash_%23_dollar_$`},
|
||||
{`ampersand_&awesome`, `ampersand_&awesome`},
|
||||
{`single_quote_'_and_another_'`, `single_quote_%27_and_another_%27`},
|
||||
{`open_paren_(_close_paren_)`, `open_paren_%28_close_paren_%29`},
|
||||
{`asterisk_*_plus_+`, `asterisk_%2A_plus_+`},
|
||||
{`comma_,slash_/`, `comma_,slash_%2F`},
|
||||
{`colon_:semicolon_;`, `colon_%3Asemicolon_;`},
|
||||
{`equal_=question_?`, `equal_=question_%3F`},
|
||||
{`at_@`, `at_%40`},
|
||||
{`open_bracket_[closed_bracket]`, `open_bracket_%5Bclosed_bracket%5D`},
|
||||
{`user:password with $paces@host/name.foo`, `user%3Apassword%20with%20$paces%40host%2Fname.foo`},
|
||||
}
|
||||
|
||||
for _, escapeCase := range cases {
|
||||
var p PostProcessor
|
||||
|
||||
p.config = getTestConfig()
|
||||
p.config.Password = escapeCase.Input
|
||||
|
||||
uri, err := p.generateURI()
|
||||
if err != nil {
|
||||
t.Fatalf("had error: %s", err)
|
||||
}
|
||||
expected_uri := fmt.Sprintf("vi://me:%s@myhost/mydc/host/mycluster", escapeCase.Expected)
|
||||
|
||||
if uri.String() != expected_uri {
|
||||
t.Fatalf("URI did not match. Recieved: %s. Expected: %s", uri, expected_uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEncodedPassword(t *testing.T) {
|
||||
|
||||
// Password is encoded, and contains a colon
|
||||
ovftool_uri := fmt.Sprintf("vi://hostname/Datacenter/host/cluster")
|
||||
|
||||
u, _ := url.Parse(ovftool_uri)
|
||||
u.User = url.UserPassword("us:ername", "P@ssW:rd")
|
||||
|
||||
encoded, isSet := getEncodedPassword(u)
|
||||
expected := "P%40ssW%3Ard"
|
||||
if !isSet {
|
||||
t.Fatalf("Password is set but test said it is not")
|
||||
}
|
||||
if encoded != expected {
|
||||
t.Fatalf("Should have successfully gotten encoded password. Expected: %s; recieved: %s", expected, encoded)
|
||||
}
|
||||
|
||||
// There is no password
|
||||
u.User = url.UserPassword("us:ername", "")
|
||||
|
||||
_, isSet = getEncodedPassword(u)
|
||||
if isSet {
|
||||
t.Fatalf("Should have determined that password was not set")
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
packerVersion "github.com/hashicorp/packer/version"
|
||||
)
|
||||
|
||||
var VSpherePostprocessorVersion *version.PluginVersion
|
||||
|
||||
func init() {
|
||||
VSpherePostprocessorVersion = version.InitializePluginVersion(
|
||||
packerVersion.Version, packerVersion.VersionPrerelease)
|
||||
}
|
|
@ -0,0 +1,373 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
|
@ -9,8 +9,8 @@ import (
|
|||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
type Builder struct {
|
|
@ -10,7 +10,7 @@ import (
|
|||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common"
|
||||
)
|
||||
|
||||
type Config struct {
|
|
@ -4,7 +4,7 @@ package clone
|
|||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
|
@ -10,8 +10,8 @@ import (
|
|||
|
||||
"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"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
type vAppConfig struct {
|
|
@ -4,7 +4,7 @@ package clone
|
|||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
|
@ -3,7 +3,7 @@ package common
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
const BuilderId = "jetbrains.vsphere"
|
|
@ -3,7 +3,7 @@ package common
|
|||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func CleanupVM(state multistep.StateBag) {
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
type CDRomConfig struct {
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
type FloppyConfig struct {
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
"golang.org/x/mobile/event/key"
|
||||
)
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
type ConfigParamsConfig struct {
|
|
@ -8,7 +8,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
type ConnectConfig struct {
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
// Defining this interface ensures that we use the common step download, or the
|
|
@ -20,7 +20,7 @@ import (
|
|||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vmware/govmomi/nfc"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
type HardwareConfig struct {
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver"
|
||||
"github.com/vmware/govmomi/vapi/vcenter"
|
||||
)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue