From 38fe79948ba7190e8c3032cc5fe0d4056b1e66c3 Mon Sep 17 00:00:00 2001 From: sylviamoss Date: Fri, 9 Apr 2021 14:41:11 +0200 Subject: [PATCH] remove vsphere components and docs --- builder/vsphere/clone/builder.go | 175 --- builder/vsphere/clone/builder_acc_test.go | 734 ----------- builder/vsphere/clone/builder_test.go | 15 - builder/vsphere/clone/config.go | 104 -- builder/vsphere/clone/config.hcl2spec.go | 282 ----- builder/vsphere/clone/config_test.go | 74 -- builder/vsphere/clone/step_clone.go | 136 -- builder/vsphere/clone/step_clone.hcl2spec.go | 71 -- builder/vsphere/clone/step_clone_test.go | 251 ---- builder/vsphere/clone/step_customize.go | 276 ----- .../vsphere/clone/step_customize.hcl2spec.go | 155 --- builder/vsphere/common/artifact.go | 50 - builder/vsphere/common/cleanup_vm.go | 30 - builder/vsphere/common/cleanup_vm_test.go | 62 - builder/vsphere/common/common_test.go | 19 - builder/vsphere/common/config_location.go | 53 - .../common/config_location.hcl2spec.go | 43 - builder/vsphere/common/config_ssh.go | 15 - builder/vsphere/common/output_config.go | 59 - .../vsphere/common/output_config.hcl2spec.go | 35 - builder/vsphere/common/step_add_cdrom.go | 81 -- .../vsphere/common/step_add_cdrom.hcl2spec.go | 33 - builder/vsphere/common/step_add_cdrom_test.go | 235 ---- builder/vsphere/common/step_add_floppy.go | 111 -- .../common/step_add_floppy.hcl2spec.go | 37 - .../vsphere/common/step_add_floppy_test.go | 453 ------- builder/vsphere/common/step_boot_command.go | 152 --- builder/vsphere/common/step_config_params.go | 65 - .../common/step_config_params.hcl2spec.go | 35 - builder/vsphere/common/step_connect.go | 64 - .../vsphere/common/step_connect.hcl2spec.go | 39 - builder/vsphere/common/step_download.go | 68 - builder/vsphere/common/step_download_test.go | 85 -- builder/vsphere/common/step_export.go | 338 ----- .../vsphere/common/step_export.hcl2spec.go | 45 - builder/vsphere/common/step_hardware.go | 98 -- .../vsphere/common/step_hardware.hcl2spec.go | 57 - builder/vsphere/common/step_hardware_test.go | 181 --- .../vsphere/common/step_http_ip_discover.go | 68 - .../common/step_http_ip_discover_test.go | 83 -- .../common/step_import_to_content_library.go | 180 --- ...step_import_to_content_library.hcl2spec.go | 49 - builder/vsphere/common/step_remote_upload.go | 117 -- .../vsphere/common/step_remote_upload_test.go | 71 -- builder/vsphere/common/step_remove_cdrom.go | 46 - .../common/step_remove_cdrom.hcl2spec.go | 31 - .../vsphere/common/step_remove_cdrom_test.go | 111 -- builder/vsphere/common/step_remove_floppy.go | 49 - .../vsphere/common/step_remove_floppy_test.go | 213 ---- builder/vsphere/common/step_run.go | 80 -- builder/vsphere/common/step_run.hcl2spec.go | 31 - builder/vsphere/common/step_shutdown.go | 109 -- .../vsphere/common/step_shutdown.hcl2spec.go | 35 - builder/vsphere/common/step_snapshot.go | 32 - builder/vsphere/common/step_ssh_key_pair.go | 115 -- builder/vsphere/common/step_template.go | 31 - builder/vsphere/common/step_wait_for_ip.go | 182 --- .../common/step_wait_for_ip.hcl2spec.go | 35 - builder/vsphere/common/storage_config.go | 118 -- .../vsphere/common/storage_config.hcl2spec.go | 62 - builder/vsphere/common/testing/utility.go | 69 -- builder/vsphere/driver/cluster.go | 19 - builder/vsphere/driver/datastore.go | 235 ---- builder/vsphere/driver/datastore_acc_test.go | 96 -- builder/vsphere/driver/datastore_mock.go | 81 -- builder/vsphere/driver/datastore_test.go | 174 --- builder/vsphere/driver/disk.go | 85 -- builder/vsphere/driver/disk_test.go | 46 - builder/vsphere/driver/driver.go | 129 -- builder/vsphere/driver/driver_mock.go | 119 -- builder/vsphere/driver/driver_test.go | 171 --- builder/vsphere/driver/folder.go | 93 -- builder/vsphere/driver/folder_acc_test.go | 19 - builder/vsphere/driver/host.go | 45 - builder/vsphere/driver/host_acc_test.go | 22 - builder/vsphere/driver/library.go | 113 -- builder/vsphere/driver/library_test.go | 62 - builder/vsphere/driver/network.go | 77 -- builder/vsphere/driver/resource_pool.go | 91 -- .../vsphere/driver/resource_pool_acc_test.go | 20 - builder/vsphere/driver/resource_pool_test.go | 71 -- builder/vsphere/driver/vm.go | 1102 ----------------- builder/vsphere/driver/vm_cdrom.go | 89 -- builder/vsphere/driver/vm_cdrom_test.go | 167 --- builder/vsphere/driver/vm_clone_acc_test.go | 312 ----- builder/vsphere/driver/vm_create_acc_test.go | 92 -- builder/vsphere/driver/vm_keyboard.go | 39 - builder/vsphere/driver/vm_mock.go | 235 ---- builder/vsphere/driver/vm_test.go | 187 --- .../vsphere/examples/alpine/alpine-3.8.json | 64 - .../examples/alpine/alpine-3.8.pkr.hcl | 44 - builder/vsphere/examples/alpine/answerfile | 15 - builder/vsphere/examples/alpine/setup.sh | 19 - builder/vsphere/examples/clone/alpine.json | 18 - builder/vsphere/examples/clone/alpine.pkr.hcl | 25 - builder/vsphere/examples/driver/main.go | 26 - .../vsphere/examples/macos/macos-10.13.json | 49 - .../examples/macos/macos-10.13.pkr.hcl | 43 - .../vsphere/examples/macos/setup/.gitignore | 1 - .../vsphere/examples/macos/setup/iso-macos.sh | 15 - .../vsphere/examples/macos/setup/iso-setup.sh | 27 - .../vsphere/examples/macos/setup/postinstall | 25 - builder/vsphere/examples/macos/setup/setup.sh | 13 - builder/vsphere/examples/ubuntu/preseed.cfg | 16 - .../vsphere/examples/ubuntu/ubuntu-16.04.json | 63 - .../examples/ubuntu/ubuntu-16.04.pkr.hcl | 52 - .../vsphere/examples/windows/.gitattributes | 2 - .../examples/windows/setup/Autounattend.xml | 122 -- .../vsphere/examples/windows/setup/setup.ps1 | 15 - .../examples/windows/setup/vmtools.cmd | 2 - .../vsphere/examples/windows/windows-10.json | 48 - .../examples/windows/windows-10.pkr.hcl | 41 - builder/vsphere/iso/builder.go | 179 --- builder/vsphere/iso/builder_acc_test.go | 568 --------- builder/vsphere/iso/common_test.go | 17 - builder/vsphere/iso/config.go | 107 -- builder/vsphere/iso/config.hcl2spec.go | 286 ----- builder/vsphere/iso/step_create.go | 188 --- builder/vsphere/iso/step_create.hcl2spec.go | 73 -- builder/vsphere/iso/step_create_test.go | 417 ------- builder/vsphere/test/lab.ovpn | 38 - builder/vsphere/test/lab.p12 | Bin 4141 -> 0 bytes builder/vsphere/test/test-key.pem | 27 - builder/vsphere/test/test-key.pub | 1 - builder/vsphere/version/version.go | 13 - command/plugin.go | 8 - .../vsphere-template/post-processor.go | 153 --- .../post-processor.hcl2spec.go | 65 - .../vsphere-template/post-processor_test.go | 39 - .../step_choose_datacenter.go | 35 - .../vsphere-template/step_create_folder.go | 86 -- .../vsphere-template/step_create_snapshot.go | 76 -- .../vsphere-template/step_mark_as_template.go | 186 --- .../vsphere-template/version/version.go | 13 - post-processor/vsphere/artifact.go | 47 - post-processor/vsphere/artifact_test.go | 22 - post-processor/vsphere/post-processor.go | 280 ----- .../vsphere/post-processor.hcl2spec.go | 75 -- post-processor/vsphere/post-processor_test.go | 130 -- post-processor/vsphere/version/version.go | 13 - .../content/docs/builders/vmware/index.mdx | 11 - .../docs/builders/vmware/vsphere-clone.mdx | 416 ------- .../docs/builders/vmware/vsphere-iso.mdx | 410 ------ .../docs/post-processors/vsphere-template.mdx | 168 --- .../content/docs/post-processors/vsphere.mdx | 180 --- .../clone/CloneConfig-not-required.mdx | 20 - .../vsphere/clone/Config-not-required.mdx | 15 - .../clone/CustomizeConfig-not-required.mdx | 9 - .../builder/vsphere/clone/CustomizeConfig.mdx | 12 - .../clone/GlobalDnsSettings-not-required.mdx | 5 - .../vsphere/clone/GlobalDnsSettings.mdx | 4 - .../GlobalRoutingSettings-not-required.mdx | 5 - .../vsphere/clone/GlobalRoutingSettings.mdx | 3 - .../clone/LinuxOptions-not-required.mdx | 9 - .../clone/NetworkInterface-not-required.mdx | 15 - .../vsphere/clone/vAppConfig-not-required.mdx | 9 - .../common/BootConfig-not-required.mdx | 4 - .../common/CDRomConfig-not-required.mdx | 12 - .../ConfigParamsConfig-not-required.mdx | 9 - .../common/ConnectConfig-not-required.mdx | 11 - ...tLibraryDestinationConfig-not-required.mdx | 46 - .../ContentLibraryDestinationConfig.mdx | 5 - .../common/DiskConfig-not-required.mdx | 7 - .../vsphere/common/DiskConfig-required.mdx | 3 - .../builder/vsphere/common/DiskConfig.mdx | 74 -- .../common/ExportConfig-not-required.mdx | 32 - .../builder/vsphere/common/ExportConfig.mdx | 33 - .../common/FloppyConfig-not-required.mdx | 14 - .../common/HardwareConfig-not-required.mdx | 31 - .../common/LocationConfig-not-required.mdx | 24 - .../common/OutputConfig-not-required.mdx | 16 - .../common/RemoveCDRomConfig-not-required.mdx | 3 - .../vsphere/common/RunConfig-not-required.mdx | 3 - .../common/ShutdownConfig-not-required.mdx | 16 - .../common/StorageConfig-not-required.mdx | 8 - .../common/WaitIpConfig-not-required.mdx | 20 - .../vsphere/iso/Config-not-required.mdx | 13 - .../vsphere/iso/CreateConfig-not-required.mdx | 16 - .../builder/vsphere/iso/NIC-not-required.mdx | 10 - .../builder/vsphere/iso/NIC-required.mdx | 3 - .../partials/builder/vsphere/iso/NIC.mdx | 30 - website/data/docs-nav-data.json | 16 - 182 files changed, 16361 deletions(-) delete mode 100644 builder/vsphere/clone/builder.go delete mode 100644 builder/vsphere/clone/builder_acc_test.go delete mode 100644 builder/vsphere/clone/builder_test.go delete mode 100644 builder/vsphere/clone/config.go delete mode 100644 builder/vsphere/clone/config.hcl2spec.go delete mode 100644 builder/vsphere/clone/config_test.go delete mode 100644 builder/vsphere/clone/step_clone.go delete mode 100644 builder/vsphere/clone/step_clone.hcl2spec.go delete mode 100644 builder/vsphere/clone/step_clone_test.go delete mode 100644 builder/vsphere/clone/step_customize.go delete mode 100644 builder/vsphere/clone/step_customize.hcl2spec.go delete mode 100644 builder/vsphere/common/artifact.go delete mode 100644 builder/vsphere/common/cleanup_vm.go delete mode 100644 builder/vsphere/common/cleanup_vm_test.go delete mode 100644 builder/vsphere/common/common_test.go delete mode 100644 builder/vsphere/common/config_location.go delete mode 100644 builder/vsphere/common/config_location.hcl2spec.go delete mode 100644 builder/vsphere/common/config_ssh.go delete mode 100644 builder/vsphere/common/output_config.go delete mode 100644 builder/vsphere/common/output_config.hcl2spec.go delete mode 100644 builder/vsphere/common/step_add_cdrom.go delete mode 100644 builder/vsphere/common/step_add_cdrom.hcl2spec.go delete mode 100644 builder/vsphere/common/step_add_cdrom_test.go delete mode 100644 builder/vsphere/common/step_add_floppy.go delete mode 100644 builder/vsphere/common/step_add_floppy.hcl2spec.go delete mode 100644 builder/vsphere/common/step_add_floppy_test.go delete mode 100644 builder/vsphere/common/step_boot_command.go delete mode 100644 builder/vsphere/common/step_config_params.go delete mode 100644 builder/vsphere/common/step_config_params.hcl2spec.go delete mode 100644 builder/vsphere/common/step_connect.go delete mode 100644 builder/vsphere/common/step_connect.hcl2spec.go delete mode 100644 builder/vsphere/common/step_download.go delete mode 100644 builder/vsphere/common/step_download_test.go delete mode 100644 builder/vsphere/common/step_export.go delete mode 100644 builder/vsphere/common/step_export.hcl2spec.go delete mode 100644 builder/vsphere/common/step_hardware.go delete mode 100644 builder/vsphere/common/step_hardware.hcl2spec.go delete mode 100644 builder/vsphere/common/step_hardware_test.go delete mode 100644 builder/vsphere/common/step_http_ip_discover.go delete mode 100644 builder/vsphere/common/step_http_ip_discover_test.go delete mode 100644 builder/vsphere/common/step_import_to_content_library.go delete mode 100644 builder/vsphere/common/step_import_to_content_library.hcl2spec.go delete mode 100644 builder/vsphere/common/step_remote_upload.go delete mode 100644 builder/vsphere/common/step_remote_upload_test.go delete mode 100644 builder/vsphere/common/step_remove_cdrom.go delete mode 100644 builder/vsphere/common/step_remove_cdrom.hcl2spec.go delete mode 100644 builder/vsphere/common/step_remove_cdrom_test.go delete mode 100644 builder/vsphere/common/step_remove_floppy.go delete mode 100644 builder/vsphere/common/step_remove_floppy_test.go delete mode 100644 builder/vsphere/common/step_run.go delete mode 100644 builder/vsphere/common/step_run.hcl2spec.go delete mode 100644 builder/vsphere/common/step_shutdown.go delete mode 100644 builder/vsphere/common/step_shutdown.hcl2spec.go delete mode 100644 builder/vsphere/common/step_snapshot.go delete mode 100644 builder/vsphere/common/step_ssh_key_pair.go delete mode 100644 builder/vsphere/common/step_template.go delete mode 100644 builder/vsphere/common/step_wait_for_ip.go delete mode 100644 builder/vsphere/common/step_wait_for_ip.hcl2spec.go delete mode 100644 builder/vsphere/common/storage_config.go delete mode 100644 builder/vsphere/common/storage_config.hcl2spec.go delete mode 100644 builder/vsphere/common/testing/utility.go delete mode 100644 builder/vsphere/driver/cluster.go delete mode 100644 builder/vsphere/driver/datastore.go delete mode 100644 builder/vsphere/driver/datastore_acc_test.go delete mode 100644 builder/vsphere/driver/datastore_mock.go delete mode 100644 builder/vsphere/driver/datastore_test.go delete mode 100644 builder/vsphere/driver/disk.go delete mode 100644 builder/vsphere/driver/disk_test.go delete mode 100644 builder/vsphere/driver/driver.go delete mode 100644 builder/vsphere/driver/driver_mock.go delete mode 100644 builder/vsphere/driver/driver_test.go delete mode 100644 builder/vsphere/driver/folder.go delete mode 100644 builder/vsphere/driver/folder_acc_test.go delete mode 100644 builder/vsphere/driver/host.go delete mode 100644 builder/vsphere/driver/host_acc_test.go delete mode 100644 builder/vsphere/driver/library.go delete mode 100644 builder/vsphere/driver/library_test.go delete mode 100644 builder/vsphere/driver/network.go delete mode 100644 builder/vsphere/driver/resource_pool.go delete mode 100644 builder/vsphere/driver/resource_pool_acc_test.go delete mode 100644 builder/vsphere/driver/resource_pool_test.go delete mode 100644 builder/vsphere/driver/vm.go delete mode 100644 builder/vsphere/driver/vm_cdrom.go delete mode 100644 builder/vsphere/driver/vm_cdrom_test.go delete mode 100644 builder/vsphere/driver/vm_clone_acc_test.go delete mode 100644 builder/vsphere/driver/vm_create_acc_test.go delete mode 100644 builder/vsphere/driver/vm_keyboard.go delete mode 100644 builder/vsphere/driver/vm_mock.go delete mode 100644 builder/vsphere/driver/vm_test.go delete mode 100644 builder/vsphere/examples/alpine/alpine-3.8.json delete mode 100644 builder/vsphere/examples/alpine/alpine-3.8.pkr.hcl delete mode 100644 builder/vsphere/examples/alpine/answerfile delete mode 100644 builder/vsphere/examples/alpine/setup.sh delete mode 100644 builder/vsphere/examples/clone/alpine.json delete mode 100644 builder/vsphere/examples/clone/alpine.pkr.hcl delete mode 100644 builder/vsphere/examples/driver/main.go delete mode 100644 builder/vsphere/examples/macos/macos-10.13.json delete mode 100644 builder/vsphere/examples/macos/macos-10.13.pkr.hcl delete mode 100644 builder/vsphere/examples/macos/setup/.gitignore delete mode 100644 builder/vsphere/examples/macos/setup/iso-macos.sh delete mode 100644 builder/vsphere/examples/macos/setup/iso-setup.sh delete mode 100644 builder/vsphere/examples/macos/setup/postinstall delete mode 100644 builder/vsphere/examples/macos/setup/setup.sh delete mode 100644 builder/vsphere/examples/ubuntu/preseed.cfg delete mode 100644 builder/vsphere/examples/ubuntu/ubuntu-16.04.json delete mode 100644 builder/vsphere/examples/ubuntu/ubuntu-16.04.pkr.hcl delete mode 100644 builder/vsphere/examples/windows/.gitattributes delete mode 100644 builder/vsphere/examples/windows/setup/Autounattend.xml delete mode 100644 builder/vsphere/examples/windows/setup/setup.ps1 delete mode 100644 builder/vsphere/examples/windows/setup/vmtools.cmd delete mode 100644 builder/vsphere/examples/windows/windows-10.json delete mode 100644 builder/vsphere/examples/windows/windows-10.pkr.hcl delete mode 100644 builder/vsphere/iso/builder.go delete mode 100644 builder/vsphere/iso/builder_acc_test.go delete mode 100644 builder/vsphere/iso/common_test.go delete mode 100644 builder/vsphere/iso/config.go delete mode 100644 builder/vsphere/iso/config.hcl2spec.go delete mode 100644 builder/vsphere/iso/step_create.go delete mode 100644 builder/vsphere/iso/step_create.hcl2spec.go delete mode 100644 builder/vsphere/iso/step_create_test.go delete mode 100644 builder/vsphere/test/lab.ovpn delete mode 100644 builder/vsphere/test/lab.p12 delete mode 100644 builder/vsphere/test/test-key.pem delete mode 100644 builder/vsphere/test/test-key.pub delete mode 100644 builder/vsphere/version/version.go delete mode 100644 post-processor/vsphere-template/post-processor.go delete mode 100644 post-processor/vsphere-template/post-processor.hcl2spec.go delete mode 100644 post-processor/vsphere-template/post-processor_test.go delete mode 100644 post-processor/vsphere-template/step_choose_datacenter.go delete mode 100644 post-processor/vsphere-template/step_create_folder.go delete mode 100644 post-processor/vsphere-template/step_create_snapshot.go delete mode 100644 post-processor/vsphere-template/step_mark_as_template.go delete mode 100644 post-processor/vsphere-template/version/version.go delete mode 100644 post-processor/vsphere/artifact.go delete mode 100644 post-processor/vsphere/artifact_test.go delete mode 100644 post-processor/vsphere/post-processor.go delete mode 100644 post-processor/vsphere/post-processor.hcl2spec.go delete mode 100644 post-processor/vsphere/post-processor_test.go delete mode 100644 post-processor/vsphere/version/version.go delete mode 100644 website/content/docs/builders/vmware/vsphere-clone.mdx delete mode 100644 website/content/docs/builders/vmware/vsphere-iso.mdx delete mode 100644 website/content/docs/post-processors/vsphere-template.mdx delete mode 100644 website/content/docs/post-processors/vsphere.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/CloneConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/Config-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/CustomizeConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/CustomizeConfig.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/GlobalDnsSettings-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/GlobalDnsSettings.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/GlobalRoutingSettings-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/GlobalRoutingSettings.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/LinuxOptions-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/NetworkInterface-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/clone/vAppConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/BootConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/CDRomConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/ConfigParamsConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/ConnectConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig.mdx delete mode 100644 website/content/partials/builder/vsphere/common/DiskConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/DiskConfig-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/DiskConfig.mdx delete mode 100644 website/content/partials/builder/vsphere/common/ExportConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/ExportConfig.mdx delete mode 100644 website/content/partials/builder/vsphere/common/FloppyConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/HardwareConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/LocationConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/OutputConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/RemoveCDRomConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/RunConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/ShutdownConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/StorageConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/common/WaitIpConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/iso/Config-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/iso/CreateConfig-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/iso/NIC-not-required.mdx delete mode 100644 website/content/partials/builder/vsphere/iso/NIC-required.mdx delete mode 100644 website/content/partials/builder/vsphere/iso/NIC.mdx diff --git a/builder/vsphere/clone/builder.go b/builder/vsphere/clone/builder.go deleted file mode 100644 index d9c34bab9..000000000 --- a/builder/vsphere/clone/builder.go +++ /dev/null @@ -1,175 +0,0 @@ -package clone - -import ( - "context" - "fmt" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "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" -) - -type Builder struct { - config Config - runner multistep.Runner -} - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - warnings, errs := b.config.Prepare(raws...) - if errs != nil { - return nil, warnings, errs - } - - return nil, warnings, nil -} - -func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) { - state := new(multistep.BasicStateBag) - state.Put("debug", b.config.PackerDebug) - state.Put("hook", hook) - state.Put("ui", ui) - - var steps []multistep.Step - - steps = append(steps, - &common.StepConnect{ - Config: &b.config.ConnectConfig, - }, - &commonsteps.StepCreateCD{ - Files: b.config.CDConfig.CDFiles, - Label: b.config.CDConfig.CDLabel, - }, - &common.StepRemoteUpload{ - Datastore: b.config.Datastore, - Host: b.config.Host, - SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads, - }, - &StepCloneVM{ - Config: &b.config.CloneConfig, - Location: &b.config.LocationConfig, - Force: b.config.PackerConfig.PackerForce, - }, - &common.StepConfigureHardware{ - Config: &b.config.HardwareConfig, - }, - &common.StepAddCDRom{ - Config: &b.config.CDRomConfig, - }, - &common.StepConfigParams{ - Config: &b.config.ConfigParamsConfig, - }, - ) - - if b.config.CustomizeConfig != nil { - steps = append(steps, &StepCustomize{ - Config: b.config.CustomizeConfig, - }) - } - - if b.config.Comm.Type != "none" { - steps = append(steps, - &commonsteps.StepCreateFloppy{ - Files: b.config.FloppyFiles, - Directories: b.config.FloppyDirectories, - Label: b.config.FloppyLabel, - }, - &common.StepAddFloppy{ - Config: &b.config.FloppyConfig, - Datastore: b.config.Datastore, - Host: b.config.Host, - SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads, - }, - &common.StepHTTPIPDiscover{ - HTTPIP: b.config.BootConfig.HTTPIP, - Network: b.config.WaitIpConfig.GetIPNet(), - }, - commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), - &common.StepSshKeyPair{ - Debug: b.config.PackerDebug, - DebugKeyPath: fmt.Sprintf("%s.pem", b.config.PackerBuildName), - Comm: &b.config.Comm, - }, - &common.StepRun{ - Config: &b.config.RunConfig, - SetOrder: false, - }, - &common.StepBootCommand{ - Config: &b.config.BootConfig, - Ctx: b.config.ctx, - VMName: b.config.VMName, - }, - &common.StepWaitForIp{ - Config: &b.config.WaitIpConfig, - }, - &communicator.StepConnect{ - Config: &b.config.Comm, - Host: common.CommHost(b.config.Comm.Host()), - SSHConfig: b.config.Comm.SSHConfigFunc(), - }, - &commonsteps.StepProvision{}, - &common.StepShutdown{ - Config: &b.config.ShutdownConfig, - }, - &common.StepRemoveFloppy{ - Datastore: b.config.Datastore, - Host: b.config.Host, - }, - ) - } - - steps = append(steps, - &common.StepRemoveCDRom{ - Config: &b.config.RemoveCDRomConfig, - }, - &common.StepCreateSnapshot{ - CreateSnapshot: b.config.CreateSnapshot, - }, - &common.StepConvertToTemplate{ - ConvertToTemplate: b.config.ConvertToTemplate, - }, - ) - - if b.config.ContentLibraryDestinationConfig != nil { - steps = append(steps, &common.StepImportToContentLibrary{ - ContentLibConfig: b.config.ContentLibraryDestinationConfig, - }) - } - - if b.config.Export != nil { - steps = append(steps, &common.StepExport{ - Name: b.config.Export.Name, - Force: b.config.Export.Force, - Images: b.config.Export.Images, - Manifest: b.config.Export.Manifest, - OutputDir: b.config.Export.OutputDir.OutputDir, - Options: b.config.Export.Options, - }) - } - - b.runner = commonsteps.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) - b.runner.Run(ctx, state) - - if rawErr, ok := state.GetOk("error"); ok { - return nil, rawErr.(error) - } - - if _, ok := state.GetOk("vm"); !ok { - return nil, nil - } - artifact := &common.Artifact{ - Name: b.config.VMName, - VM: state.Get("vm").(*driver.VirtualMachineDriver), - StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, - } - if b.config.Export != nil { - artifact.Outconfig = &b.config.Export.OutputDir - } - - return artifact, nil -} diff --git a/builder/vsphere/clone/builder_acc_test.go b/builder/vsphere/clone/builder_acc_test.go deleted file mode 100644 index f39610644..000000000 --- a/builder/vsphere/clone/builder_acc_test.go +++ /dev/null @@ -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 -} diff --git a/builder/vsphere/clone/builder_test.go b/builder/vsphere/clone/builder_test.go deleted file mode 100644 index a3150f52b..000000000 --- a/builder/vsphere/clone/builder_test.go +++ /dev/null @@ -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") - } -} diff --git a/builder/vsphere/clone/config.go b/builder/vsphere/clone/config.go deleted file mode 100644 index 8d2160577..000000000 --- a/builder/vsphere/clone/config.go +++ /dev/null @@ -1,104 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type Config - -package clone - -import ( - packerCommon "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - 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" -) - -type Config struct { - packerCommon.PackerConfig `mapstructure:",squash"` - commonsteps.HTTPConfig `mapstructure:",squash"` - commonsteps.CDConfig `mapstructure:",squash"` - - common.ConnectConfig `mapstructure:",squash"` - CloneConfig `mapstructure:",squash"` - common.LocationConfig `mapstructure:",squash"` - common.HardwareConfig `mapstructure:",squash"` - common.ConfigParamsConfig `mapstructure:",squash"` - - common.CDRomConfig `mapstructure:",squash"` - common.RemoveCDRomConfig `mapstructure:",squash"` - common.FloppyConfig `mapstructure:",squash"` - common.RunConfig `mapstructure:",squash"` - common.BootConfig `mapstructure:",squash"` - common.WaitIpConfig `mapstructure:",squash"` - Comm communicator.Config `mapstructure:",squash"` - common.ShutdownConfig `mapstructure:",squash"` - - // Create a snapshot when set to `true`, so the VM can be used as a base - // for linked clones. Defaults to `false`. - CreateSnapshot bool `mapstructure:"create_snapshot"` - // Convert VM to a template. Defaults to `false`. - ConvertToTemplate bool `mapstructure:"convert_to_template"` - // Configuration for exporting VM to an ovf file. - // The VM will not be exported if no [Export Configuration](#export-configuration) is specified. - Export *common.ExportConfig `mapstructure:"export"` - // Configuration for importing a VM template or OVF template to a Content Library. - // The template will not be imported if no [Content Library Import Configuration](#content-library-import-configuration) is specified. - // The import doesn't work if [convert_to_template](#convert_to_template) is set to true. - ContentLibraryDestinationConfig *common.ContentLibraryDestinationConfig `mapstructure:"content_library_destination"` - // Customize the cloned VM to configure host, network, or licensing settings. See the [customization options](#customization). - CustomizeConfig *CustomizeConfig `mapstructure:"customize"` - - ctx interpolate.Context -} - -func (c *Config) Prepare(raws ...interface{}) ([]string, error) { - err := config.Decode(c, &config.DecodeOpts{ - PluginType: common.BuilderId, - Interpolate: true, - InterpolateContext: &c.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{ - "boot_command", - }, - }, - }, raws...) - if err != nil { - return nil, err - } - - // warnings := make([]string, 0) - errs := new(packersdk.MultiError) - - errs = packersdk.MultiErrorAppend(errs, c.ConnectConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.CloneConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.LocationConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...) - - errs = packersdk.MultiErrorAppend(errs, c.CDRomConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.CDConfig.Prepare(&c.ctx)...) - errs = packersdk.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.ctx)...) - errs = packersdk.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) - - _, shutdownErrs := c.ShutdownConfig.Prepare(c.Comm) - // shutdownWarnings, shutdownErrs := c.ShutdownConfig.Prepare(c.Comm) - // warnings = append(warnings, shutdownWarnings...) - errs = packersdk.MultiErrorAppend(errs, shutdownErrs...) - - if c.Export != nil { - errs = packersdk.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...) - } - if c.ContentLibraryDestinationConfig != nil { - errs = packersdk.MultiErrorAppend(errs, c.ContentLibraryDestinationConfig.Prepare(&c.LocationConfig)...) - } - if c.CustomizeConfig != nil { - errs = packersdk.MultiErrorAppend(errs, c.CustomizeConfig.Prepare()...) - } - - if len(errs.Errors) > 0 { - return nil, errs - } - - return nil, nil -} diff --git a/builder/vsphere/clone/config.hcl2spec.go b/builder/vsphere/clone/config.hcl2spec.go deleted file mode 100644 index ad7787e7e..000000000 --- a/builder/vsphere/clone/config.hcl2spec.go +++ /dev/null @@ -1,282 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT. - -package clone - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/vsphere/common" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"` - CDFiles []string `mapstructure:"cd_files" cty:"cd_files" hcl:"cd_files"` - CDLabel *string `mapstructure:"cd_label" cty:"cd_label" hcl:"cd_label"` - VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection" hcl:"insecure_connection"` - Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"` - Template *string `mapstructure:"template" cty:"template" hcl:"template"` - DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"` - LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone" hcl:"linked_clone"` - Network *string `mapstructure:"network" cty:"network" hcl:"network"` - MacAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"` - Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"` - VAppConfig *FlatvAppConfig `mapstructure:"vapp" cty:"vapp" hcl:"vapp"` - DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"` - Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"` - Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"` - Host *string `mapstructure:"host" cty:"host" hcl:"host"` - ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"` - Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"` - SetHostForDatastoreUploads *bool `mapstructure:"set_host_for_datastore_uploads" cty:"set_host_for_datastore_uploads" hcl:"set_host_for_datastore_uploads"` - CPUs *int32 `mapstructure:"CPUs" cty:"CPUs" hcl:"CPUs"` - CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores" hcl:"cpu_cores"` - CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation" hcl:"CPU_reservation"` - CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit" hcl:"CPU_limit"` - CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug" hcl:"CPU_hot_plug"` - RAM *int64 `mapstructure:"RAM" cty:"RAM" hcl:"RAM"` - RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation" hcl:"RAM_reservation"` - RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all" hcl:"RAM_reserve_all"` - MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug" hcl:"RAM_hot_plug"` - VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram" hcl:"video_ram"` - VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile" hcl:"vgpu_profile"` - NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV" hcl:"NestedHV"` - Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"` - ForceBIOSSetup *bool `mapstructure:"force_bios_setup" cty:"force_bios_setup" hcl:"force_bios_setup"` - ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"` - ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"` - ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"` - CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type" hcl:"cdrom_type"` - ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths" hcl:"iso_paths"` - RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom" hcl:"remove_cdrom"` - FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path" hcl:"floppy_img_path"` - FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"` - FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"` - FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"` - BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"` - BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"` - BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"` - BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"` - HTTPIP *string `mapstructure:"http_ip" cty:"http_ip" hcl:"http_ip"` - WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"` - SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"` - WaitAddress *string `mapstructure:"ip_wait_address" cty:"ip_wait_address" hcl:"ip_wait_address"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` - SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - Command *string `mapstructure:"shutdown_command" cty:"shutdown_command" hcl:"shutdown_command"` - Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout" hcl:"shutdown_timeout"` - DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown" hcl:"disable_shutdown"` - CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot" hcl:"create_snapshot"` - ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template" hcl:"convert_to_template"` - Export *common.FlatExportConfig `mapstructure:"export" cty:"export" hcl:"export"` - ContentLibraryDestinationConfig *common.FlatContentLibraryDestinationConfig `mapstructure:"content_library_destination" cty:"content_library_destination" hcl:"content_library_destination"` - CustomizeConfig *FlatCustomizeConfig `mapstructure:"customize" cty:"customize" hcl:"customize"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, - "http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false}, - "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, - "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, - "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, - "http_interface": &hcldec.AttrSpec{Name: "http_interface", Type: cty.String, Required: false}, - "cd_files": &hcldec.AttrSpec{Name: "cd_files", Type: cty.List(cty.String), Required: false}, - "cd_label": &hcldec.AttrSpec{Name: "cd_label", Type: cty.String, Required: false}, - "vcenter_server": &hcldec.AttrSpec{Name: "vcenter_server", Type: cty.String, Required: false}, - "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "insecure_connection": &hcldec.AttrSpec{Name: "insecure_connection", Type: cty.Bool, Required: false}, - "datacenter": &hcldec.AttrSpec{Name: "datacenter", Type: cty.String, Required: false}, - "template": &hcldec.AttrSpec{Name: "template", Type: cty.String, Required: false}, - "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false}, - "linked_clone": &hcldec.AttrSpec{Name: "linked_clone", Type: cty.Bool, Required: false}, - "network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false}, - "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, - "notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false}, - "vapp": &hcldec.BlockSpec{TypeName: "vapp", Nested: hcldec.ObjectSpec((*FlatvAppConfig)(nil).HCL2Spec())}, - "disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false}, - "storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "folder": &hcldec.AttrSpec{Name: "folder", Type: cty.String, Required: false}, - "cluster": &hcldec.AttrSpec{Name: "cluster", Type: cty.String, Required: false}, - "host": &hcldec.AttrSpec{Name: "host", Type: cty.String, Required: false}, - "resource_pool": &hcldec.AttrSpec{Name: "resource_pool", Type: cty.String, Required: false}, - "datastore": &hcldec.AttrSpec{Name: "datastore", Type: cty.String, Required: false}, - "set_host_for_datastore_uploads": &hcldec.AttrSpec{Name: "set_host_for_datastore_uploads", Type: cty.Bool, Required: false}, - "CPUs": &hcldec.AttrSpec{Name: "CPUs", Type: cty.Number, Required: false}, - "cpu_cores": &hcldec.AttrSpec{Name: "cpu_cores", Type: cty.Number, Required: false}, - "CPU_reservation": &hcldec.AttrSpec{Name: "CPU_reservation", Type: cty.Number, Required: false}, - "CPU_limit": &hcldec.AttrSpec{Name: "CPU_limit", Type: cty.Number, Required: false}, - "CPU_hot_plug": &hcldec.AttrSpec{Name: "CPU_hot_plug", Type: cty.Bool, Required: false}, - "RAM": &hcldec.AttrSpec{Name: "RAM", Type: cty.Number, Required: false}, - "RAM_reservation": &hcldec.AttrSpec{Name: "RAM_reservation", Type: cty.Number, Required: false}, - "RAM_reserve_all": &hcldec.AttrSpec{Name: "RAM_reserve_all", Type: cty.Bool, Required: false}, - "RAM_hot_plug": &hcldec.AttrSpec{Name: "RAM_hot_plug", Type: cty.Bool, Required: false}, - "video_ram": &hcldec.AttrSpec{Name: "video_ram", Type: cty.Number, Required: false}, - "vgpu_profile": &hcldec.AttrSpec{Name: "vgpu_profile", Type: cty.String, Required: false}, - "NestedHV": &hcldec.AttrSpec{Name: "NestedHV", Type: cty.Bool, Required: false}, - "firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false}, - "force_bios_setup": &hcldec.AttrSpec{Name: "force_bios_setup", Type: cty.Bool, Required: false}, - "configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false}, - "tools_sync_time": &hcldec.AttrSpec{Name: "tools_sync_time", Type: cty.Bool, Required: false}, - "tools_upgrade_policy": &hcldec.AttrSpec{Name: "tools_upgrade_policy", Type: cty.Bool, Required: false}, - "cdrom_type": &hcldec.AttrSpec{Name: "cdrom_type", Type: cty.String, Required: false}, - "iso_paths": &hcldec.AttrSpec{Name: "iso_paths", Type: cty.List(cty.String), Required: false}, - "remove_cdrom": &hcldec.AttrSpec{Name: "remove_cdrom", Type: cty.Bool, Required: false}, - "floppy_img_path": &hcldec.AttrSpec{Name: "floppy_img_path", Type: cty.String, Required: false}, - "floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false}, - "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, - "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, - "boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.String, Required: false}, - "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, - "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, - "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "http_ip": &hcldec.AttrSpec{Name: "http_ip", Type: cty.String, Required: false}, - "ip_wait_timeout": &hcldec.AttrSpec{Name: "ip_wait_timeout", Type: cty.String, Required: false}, - "ip_settle_timeout": &hcldec.AttrSpec{Name: "ip_settle_timeout", Type: cty.String, Required: false}, - "ip_wait_address": &hcldec.AttrSpec{Name: "ip_wait_address", Type: cty.String, Required: false}, - "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, - "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, - "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, - "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, - "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, - "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, - "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, - "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, - "temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false}, - "temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false}, - "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, - "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, - "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, - "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, - "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, - "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, - "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, - "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, - "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, - "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, - "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, - "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, - "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, - "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, - "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, - "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, - "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, - "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, - "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, - "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, - "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, - "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, - "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, - "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, - "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, - "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, - "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, - "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, - "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, - "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, - "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, - "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, - "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, - "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, - "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, - "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, - "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, - "shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false}, - "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false}, - "disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false}, - "create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false}, - "convert_to_template": &hcldec.AttrSpec{Name: "convert_to_template", Type: cty.Bool, Required: false}, - "export": &hcldec.BlockSpec{TypeName: "export", Nested: hcldec.ObjectSpec((*common.FlatExportConfig)(nil).HCL2Spec())}, - "content_library_destination": &hcldec.BlockSpec{TypeName: "content_library_destination", Nested: hcldec.ObjectSpec((*common.FlatContentLibraryDestinationConfig)(nil).HCL2Spec())}, - "customize": &hcldec.BlockSpec{TypeName: "customize", Nested: hcldec.ObjectSpec((*FlatCustomizeConfig)(nil).HCL2Spec())}, - } - return s -} diff --git a/builder/vsphere/clone/config_test.go b/builder/vsphere/clone/config_test.go deleted file mode 100644 index a1da7013d..000000000 --- a/builder/vsphere/clone/config_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/clone/step_clone.go b/builder/vsphere/clone/step_clone.go deleted file mode 100644 index c0def3269..000000000 --- a/builder/vsphere/clone/step_clone.go +++ /dev/null @@ -1,136 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type CloneConfig,vAppConfig - -package clone - -import ( - "context" - "fmt" - "path" - - "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" -) - -type vAppConfig struct { - // Set values for the available vApp Properties to supply configuration parameters to a virtual machine cloned from - // a template that came from an imported OVF or OVA file. - // - // -> **Note:** The only supported usage path for vApp properties is for existing user-configurable keys. - // These generally come from an existing template that was created from an imported OVF or OVA file. - // You cannot set values for vApp properties on virtual machines created from scratch, - // virtual machines lacking a vApp configuration, or on property keys that do not exist. - Properties map[string]string `mapstructure:"properties"` -} - -type CloneConfig struct { - // Name of source VM. Path is optional. - Template string `mapstructure:"template"` - // The size of the disk in MB. - DiskSize int64 `mapstructure:"disk_size"` - // Create VM as a linked clone from latest snapshot. Defaults to `false`. - LinkedClone bool `mapstructure:"linked_clone"` - // Set the network in which the VM will be connected to. If no network is - // specified, `host` must be specified to allow Packer to look for the - // available network. If the network is inside a network folder in vCenter, - // you need to provide the full path to the network. - Network string `mapstructure:"network"` - // Sets a custom Mac Address to the network adapter. If set, the [network](#network) must be also specified. - MacAddress string `mapstructure:"mac_address"` - // VM notes. - Notes string `mapstructure:"notes"` - // Set the vApp Options to a virtual machine. - // See the [vApp Options Configuration](/docs/builders/vmware/vsphere-clone#vapp-options-configuration) - // to know the available options and how to use it. - VAppConfig vAppConfig `mapstructure:"vapp"` - StorageConfig common.StorageConfig `mapstructure:",squash"` -} - -func (c *CloneConfig) Prepare() []error { - var errs []error - errs = append(errs, c.StorageConfig.Prepare()...) - - if c.Template == "" { - errs = append(errs, fmt.Errorf("'template' is required")) - } - - if c.LinkedClone == true && c.DiskSize != 0 { - errs = append(errs, fmt.Errorf("'linked_clone' and 'disk_size' cannot be used together")) - } - - if c.MacAddress != "" && c.Network == "" { - errs = append(errs, fmt.Errorf("'network' is required when 'mac_address' is specified")) - } - - return errs -} - -type StepCloneVM struct { - Config *CloneConfig - Location *common.LocationConfig - Force bool -} - -func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - d := state.Get("driver").(driver.Driver) - vmPath := path.Join(s.Location.Folder, s.Location.VMName) - - err := d.PreCleanVM(ui, vmPath, s.Force) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - ui.Say("Cloning VM...") - template, err := d.FindVM(s.Config.Template) - if err != nil { - state.Put("error", fmt.Errorf("Error finding vm to clone: %s", err)) - return multistep.ActionHalt - } - - var disks []driver.Disk - for _, disk := range s.Config.StorageConfig.Storage { - disks = append(disks, driver.Disk{ - DiskSize: disk.DiskSize, - DiskEagerlyScrub: disk.DiskEagerlyScrub, - DiskThinProvisioned: disk.DiskThinProvisioned, - ControllerIndex: disk.DiskControllerIndex, - }) - } - - vm, err := template.Clone(ctx, &driver.CloneConfig{ - Name: s.Location.VMName, - Folder: s.Location.Folder, - Cluster: s.Location.Cluster, - Host: s.Location.Host, - ResourcePool: s.Location.ResourcePool, - Datastore: s.Location.Datastore, - LinkedClone: s.Config.LinkedClone, - Network: s.Config.Network, - MacAddress: s.Config.MacAddress, - Annotation: s.Config.Notes, - VAppProperties: s.Config.VAppConfig.Properties, - PrimaryDiskSize: s.Config.DiskSize, - StorageConfig: driver.StorageConfig{ - DiskControllerType: s.Config.StorageConfig.DiskControllerType, - Storage: disks, - }, - }) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - if vm == nil { - return multistep.ActionHalt - } - state.Put("vm", vm) - - return multistep.ActionContinue -} - -func (s *StepCloneVM) Cleanup(state multistep.StateBag) { - common.CleanupVM(state) -} diff --git a/builder/vsphere/clone/step_clone.hcl2spec.go b/builder/vsphere/clone/step_clone.hcl2spec.go deleted file mode 100644 index 41897a0fb..000000000 --- a/builder/vsphere/clone/step_clone.hcl2spec.go +++ /dev/null @@ -1,71 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type CloneConfig,vAppConfig"; DO NOT EDIT. - -package clone - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/vsphere/common" - "github.com/zclconf/go-cty/cty" -) - -// FlatCloneConfig is an auto-generated flat version of CloneConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatCloneConfig struct { - Template *string `mapstructure:"template" cty:"template" hcl:"template"` - DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"` - LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone" hcl:"linked_clone"` - Network *string `mapstructure:"network" cty:"network" hcl:"network"` - MacAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"` - Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"` - VAppConfig *FlatvAppConfig `mapstructure:"vapp" cty:"vapp" hcl:"vapp"` - DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"` - Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"` -} - -// FlatMapstructure returns a new FlatCloneConfig. -// FlatCloneConfig is an auto-generated flat version of CloneConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*CloneConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatCloneConfig) -} - -// HCL2Spec returns the hcl spec of a CloneConfig. -// This spec is used by HCL to read the fields of CloneConfig. -// The decoded values from this spec will then be applied to a FlatCloneConfig. -func (*FlatCloneConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "template": &hcldec.AttrSpec{Name: "template", Type: cty.String, Required: false}, - "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false}, - "linked_clone": &hcldec.AttrSpec{Name: "linked_clone", Type: cty.Bool, Required: false}, - "network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false}, - "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, - "notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false}, - "vapp": &hcldec.BlockSpec{TypeName: "vapp", Nested: hcldec.ObjectSpec((*FlatvAppConfig)(nil).HCL2Spec())}, - "disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false}, - "storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())}, - } - return s -} - -// FlatvAppConfig is an auto-generated flat version of vAppConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatvAppConfig struct { - Properties map[string]string `mapstructure:"properties" cty:"properties" hcl:"properties"` -} - -// FlatMapstructure returns a new FlatvAppConfig. -// FlatvAppConfig is an auto-generated flat version of vAppConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*vAppConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatvAppConfig) -} - -// HCL2Spec returns the hcl spec of a vAppConfig. -// This spec is used by HCL to read the fields of vAppConfig. -// The decoded values from this spec will then be applied to a FlatvAppConfig. -func (*FlatvAppConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "properties": &hcldec.AttrSpec{Name: "properties", Type: cty.Map(cty.String), Required: false}, - } - return s -} diff --git a/builder/vsphere/clone/step_clone_test.go b/builder/vsphere/clone/step_clone_test.go deleted file mode 100644 index 9b23ea443..000000000 --- a/builder/vsphere/clone/step_clone_test.go +++ /dev/null @@ -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, - } -} diff --git a/builder/vsphere/clone/step_customize.go b/builder/vsphere/clone/step_customize.go deleted file mode 100644 index 0a48d0c24..000000000 --- a/builder/vsphere/clone/step_customize.go +++ /dev/null @@ -1,276 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type CustomizeConfig,LinuxOptions,NetworkInterfaces,NetworkInterface,GlobalDnsSettings,GlobalRoutingSettings -package clone - -import ( - "context" - "fmt" - "io/ioutil" - "net" - - "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/vmware/govmomi/vim25/types" -) - -// A cloned virtual machine can be [customized](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-58E346FF-83AE-42B8-BE58-253641D257BC.html) -// to configure host, network, or licensing settings. -// -// To perform virtual machine customization as a part of the clone process, specify the customize block with the -// respective customization options. Windows guests are customized using Sysprep, which will result in the machine SID being reset. -// Before using customization, check that your source VM meets the [requirements](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-E63B6FAA-8D35-428D-B40C-744769845906.html) -// for guest OS customization on vSphere. -// See the [customization example](#customization-example) for a usage synopsis. -// -// The settings for customize are as follows: -type CustomizeConfig struct { - // Settings to Linux guest OS customization. See [Linux customization settings](#linux-customization-settings). - LinuxOptions *LinuxOptions `mapstructure:"linux_options"` - // Supply your own sysprep.xml file to allow full control of the customization process out-of-band of vSphere. - WindowsSysPrepFile string `mapstructure:"windows_sysprep_file"` - // Configure network interfaces on a per-interface basis that should matched up to the network adapters present in the VM. - // To use DHCP, declare an empty network_interface for each adapter being configured. This field is required. - // See [Network interface settings](#network-interface-settings). - NetworkInterfaces NetworkInterfaces `mapstructure:"network_interface"` - GlobalRoutingSettings `mapstructure:",squash"` - GlobalDnsSettings `mapstructure:",squash"` -} - -type LinuxOptions struct { - // The domain name for this machine. This, along with [host_name](#host_name), make up the FQDN of this virtual machine. - Domain string `mapstructure:"domain"` - // The host name for this machine. This, along with [domain](#domain), make up the FQDN of this virtual machine. - Hostname string `mapstructure:"host_name"` - // Tells the operating system that the hardware clock is set to UTC. Default: true. - HWClockUTC config.Trilean `mapstructure:"hw_clock_utc"` - // Sets the time zone. The default is UTC. - Timezone string `mapstructure:"time_zone"` -} - -type NetworkInterface struct { - // Network interface-specific DNS server settings for Windows operating systems. - // Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section. - DnsServerList []string `mapstructure:"dns_server_list"` - // Network interface-specific DNS search domain for Windows operating systems. - // Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section. - DnsDomain string `mapstructure:"dns_domain"` - // The IPv4 address assigned to this network adapter. If left blank or not included, DHCP is used. - Ipv4Address string `mapstructure:"ipv4_address"` - // The IPv4 subnet mask, in bits (example: 24 for 255.255.255.0). - Ipv4NetMask int `mapstructure:"ipv4_netmask"` - // The IPv6 address assigned to this network adapter. If left blank or not included, auto-configuration is used. - Ipv6Address string `mapstructure:"ipv6_address"` - // The IPv6 subnet mask, in bits (example: 32). - Ipv6NetMask int `mapstructure:"ipv6_netmask"` -} - -type NetworkInterfaces []NetworkInterface - -// The settings here must match the IP/mask of at least one network_interface supplied to customization. -type GlobalRoutingSettings struct { - // The IPv4 default gateway when using network_interface customization on the virtual machine. - Ipv4Gateway string `mapstructure:"ipv4_gateway"` - // The IPv6 default gateway when using network_interface customization on the virtual machine. - Ipv6Gateway string `mapstructure:"ipv6_gateway"` -} - -// The following settings configure DNS globally, generally for Linux systems. For Windows systems, -// this is done per-interface, see [network interface](#network_interface) settings. -type GlobalDnsSettings struct { - // The list of DNS servers to configure on a virtual machine. - DnsServerList []string `mapstructure:"dns_server_list"` - // A list of DNS search domains to add to the DNS configuration on the virtual machine. - DnsSuffixList []string `mapstructure:"dns_suffix_list"` -} - -type StepCustomize struct { - Config *CustomizeConfig -} - -func (c *CustomizeConfig) Prepare() []error { - var errs []error - - if c.LinuxOptions == nil && c.WindowsSysPrepFile == "" { - errs = append(errs, fmt.Errorf("customize is empty")) - } - if c.LinuxOptions != nil && c.WindowsSysPrepFile != "" { - errs = append(errs, fmt.Errorf("`linux_options` and `windows_sysprep_text` both set - one must not be included if the other is specified")) - } - - if c.LinuxOptions != nil { - if c.LinuxOptions.Hostname == "" { - errs = append(errs, fmt.Errorf("linux options `host_name` is empty")) - } - if c.LinuxOptions.Domain == "" { - errs = append(errs, fmt.Errorf("linux options `domain` is empty")) - } - - if c.LinuxOptions.HWClockUTC == config.TriUnset { - c.LinuxOptions.HWClockUTC = config.TriTrue - } - if c.LinuxOptions.Timezone == "" { - c.LinuxOptions.Timezone = "UTC" - } - } - - if len(c.NetworkInterfaces) == 0 { - errs = append(errs, fmt.Errorf("one or more `network_interface` must be provided")) - } - - return errs -} - -func (s *StepCustomize) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - vm := state.Get("vm").(*driver.VirtualMachineDriver) - ui := state.Get("ui").(packersdk.Ui) - - identity, err := s.identitySettings() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - nicSettingsMap := s.nicSettingsMap() - globalIpSettings := s.globalIpSettings() - - spec := types.CustomizationSpec{ - Identity: identity, - NicSettingMap: nicSettingsMap, - GlobalIPSettings: globalIpSettings, - } - ui.Say("Customizing VM...") - err = vm.Customize(spec) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *StepCustomize) identitySettings() (types.BaseCustomizationIdentitySettings, error) { - if s.Config.LinuxOptions != nil { - return &types.CustomizationLinuxPrep{ - HostName: &types.CustomizationFixedName{ - Name: s.Config.LinuxOptions.Hostname, - }, - Domain: s.Config.LinuxOptions.Domain, - TimeZone: s.Config.LinuxOptions.Timezone, - HwClockUTC: s.Config.LinuxOptions.HWClockUTC.ToBoolPointer(), - }, nil - } - - if s.Config.WindowsSysPrepFile != "" { - sysPrep, err := ioutil.ReadFile(s.Config.WindowsSysPrepFile) - if err != nil { - return nil, fmt.Errorf("error on reading %s: %s", s.Config.WindowsSysPrepFile, err) - } - return &types.CustomizationSysprepText{ - Value: string(sysPrep), - }, nil - } - - return nil, fmt.Errorf("no customization identity found") -} - -func (s *StepCustomize) nicSettingsMap() []types.CustomizationAdapterMapping { - result := make([]types.CustomizationAdapterMapping, len(s.Config.NetworkInterfaces)) - var ipv4gwFound, ipv6gwFound bool - for i := range s.Config.NetworkInterfaces { - var adapter types.CustomizationIPSettings - adapter, ipv4gwFound, ipv6gwFound = s.ipSettings(i, !ipv4gwFound, !ipv6gwFound) - obj := types.CustomizationAdapterMapping{ - Adapter: adapter, - } - result[i] = obj - } - return result -} - -func (s *StepCustomize) ipSettings(n int, ipv4gwAdd bool, ipv6gwAdd bool) (types.CustomizationIPSettings, bool, bool) { - var v4gwFound, v6gwFound bool - var obj types.CustomizationIPSettings - - ipv4Address := s.Config.NetworkInterfaces[n].Ipv4Address - if ipv4Address != "" { - ipv4mask := s.Config.NetworkInterfaces[n].Ipv4NetMask - ipv4Gateway := s.Config.Ipv4Gateway - obj.Ip = &types.CustomizationFixedIp{ - IpAddress: ipv4Address, - } - obj.SubnetMask = v4CIDRMaskToDotted(ipv4mask) - // Check for the gateway - if ipv4gwAdd && ipv4Gateway != "" && matchGateway(ipv4Address, ipv4mask, ipv4Gateway) { - obj.Gateway = []string{ipv4Gateway} - v4gwFound = true - } - } else { - obj.Ip = &types.CustomizationDhcpIpGenerator{} - } - - obj.DnsServerList = s.Config.NetworkInterfaces[n].DnsServerList - obj.DnsDomain = s.Config.NetworkInterfaces[n].DnsDomain - obj.IpV6Spec, v6gwFound = s.IPSettingsIPV6Address(n, ipv6gwAdd) - - return obj, v4gwFound, v6gwFound -} - -func v4CIDRMaskToDotted(mask int) string { - m := net.CIDRMask(mask, 32) - a := int(m[0]) - b := int(m[1]) - c := int(m[2]) - d := int(m[3]) - return fmt.Sprintf("%d.%d.%d.%d", a, b, c, d) -} - -func (s *StepCustomize) IPSettingsIPV6Address(n int, gwAdd bool) (*types.CustomizationIPSettingsIpV6AddressSpec, bool) { - addr := s.Config.NetworkInterfaces[n].Ipv6Address - var gwFound bool - if addr == "" { - return nil, gwFound - } - mask := s.Config.NetworkInterfaces[n].Ipv6NetMask - gw := s.Config.Ipv6Gateway - obj := &types.CustomizationIPSettingsIpV6AddressSpec{ - Ip: []types.BaseCustomizationIpV6Generator{ - &types.CustomizationFixedIpV6{ - IpAddress: addr, - SubnetMask: int32(mask), - }, - }, - } - if gwAdd && gw != "" && matchGateway(addr, mask, gw) { - obj.Gateway = []string{gw} - gwFound = true - } - return obj, gwFound -} - -// matchGateway take an IP, mask, and gateway, and checks to see if the gateway -// is reachable from the IP address. -func matchGateway(a string, m int, g string) bool { - ip := net.ParseIP(a) - gw := net.ParseIP(g) - var mask net.IPMask - if ip.To4() != nil { - mask = net.CIDRMask(m, 32) - } else { - mask = net.CIDRMask(m, 128) - } - if ip.Mask(mask).Equal(gw.Mask(mask)) { - return true - } - return false -} - -func (s *StepCustomize) globalIpSettings() types.CustomizationGlobalIPSettings { - return types.CustomizationGlobalIPSettings{ - DnsServerList: s.Config.DnsServerList, - DnsSuffixList: s.Config.DnsSuffixList, - } -} - -func (s *StepCustomize) Cleanup(_ multistep.StateBag) {} diff --git a/builder/vsphere/clone/step_customize.hcl2spec.go b/builder/vsphere/clone/step_customize.hcl2spec.go deleted file mode 100644 index 0634474a3..000000000 --- a/builder/vsphere/clone/step_customize.hcl2spec.go +++ /dev/null @@ -1,155 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type CustomizeConfig,LinuxOptions,NetworkInterfaces,NetworkInterface,GlobalDnsSettings,GlobalRoutingSettings"; DO NOT EDIT. - -package clone - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatCustomizeConfig is an auto-generated flat version of CustomizeConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatCustomizeConfig struct { - LinuxOptions *FlatLinuxOptions `mapstructure:"linux_options" cty:"linux_options" hcl:"linux_options"` - WindowsSysPrepFile *string `mapstructure:"windows_sysprep_file" cty:"windows_sysprep_file" hcl:"windows_sysprep_file"` - NetworkInterfaces []FlatNetworkInterface `mapstructure:"network_interface" cty:"network_interface" hcl:"network_interface"` - Ipv4Gateway *string `mapstructure:"ipv4_gateway" cty:"ipv4_gateway" hcl:"ipv4_gateway"` - Ipv6Gateway *string `mapstructure:"ipv6_gateway" cty:"ipv6_gateway" hcl:"ipv6_gateway"` - DnsServerList []string `mapstructure:"dns_server_list" cty:"dns_server_list" hcl:"dns_server_list"` - DnsSuffixList []string `mapstructure:"dns_suffix_list" cty:"dns_suffix_list" hcl:"dns_suffix_list"` -} - -// FlatMapstructure returns a new FlatCustomizeConfig. -// FlatCustomizeConfig is an auto-generated flat version of CustomizeConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*CustomizeConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatCustomizeConfig) -} - -// HCL2Spec returns the hcl spec of a CustomizeConfig. -// This spec is used by HCL to read the fields of CustomizeConfig. -// The decoded values from this spec will then be applied to a FlatCustomizeConfig. -func (*FlatCustomizeConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "linux_options": &hcldec.BlockSpec{TypeName: "linux_options", Nested: hcldec.ObjectSpec((*FlatLinuxOptions)(nil).HCL2Spec())}, - "windows_sysprep_file": &hcldec.AttrSpec{Name: "windows_sysprep_file", Type: cty.String, Required: false}, - "network_interface": &hcldec.BlockListSpec{TypeName: "network_interface", Nested: hcldec.ObjectSpec((*FlatNetworkInterface)(nil).HCL2Spec())}, - "ipv4_gateway": &hcldec.AttrSpec{Name: "ipv4_gateway", Type: cty.String, Required: false}, - "ipv6_gateway": &hcldec.AttrSpec{Name: "ipv6_gateway", Type: cty.String, Required: false}, - "dns_server_list": &hcldec.AttrSpec{Name: "dns_server_list", Type: cty.List(cty.String), Required: false}, - "dns_suffix_list": &hcldec.AttrSpec{Name: "dns_suffix_list", Type: cty.List(cty.String), Required: false}, - } - return s -} - -// FlatGlobalDnsSettings is an auto-generated flat version of GlobalDnsSettings. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatGlobalDnsSettings struct { - DnsServerList []string `mapstructure:"dns_server_list" cty:"dns_server_list" hcl:"dns_server_list"` - DnsSuffixList []string `mapstructure:"dns_suffix_list" cty:"dns_suffix_list" hcl:"dns_suffix_list"` -} - -// FlatMapstructure returns a new FlatGlobalDnsSettings. -// FlatGlobalDnsSettings is an auto-generated flat version of GlobalDnsSettings. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*GlobalDnsSettings) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatGlobalDnsSettings) -} - -// HCL2Spec returns the hcl spec of a GlobalDnsSettings. -// This spec is used by HCL to read the fields of GlobalDnsSettings. -// The decoded values from this spec will then be applied to a FlatGlobalDnsSettings. -func (*FlatGlobalDnsSettings) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "dns_server_list": &hcldec.AttrSpec{Name: "dns_server_list", Type: cty.List(cty.String), Required: false}, - "dns_suffix_list": &hcldec.AttrSpec{Name: "dns_suffix_list", Type: cty.List(cty.String), Required: false}, - } - return s -} - -// FlatGlobalRoutingSettings is an auto-generated flat version of GlobalRoutingSettings. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatGlobalRoutingSettings struct { - Ipv4Gateway *string `mapstructure:"ipv4_gateway" cty:"ipv4_gateway" hcl:"ipv4_gateway"` - Ipv6Gateway *string `mapstructure:"ipv6_gateway" cty:"ipv6_gateway" hcl:"ipv6_gateway"` -} - -// FlatMapstructure returns a new FlatGlobalRoutingSettings. -// FlatGlobalRoutingSettings is an auto-generated flat version of GlobalRoutingSettings. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*GlobalRoutingSettings) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatGlobalRoutingSettings) -} - -// HCL2Spec returns the hcl spec of a GlobalRoutingSettings. -// This spec is used by HCL to read the fields of GlobalRoutingSettings. -// The decoded values from this spec will then be applied to a FlatGlobalRoutingSettings. -func (*FlatGlobalRoutingSettings) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "ipv4_gateway": &hcldec.AttrSpec{Name: "ipv4_gateway", Type: cty.String, Required: false}, - "ipv6_gateway": &hcldec.AttrSpec{Name: "ipv6_gateway", Type: cty.String, Required: false}, - } - return s -} - -// FlatLinuxOptions is an auto-generated flat version of LinuxOptions. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatLinuxOptions struct { - Domain *string `mapstructure:"domain" cty:"domain" hcl:"domain"` - Hostname *string `mapstructure:"host_name" cty:"host_name" hcl:"host_name"` - HWClockUTC *bool `mapstructure:"hw_clock_utc" cty:"hw_clock_utc" hcl:"hw_clock_utc"` - Timezone *string `mapstructure:"time_zone" cty:"time_zone" hcl:"time_zone"` -} - -// FlatMapstructure returns a new FlatLinuxOptions. -// FlatLinuxOptions is an auto-generated flat version of LinuxOptions. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*LinuxOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatLinuxOptions) -} - -// HCL2Spec returns the hcl spec of a LinuxOptions. -// This spec is used by HCL to read the fields of LinuxOptions. -// The decoded values from this spec will then be applied to a FlatLinuxOptions. -func (*FlatLinuxOptions) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "domain": &hcldec.AttrSpec{Name: "domain", Type: cty.String, Required: false}, - "host_name": &hcldec.AttrSpec{Name: "host_name", Type: cty.String, Required: false}, - "hw_clock_utc": &hcldec.AttrSpec{Name: "hw_clock_utc", Type: cty.Bool, Required: false}, - "time_zone": &hcldec.AttrSpec{Name: "time_zone", Type: cty.String, Required: false}, - } - return s -} - -// FlatNetworkInterface is an auto-generated flat version of NetworkInterface. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatNetworkInterface struct { - DnsServerList []string `mapstructure:"dns_server_list" cty:"dns_server_list" hcl:"dns_server_list"` - DnsDomain *string `mapstructure:"dns_domain" cty:"dns_domain" hcl:"dns_domain"` - Ipv4Address *string `mapstructure:"ipv4_address" cty:"ipv4_address" hcl:"ipv4_address"` - Ipv4NetMask *int `mapstructure:"ipv4_netmask" cty:"ipv4_netmask" hcl:"ipv4_netmask"` - Ipv6Address *string `mapstructure:"ipv6_address" cty:"ipv6_address" hcl:"ipv6_address"` - Ipv6NetMask *int `mapstructure:"ipv6_netmask" cty:"ipv6_netmask" hcl:"ipv6_netmask"` -} - -// FlatMapstructure returns a new FlatNetworkInterface. -// FlatNetworkInterface is an auto-generated flat version of NetworkInterface. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*NetworkInterface) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatNetworkInterface) -} - -// HCL2Spec returns the hcl spec of a NetworkInterface. -// This spec is used by HCL to read the fields of NetworkInterface. -// The decoded values from this spec will then be applied to a FlatNetworkInterface. -func (*FlatNetworkInterface) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "dns_server_list": &hcldec.AttrSpec{Name: "dns_server_list", Type: cty.List(cty.String), Required: false}, - "dns_domain": &hcldec.AttrSpec{Name: "dns_domain", Type: cty.String, Required: false}, - "ipv4_address": &hcldec.AttrSpec{Name: "ipv4_address", Type: cty.String, Required: false}, - "ipv4_netmask": &hcldec.AttrSpec{Name: "ipv4_netmask", Type: cty.Number, Required: false}, - "ipv6_address": &hcldec.AttrSpec{Name: "ipv6_address", Type: cty.String, Required: false}, - "ipv6_netmask": &hcldec.AttrSpec{Name: "ipv6_netmask", Type: cty.Number, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/artifact.go b/builder/vsphere/common/artifact.go deleted file mode 100644 index 267b03d8b..000000000 --- a/builder/vsphere/common/artifact.go +++ /dev/null @@ -1,50 +0,0 @@ -package common - -import ( - "os" - - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -const BuilderId = "jetbrains.vsphere" - -type Artifact struct { - Outconfig *OutputConfig - Name string - VM *driver.VirtualMachineDriver - - // StateData should store data such as GeneratedData - // to be shared with post-processors - StateData map[string]interface{} -} - -func (a *Artifact) BuilderId() string { - return BuilderId -} - -func (a *Artifact) Files() []string { - if a.Outconfig != nil { - files, _ := a.Outconfig.ListFiles() - return files - } - return []string{} -} - -func (a *Artifact) Id() string { - return a.Name -} - -func (a *Artifact) String() string { - return a.Name -} - -func (a *Artifact) State(name string) interface{} { - return a.StateData[name] -} - -func (a *Artifact) Destroy() error { - if a.Outconfig != nil { - os.RemoveAll(a.Outconfig.OutputDir) - } - return a.VM.Destroy() -} diff --git a/builder/vsphere/common/cleanup_vm.go b/builder/vsphere/common/cleanup_vm.go deleted file mode 100644 index 3e847a9ea..000000000 --- a/builder/vsphere/common/cleanup_vm.go +++ /dev/null @@ -1,30 +0,0 @@ -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" -) - -func CleanupVM(state multistep.StateBag) { - _, cancelled := state.GetOk(multistep.StateCancelled) - _, halted := state.GetOk(multistep.StateHalted) - _, destroy := state.GetOk("destroy_vm") - if !cancelled && !halted && !destroy { - return - } - - ui := state.Get("ui").(packersdk.Ui) - - st := state.Get("vm") - if st == nil { - return - } - vm := st.(driver.VirtualMachine) - - ui.Say("Destroying VM...") - err := vm.Destroy() - if err != nil { - ui.Error(err.Error()) - } -} diff --git a/builder/vsphere/common/cleanup_vm_test.go b/builder/vsphere/common/cleanup_vm_test.go deleted file mode 100644 index d27f30a28..000000000 --- a/builder/vsphere/common/cleanup_vm_test.go +++ /dev/null @@ -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) - } - } - -} diff --git a/builder/vsphere/common/common_test.go b/builder/vsphere/common/common_test.go deleted file mode 100644 index 74fdfa3f9..000000000 --- a/builder/vsphere/common/common_test.go +++ /dev/null @@ -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 -} diff --git a/builder/vsphere/common/config_location.go b/builder/vsphere/common/config_location.go deleted file mode 100644 index 06c651a10..000000000 --- a/builder/vsphere/common/config_location.go +++ /dev/null @@ -1,53 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type LocationConfig - -package common - -import ( - "fmt" - "path" - "strings" -) - -type LocationConfig struct { - // Name of the new VM to create. - VMName string `mapstructure:"vm_name"` - // VM folder to create the VM in. - Folder string `mapstructure:"folder"` - // ESXi cluster where target VM is created. See the - // [Working With Clusters And Hosts](#working-with-clusters-and-hosts) - // section above for more details. - Cluster string `mapstructure:"cluster"` - // ESXi host where target VM is created. A full path must be specified if - // the host is in a folder. For example `folder/host`. See the - // [Working With Clusters And Hosts](#working-with-clusters-and-hosts) - // section above for more details. - Host string `mapstructure:"host"` - // VMWare resource pool. If not set, it will look for the root resource - // pool of the `host` or `cluster`. If a root resource is not found, it - // will then look for a default resource pool. - ResourcePool string `mapstructure:"resource_pool"` - // VMWare datastore. Required if `host` is a cluster, or if `host` has - // multiple datastores. - Datastore string `mapstructure:"datastore"` - // Set this to true if packer should use the host for uploading files - // to the datastore. Defaults to false. - SetHostForDatastoreUploads bool `mapstructure:"set_host_for_datastore_uploads"` -} - -func (c *LocationConfig) Prepare() []error { - var errs []error - - if c.VMName == "" { - errs = append(errs, fmt.Errorf("'vm_name' is required")) - } - if c.Cluster == "" && c.Host == "" { - errs = append(errs, fmt.Errorf("'host' or 'cluster' is required")) - } - - // clean Folder path and remove leading slash as folders are relative within vsphere - c.Folder = path.Clean(c.Folder) - c.Folder = strings.TrimLeft(c.Folder, "/") - - return errs -} diff --git a/builder/vsphere/common/config_location.hcl2spec.go b/builder/vsphere/common/config_location.hcl2spec.go deleted file mode 100644 index c55712475..000000000 --- a/builder/vsphere/common/config_location.hcl2spec.go +++ /dev/null @@ -1,43 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type LocationConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatLocationConfig is an auto-generated flat version of LocationConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatLocationConfig struct { - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"` - Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"` - Host *string `mapstructure:"host" cty:"host" hcl:"host"` - ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"` - Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"` - SetHostForDatastoreUploads *bool `mapstructure:"set_host_for_datastore_uploads" cty:"set_host_for_datastore_uploads" hcl:"set_host_for_datastore_uploads"` -} - -// FlatMapstructure returns a new FlatLocationConfig. -// FlatLocationConfig is an auto-generated flat version of LocationConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*LocationConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatLocationConfig) -} - -// HCL2Spec returns the hcl spec of a LocationConfig. -// This spec is used by HCL to read the fields of LocationConfig. -// The decoded values from this spec will then be applied to a FlatLocationConfig. -func (*FlatLocationConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "folder": &hcldec.AttrSpec{Name: "folder", Type: cty.String, Required: false}, - "cluster": &hcldec.AttrSpec{Name: "cluster", Type: cty.String, Required: false}, - "host": &hcldec.AttrSpec{Name: "host", Type: cty.String, Required: false}, - "resource_pool": &hcldec.AttrSpec{Name: "resource_pool", Type: cty.String, Required: false}, - "datastore": &hcldec.AttrSpec{Name: "datastore", Type: cty.String, Required: false}, - "set_host_for_datastore_uploads": &hcldec.AttrSpec{Name: "set_host_for_datastore_uploads", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/config_ssh.go b/builder/vsphere/common/config_ssh.go deleted file mode 100644 index bb967a45f..000000000 --- a/builder/vsphere/common/config_ssh.go +++ /dev/null @@ -1,15 +0,0 @@ -package common - -import ( - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func CommHost(host string) func(multistep.StateBag) (string, error) { - return func(state multistep.StateBag) (string, error) { - if host != "" { - return host, nil - } else { - return state.Get("ip").(string), nil - } - } -} diff --git a/builder/vsphere/common/output_config.go b/builder/vsphere/common/output_config.go deleted file mode 100644 index 1aef6cc30..000000000 --- a/builder/vsphere/common/output_config.go +++ /dev/null @@ -1,59 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type OutputConfig - -package common - -import ( - "fmt" - "os" - "path/filepath" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -type OutputConfig struct { - // This setting specifies the directory that - // artifacts from the build, such as the virtual machine files and disks, - // will be output to. The path to the directory may be relative or - // absolute. If relative, the path is relative to the working directory - // packer is executed from. This directory must not exist or, if - // created, must be empty prior to running the builder. By default this is - // "output-BUILDNAME" where "BUILDNAME" is the name of the build. - OutputDir string `mapstructure:"output_directory" required:"false"` - // The permissions to apply to the "output_directory", and to any parent - // directories that get created for output_directory. By default this is - // "0750". You should express the permission as quoted string with a - // leading zero such as "0755" in JSON file, because JSON does not support - // octal value. In Unix-like OS, the actual permission may differ from - // this value because of umask. - DirPerm os.FileMode `mapstructure:"directory_permission" required:"false"` -} - -func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { - if c.OutputDir == "" { - c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName) - } - if c.DirPerm == 0 { - c.DirPerm = 0750 - } - - return nil -} - -// Stolen from output_dir_local.go in vmware builder. -func (c *OutputConfig) ListFiles() ([]string, error) { - files := make([]string, 0, 10) - - visit := func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - files = append(files, path) - } - return nil - } - - return files, filepath.Walk(c.OutputDir, visit) -} diff --git a/builder/vsphere/common/output_config.hcl2spec.go b/builder/vsphere/common/output_config.hcl2spec.go deleted file mode 100644 index 0cec88325..000000000 --- a/builder/vsphere/common/output_config.hcl2spec.go +++ /dev/null @@ -1,35 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type OutputConfig"; DO NOT EDIT. - -package common - -import ( - "io/fs" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatOutputConfig is an auto-generated flat version of OutputConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatOutputConfig struct { - OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` - DirPerm *fs.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"` -} - -// FlatMapstructure returns a new FlatOutputConfig. -// FlatOutputConfig is an auto-generated flat version of OutputConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*OutputConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatOutputConfig) -} - -// HCL2Spec returns the hcl spec of a OutputConfig. -// This spec is used by HCL to read the fields of OutputConfig. -// The decoded values from this spec will then be applied to a FlatOutputConfig. -func (*FlatOutputConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, - "directory_permission": &hcldec.AttrSpec{Name: "directory_permission", Type: cty.Number, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_add_cdrom.go b/builder/vsphere/common/step_add_cdrom.go deleted file mode 100644 index 887bbc5f9..000000000 --- a/builder/vsphere/common/step_add_cdrom.go +++ /dev/null @@ -1,81 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type CDRomConfig - -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type CDRomConfig struct { - // Which controller to use. Example: `sata`. Defaults to `ide`. - CdromType string `mapstructure:"cdrom_type"` - // List of Datastore or Content Library paths to ISO files that will be mounted to the VM. - // Here's an HCL2 example: - // ```hcl - // iso_paths = [ - // "[datastore1] ISO/ubuntu.iso", - // "Packer Library Test/ubuntu-16.04.6-server-amd64/ubuntu-16.04.6-server-amd64.iso" - // ] - // ``` - ISOPaths []string `mapstructure:"iso_paths"` -} - -type StepAddCDRom struct { - Config *CDRomConfig -} - -func (c *CDRomConfig) Prepare() []error { - var errs []error - - if c.CdromType != "" && c.CdromType != "ide" && c.CdromType != "sata" { - errs = append(errs, fmt.Errorf("'cdrom_type' must be 'ide' or 'sata'")) - } - - return errs -} - -func (s *StepAddCDRom) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(driver.VirtualMachine) - - if s.Config.CdromType == "sata" { - if _, err := vm.FindSATAController(); err == driver.ErrNoSataController { - ui.Say("Adding SATA controller...") - if err := vm.AddSATAController(); err != nil { - state.Put("error", fmt.Errorf("error adding SATA controller: %v", err)) - return multistep.ActionHalt - } - } - } - - ui.Say("Mounting ISO images...") - if path, ok := state.GetOk("iso_remote_path"); ok { - if err := vm.AddCdrom(s.Config.CdromType, path.(string)); err != nil { - state.Put("error", fmt.Errorf("error mounting an image '%v': %v", path, err)) - return multistep.ActionHalt - } - } - - // Add our custom CD, if it exists - if cd_path, _ := state.Get("cd_path").(string); cd_path != "" { - s.Config.ISOPaths = append(s.Config.ISOPaths, cd_path) - } - - if len(s.Config.ISOPaths) > 0 { - for _, path := range s.Config.ISOPaths { - if err := vm.AddCdrom(s.Config.CdromType, path); err != nil { - state.Put("error", fmt.Errorf("error mounting an image '%v': %v", path, err)) - return multistep.ActionHalt - } - } - } - return multistep.ActionContinue -} - -func (s *StepAddCDRom) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_add_cdrom.hcl2spec.go b/builder/vsphere/common/step_add_cdrom.hcl2spec.go deleted file mode 100644 index 205232829..000000000 --- a/builder/vsphere/common/step_add_cdrom.hcl2spec.go +++ /dev/null @@ -1,33 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type CDRomConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatCDRomConfig is an auto-generated flat version of CDRomConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatCDRomConfig struct { - CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type" hcl:"cdrom_type"` - ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths" hcl:"iso_paths"` -} - -// FlatMapstructure returns a new FlatCDRomConfig. -// FlatCDRomConfig is an auto-generated flat version of CDRomConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*CDRomConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatCDRomConfig) -} - -// HCL2Spec returns the hcl spec of a CDRomConfig. -// This spec is used by HCL to read the fields of CDRomConfig. -// The decoded values from this spec will then be applied to a FlatCDRomConfig. -func (*FlatCDRomConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "cdrom_type": &hcldec.AttrSpec{Name: "cdrom_type", Type: cty.String, Required: false}, - "iso_paths": &hcldec.AttrSpec{Name: "iso_paths", Type: cty.List(cty.String), Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_add_cdrom_test.go b/builder/vsphere/common/step_add_cdrom_test.go deleted file mode 100644 index bc50a9e3c..000000000 --- a/builder/vsphere/common/step_add_cdrom_test.go +++ /dev/null @@ -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 -} diff --git a/builder/vsphere/common/step_add_floppy.go b/builder/vsphere/common/step_add_floppy.go deleted file mode 100644 index a56671348..000000000 --- a/builder/vsphere/common/step_add_floppy.go +++ /dev/null @@ -1,111 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type FloppyConfig - -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type FloppyConfig struct { - // Datastore path to a floppy image that will be mounted to the VM. - // Example: `[datastore1] ISO/pvscsi-Windows8.flp`. - FloppyIMGPath string `mapstructure:"floppy_img_path"` - // List of local files to be mounted to the VM floppy drive. Can be used to - // make Debian preseed or RHEL kickstart files available to the VM. - FloppyFiles []string `mapstructure:"floppy_files"` - // List of directories to copy files from. - FloppyDirectories []string `mapstructure:"floppy_dirs"` - // The label to use for the floppy disk that - // is attached when the VM is booted. This is most useful for cloud-init, - // Kickstart or other early initialization tools, which can benefit from labelled floppy disks. - // By default, the floppy label will be 'packer'. - FloppyLabel string `mapstructure:"floppy_label"` -} - -type StepAddFloppy struct { - Config *FloppyConfig - Datastore string - Host string - SetHostForDatastoreUploads bool -} - -func (s *StepAddFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(driver.VirtualMachine) - d := state.Get("driver").(driver.Driver) - - if floppyPath, ok := state.GetOk("floppy_path"); ok { - ui.Say("Uploading created floppy image") - - ds, err := d.FindDatastore(s.Datastore, s.Host) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - vmDir, err := vm.GetDir() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - uploadPath := fmt.Sprintf("%v/packer-tmp-created-floppy.flp", vmDir) - if err := ds.UploadFile(floppyPath.(string), uploadPath, s.Host, s.SetHostForDatastoreUploads); err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - state.Put("uploaded_floppy_path", uploadPath) - - ui.Say("Adding generated Floppy...") - floppyIMGPath := ds.ResolvePath(uploadPath) - err = vm.AddFloppy(floppyIMGPath) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } - - if s.Config.FloppyIMGPath != "" { - ui.Say("Adding Floppy image...") - err := vm.AddFloppy(s.Config.FloppyIMGPath) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepAddFloppy) Cleanup(state multistep.StateBag) { - _, cancelled := state.GetOk(multistep.StateCancelled) - _, halted := state.GetOk(multistep.StateHalted) - if !cancelled && !halted { - return - } - - ui := state.Get("ui").(packersdk.Ui) - d := state.Get("driver").(driver.Driver) - - if UploadedFloppyPath, ok := state.GetOk("uploaded_floppy_path"); ok { - ui.Say("Deleting Floppy image ...") - - ds, err := d.FindDatastore(s.Datastore, s.Host) - if err != nil { - state.Put("error", err) - return - } - - err = ds.Delete(UploadedFloppyPath.(string)) - if err != nil { - state.Put("error", err) - return - } - - } -} diff --git a/builder/vsphere/common/step_add_floppy.hcl2spec.go b/builder/vsphere/common/step_add_floppy.hcl2spec.go deleted file mode 100644 index a42511314..000000000 --- a/builder/vsphere/common/step_add_floppy.hcl2spec.go +++ /dev/null @@ -1,37 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type FloppyConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatFloppyConfig is an auto-generated flat version of FloppyConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatFloppyConfig struct { - FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path" hcl:"floppy_img_path"` - FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"` - FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"` - FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"` -} - -// FlatMapstructure returns a new FlatFloppyConfig. -// FlatFloppyConfig is an auto-generated flat version of FloppyConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*FloppyConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatFloppyConfig) -} - -// HCL2Spec returns the hcl spec of a FloppyConfig. -// This spec is used by HCL to read the fields of FloppyConfig. -// The decoded values from this spec will then be applied to a FlatFloppyConfig. -func (*FlatFloppyConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "floppy_img_path": &hcldec.AttrSpec{Name: "floppy_img_path", Type: cty.String, Required: false}, - "floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false}, - "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, - "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_add_floppy_test.go b/builder/vsphere/common/step_add_floppy_test.go deleted file mode 100644 index d6533580a..000000000 --- a/builder/vsphere/common/step_add_floppy_test.go +++ /dev/null @@ -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) - } - }) - } -} diff --git a/builder/vsphere/common/step_boot_command.go b/builder/vsphere/common/step_boot_command.go deleted file mode 100644 index 5847d1f08..000000000 --- a/builder/vsphere/common/step_boot_command.go +++ /dev/null @@ -1,152 +0,0 @@ -//go:generate struct-markdown -package common - -import ( - "context" - "fmt" - "time" - - "github.com/hashicorp/packer-plugin-sdk/bootcommand" - "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" - "golang.org/x/mobile/event/key" -) - -type BootConfig struct { - bootcommand.BootConfig `mapstructure:",squash"` - // The IP address to use for the HTTP server started to serve the `http_directory`. - // If unset, Packer will automatically discover and assign an IP. - HTTPIP string `mapstructure:"http_ip"` -} - -type bootCommandTemplateData struct { - HTTPIP string - HTTPPort int - Name string -} - -func (c *BootConfig) Prepare(ctx *interpolate.Context) []error { - if c.BootWait == 0 { - c.BootWait = 10 * time.Second - } - return c.BootConfig.Prepare(ctx) -} - -type StepBootCommand struct { - Config *BootConfig - VMName string - Ctx interpolate.Context -} - -func (s *StepBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - debug := state.Get("debug").(bool) - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - if s.Config.BootCommand == nil { - return multistep.ActionContinue - } - - // Wait the for the vm to boot. - if int64(s.Config.BootWait) > 0 { - ui.Say(fmt.Sprintf("Waiting %s for boot...", s.Config.BootWait.String())) - select { - case <-time.After(s.Config.BootWait): - break - case <-ctx.Done(): - return multistep.ActionHalt - } - } - - var pauseFn multistep.DebugPauseFn - if debug { - pauseFn = state.Get("pauseFn").(multistep.DebugPauseFn) - } - - port := state.Get("http_port").(int) - if port > 0 { - ip := state.Get("http_ip").(string) - s.Ctx.Data = &bootCommandTemplateData{ - ip, - port, - s.VMName, - } - ui.Say(fmt.Sprintf("HTTP server is working at http://%v:%v/", ip, port)) - } - - var keyAlt, keyCtrl, keyShift bool - sendCodes := func(code key.Code, down bool) error { - switch code { - case key.CodeLeftAlt: - keyAlt = down - case key.CodeLeftControl: - keyCtrl = down - case key.CodeLeftShift: - keyShift = down - } - - shift := down - if keyShift { - shift = keyShift - } - - _, err := vm.TypeOnKeyboard(driver.KeyInput{ - Scancode: code, - Ctrl: keyCtrl, - Alt: keyAlt, - Shift: shift, - }) - if err != nil { - // retry once if error - ui.Error(fmt.Errorf("error typing a boot command (code, down) `%d, %t`: %w", code, down, err).Error()) - ui.Say("trying key input again") - time.Sleep(s.Config.BootGroupInterval) - _, err = vm.TypeOnKeyboard(driver.KeyInput{ - Scancode: code, - Ctrl: keyCtrl, - Alt: keyAlt, - Shift: shift, - }) - if err != nil { - return fmt.Errorf("error typing a boot command (code, down) `%d, %t`: %w", code, down, err) - } - } - return nil - } - d := bootcommand.NewUSBDriver(sendCodes, s.Config.BootGroupInterval) - - ui.Say("Typing boot command...") - flatBootCommand := s.Config.FlatBootCommand() - command, err := interpolate.Render(flatBootCommand, &s.Ctx) - if err != nil { - err := fmt.Errorf("Error preparing boot command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - seq, err := bootcommand.GenerateExpressionSequence(command) - if err != nil { - err := fmt.Errorf("Error generating boot command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if err := seq.Do(ctx, d); err != nil { - err := fmt.Errorf("Error running boot command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if pauseFn != nil { - pauseFn(multistep.DebugLocationAfterRun, fmt.Sprintf("boot_command: %s", command), state) - } - - return multistep.ActionContinue -} - -func (s *StepBootCommand) Cleanup(_ multistep.StateBag) {} diff --git a/builder/vsphere/common/step_config_params.go b/builder/vsphere/common/step_config_params.go deleted file mode 100644 index e9e52f0ec..000000000 --- a/builder/vsphere/common/step_config_params.go +++ /dev/null @@ -1,65 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type ConfigParamsConfig - -package common - -import ( - "context" - "fmt" - - "github.com/vmware/govmomi/vim25/types" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type ConfigParamsConfig struct { - // configuration_parameters is a direct passthrough to the VSphere API's - // ConfigSpec: https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.ConfigSpec.html - ConfigParams map[string]string `mapstructure:"configuration_parameters"` - - // Enables time synchronization with the host. Defaults to false. - ToolsSyncTime bool `mapstructure:"tools_sync_time"` - - // If sets to true, vSphere will automatically check and upgrade VMware Tools upon a system power cycle. - // If not set, defaults to manual upgrade. - ToolsUpgradePolicy bool `mapstructure:"tools_upgrade_policy"` -} - -type StepConfigParams struct { - Config *ConfigParamsConfig -} - -func (s *StepConfigParams) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - configParams := make(map[string]string) - - if s.Config.ConfigParams != nil { - configParams = s.Config.ConfigParams - } - - var info *types.ToolsConfigInfo - if s.Config.ToolsSyncTime || s.Config.ToolsUpgradePolicy { - info = &types.ToolsConfigInfo{} - - if s.Config.ToolsSyncTime { - info.SyncTimeWithHost = &s.Config.ToolsSyncTime - } - - if s.Config.ToolsUpgradePolicy { - info.ToolsUpgradePolicy = "UpgradeAtPowerCycle" - } - } - - ui.Say("Adding configuration parameters...") - if err := vm.AddConfigParams(configParams, info); err != nil { - state.Put("error", fmt.Errorf("error adding configuration parameters: %v", err)) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *StepConfigParams) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_config_params.hcl2spec.go b/builder/vsphere/common/step_config_params.hcl2spec.go deleted file mode 100644 index a68cb3ad2..000000000 --- a/builder/vsphere/common/step_config_params.hcl2spec.go +++ /dev/null @@ -1,35 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type ConfigParamsConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfigParamsConfig is an auto-generated flat version of ConfigParamsConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfigParamsConfig struct { - ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"` - ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"` - ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"` -} - -// FlatMapstructure returns a new FlatConfigParamsConfig. -// FlatConfigParamsConfig is an auto-generated flat version of ConfigParamsConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*ConfigParamsConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfigParamsConfig) -} - -// HCL2Spec returns the hcl spec of a ConfigParamsConfig. -// This spec is used by HCL to read the fields of ConfigParamsConfig. -// The decoded values from this spec will then be applied to a FlatConfigParamsConfig. -func (*FlatConfigParamsConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false}, - "tools_sync_time": &hcldec.AttrSpec{Name: "tools_sync_time", Type: cty.Bool, Required: false}, - "tools_upgrade_policy": &hcldec.AttrSpec{Name: "tools_upgrade_policy", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_connect.go b/builder/vsphere/common/step_connect.go deleted file mode 100644 index 6afec36d8..000000000 --- a/builder/vsphere/common/step_connect.go +++ /dev/null @@ -1,64 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type ConnectConfig - -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type ConnectConfig struct { - // vCenter server hostname. - VCenterServer string `mapstructure:"vcenter_server"` - // vSphere username. - Username string `mapstructure:"username"` - // vSphere password. - Password string `mapstructure:"password"` - // Do not validate vCenter server's TLS certificate. Defaults to `false`. - InsecureConnection bool `mapstructure:"insecure_connection"` - // VMware datacenter name. Required if there is more than one datacenter in vCenter. - Datacenter string `mapstructure:"datacenter"` -} - -func (c *ConnectConfig) Prepare() []error { - var errs []error - - if c.VCenterServer == "" { - errs = append(errs, fmt.Errorf("'vcenter_server' is required")) - } - if c.Username == "" { - errs = append(errs, fmt.Errorf("'username' is required")) - } - if c.Password == "" { - errs = append(errs, fmt.Errorf("'password' is required")) - } - - return errs -} - -type StepConnect struct { - Config *ConnectConfig -} - -func (s *StepConnect) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - d, err := driver.NewDriver(&driver.ConnectConfig{ - VCenterServer: s.Config.VCenterServer, - Username: s.Config.Username, - Password: s.Config.Password, - InsecureConnection: s.Config.InsecureConnection, - Datacenter: s.Config.Datacenter, - }) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - state.Put("driver", d) - - return multistep.ActionContinue -} - -func (s *StepConnect) Cleanup(multistep.StateBag) {} diff --git a/builder/vsphere/common/step_connect.hcl2spec.go b/builder/vsphere/common/step_connect.hcl2spec.go deleted file mode 100644 index fa5782e33..000000000 --- a/builder/vsphere/common/step_connect.hcl2spec.go +++ /dev/null @@ -1,39 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type ConnectConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConnectConfig is an auto-generated flat version of ConnectConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConnectConfig struct { - VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection" hcl:"insecure_connection"` - Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"` -} - -// FlatMapstructure returns a new FlatConnectConfig. -// FlatConnectConfig is an auto-generated flat version of ConnectConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*ConnectConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConnectConfig) -} - -// HCL2Spec returns the hcl spec of a ConnectConfig. -// This spec is used by HCL to read the fields of ConnectConfig. -// The decoded values from this spec will then be applied to a FlatConnectConfig. -func (*FlatConnectConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "vcenter_server": &hcldec.AttrSpec{Name: "vcenter_server", Type: cty.String, Required: false}, - "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "insecure_connection": &hcldec.AttrSpec{Name: "insecure_connection", Type: cty.Bool, Required: false}, - "datacenter": &hcldec.AttrSpec{Name: "datacenter", Type: cty.String, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_download.go b/builder/vsphere/common/step_download.go deleted file mode 100644 index 93aafc726..000000000 --- a/builder/vsphere/common/step_download.go +++ /dev/null @@ -1,68 +0,0 @@ -package common - -import ( - "context" - "fmt" - "net/url" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -// Defining this interface ensures that we use the common step download, or the -// mock created to test this wrapper -type DownloadStep interface { - Run(context.Context, multistep.StateBag) multistep.StepAction - Cleanup(multistep.StateBag) - UseSourceToFindCacheTarget(source string) (*url.URL, string, error) -} - -// VSphere has a specialized need -- before we waste time downloading an iso, -// we need to check whether that iso already exists on the remote datastore. -// if it does, we skip the download. This wrapping-step still uses the common -// StepDownload but only if the image isn't already present on the datastore. -type StepDownload struct { - DownloadStep DownloadStep - // These keys are VSphere-specific and used to check the remote datastore. - Url []string - ResultKey string - Datastore string - Host string -} - -func (s *StepDownload) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(driver.Driver) - ui := state.Get("ui").(packersdk.Ui) - - // Check whether iso is present on remote datastore. - ds, err := driver.FindDatastore(s.Datastore, s.Host) - if err != nil { - state.Put("error", fmt.Errorf("datastore doesn't exist: %v", err)) - return multistep.ActionHalt - } - - // loop over URLs to see if any are already present. If they are, store that - // one instate and continue - for _, source := range s.Url { - _, targetPath, err := s.DownloadStep.UseSourceToFindCacheTarget(source) - if err != nil { - state.Put("error", fmt.Errorf("Error getting target path: %s", err)) - return multistep.ActionHalt - } - _, remotePath, _, _ := GetRemoteDirectoryAndPath(targetPath, ds) - - if exists := ds.FileExists(remotePath); exists { - ui.Say(fmt.Sprintf("File %s already uploaded; continuing", targetPath)) - state.Put(s.ResultKey, targetPath) - return multistep.ActionContinue - } - } - - // ISO is not present on datastore, so we need to download, then upload it. - // Pass through to the common download step. - return s.DownloadStep.Run(ctx, state) -} - -func (s *StepDownload) Cleanup(state multistep.StateBag) { -} diff --git a/builder/vsphere/common/step_download_test.go b/builder/vsphere/common/step_download_test.go deleted file mode 100644 index 887868d99..000000000 --- a/builder/vsphere/common/step_download_test.go +++ /dev/null @@ -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) - } - } - } -} diff --git a/builder/vsphere/common/step_export.go b/builder/vsphere/common/step_export.go deleted file mode 100644 index d5dae8401..000000000 --- a/builder/vsphere/common/step_export.go +++ /dev/null @@ -1,338 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type ExportConfig - -package common - -import ( - "bytes" - "context" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "fmt" - "hash" - "io" - "os" - "path/filepath" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/common" - "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/pkg/errors" - "github.com/vmware/govmomi/nfc" - "github.com/vmware/govmomi/vim25/soap" - "github.com/vmware/govmomi/vim25/types" -) - -// You may optionally export an ovf from VSphere to the instance running Packer. -// -// Example usage: -// -// In JSON: -// ```json -// ... -// "vm_name": "example-ubuntu", -// ... -// "export": { -// "force": true, -// "output_directory": "./output_vsphere" -// }, -// ``` -// In HCL2: -// ```hcl -// # ... -// vm_name = "example-ubuntu" -// # ... -// export { -// force = true -// output_directory = "./output_vsphere" -// } -// ``` -// The above configuration would create the following files: -// -// ```text -// ./output_vsphere/example-ubuntu-disk-0.vmdk -// ./output_vsphere/example-ubuntu.mf -// ./output_vsphere/example-ubuntu.ovf -// ``` -type ExportConfig struct { - // name of the ovf. defaults to the name of the VM - Name string `mapstructure:"name"` - // overwrite ovf if it exists - Force bool `mapstructure:"force"` - // include iso and img image files that are attached to the VM - Images bool `mapstructure:"images"` - // generate manifest using sha1, sha256, sha512. Defaults to 'sha256'. Use 'none' for no manifest. - Manifest string `mapstructure:"manifest"` - // Directory on the computer running Packer to export files to - OutputDir OutputConfig `mapstructure:",squash"` - // Advanced ovf export options. Options can include: - // * mac - MAC address is exported for all ethernet devices - // * uuid - UUID is exported for all virtual machines - // * extraconfig - all extra configuration options are exported for a virtual machine - // * nodevicesubtypes - resource subtypes for CD/DVD drives, floppy drives, and serial and parallel ports are not exported - // - // For example, adding the following export config option would output the mac addresses for all Ethernet devices in the ovf file: - // - // In JSON: - // ```json - // ... - // "export": { - // "options": ["mac"] - // }, - // ``` - // In HCL2: - // ```hcl - // ... - // export { - // options = ["mac"] - // } - // ``` - Options []string `mapstructure:"options"` -} - -var sha = map[string]func() hash.Hash{ - "none": nil, - "sha1": sha1.New, - "sha256": sha256.New, - "sha512": sha512.New, -} - -func (c *ExportConfig) Prepare(ctx *interpolate.Context, lc *LocationConfig, pc *common.PackerConfig) []error { - var errs *packersdk.MultiError - - errs = packersdk.MultiErrorAppend(errs, c.OutputDir.Prepare(ctx, pc)...) - - // manifest should default to sha256 - if c.Manifest == "" { - c.Manifest = "sha256" - } - if _, ok := sha[c.Manifest]; !ok { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("unknown hash: %s. available options include available options being 'none', 'sha1', 'sha256', 'sha512'", c.Manifest)) - } - - if c.Name == "" { - c.Name = lc.VMName - } - target := getTarget(c.OutputDir.OutputDir, c.Name) - if !c.Force { - if _, err := os.Stat(target); err == nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("file already exists: %s", target)) - } - } - - if err := os.MkdirAll(c.OutputDir.OutputDir, c.OutputDir.DirPerm); err != nil { - errs = packersdk.MultiErrorAppend(errs, errors.Wrap(err, "unable to make directory for export")) - } - - if errs != nil && len(errs.Errors) > 0 { - return errs.Errors - } - - return nil -} - -func getTarget(dir string, name string) string { - return filepath.Join(dir, name+".ovf") -} - -type StepExport struct { - Name string - Force bool - Images bool - Manifest string - OutputDir string - Options []string - mf bytes.Buffer -} - -func (s *StepExport) Cleanup(multistep.StateBag) { -} - -func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - ui.Message("Starting export...") - lease, err := vm.Export() - if err != nil { - state.Put("error", errors.Wrap(err, "error exporting vm")) - return multistep.ActionHalt - } - - info, err := lease.Wait(ctx, nil) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - u := lease.StartUpdater(ctx, info) - defer u.Done() - - cdp := types.OvfCreateDescriptorParams{ - Name: s.Name, - } - - m := vm.NewOvfManager() - if len(s.Options) > 0 { - exportOptions, err := vm.GetOvfExportOptions(m) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - var unknown []string - for _, option := range s.Options { - found := false - for _, exportOpt := range exportOptions { - if exportOpt.Option == option { - found = true - break - } - } - if !found { - unknown = append(unknown, option) - } - cdp.ExportOption = append(cdp.ExportOption, option) - } - - // only printing error message because the unknown options are just ignored by vcenter - if len(unknown) > 0 { - ui.Error(fmt.Sprintf("unknown export options %s", strings.Join(unknown, ","))) - } - } - - for _, i := range info.Items { - if !s.include(&i) { - continue - } - - if !strings.HasPrefix(i.Path, s.Name) { - i.Path = s.Name + "-" + i.Path - } - - file := i.File() - - ui.Message("Downloading: " + file.Path) - size, err := s.Download(ctx, lease, i) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - // Fix file size descriptor - file.Size = size - - ui.Message("Exporting file: " + file.Path) - cdp.OvfFiles = append(cdp.OvfFiles, file) - } - - if err = lease.Complete(ctx); err != nil { - state.Put("error", errors.Wrap(err, "unable to complete lease")) - return multistep.ActionHalt - } - - desc, err := vm.CreateDescriptor(m, cdp) - if err != nil { - state.Put("error", errors.Wrap(err, "unable to create descriptor")) - return multistep.ActionHalt - } - - target := getTarget(s.OutputDir, s.Name) - file, err := os.Create(target) - if err != nil { - state.Put("error", errors.Wrap(err, "unable to create file: "+target)) - return multistep.ActionHalt - } - - var w io.Writer = file - h, ok := s.newHash() - if ok { - w = io.MultiWriter(file, h) - } - - ui.Message("Writing ovf...") - _, err = io.WriteString(w, desc.OvfDescriptor) - if err != nil { - state.Put("error", errors.Wrap(err, "unable to write descriptor")) - return multistep.ActionHalt - } - - if err = file.Close(); err != nil { - state.Put("error", errors.Wrap(err, "unable to close descriptor")) - return multistep.ActionHalt - } - - if s.Manifest == "none" { - // manifest does not need to be created, return - return multistep.ActionContinue - } - - ui.Message("Creating manifest...") - s.addHash(filepath.Base(target), h) - - file, err = os.Create(filepath.Join(s.OutputDir, s.Name+".mf")) - if err != nil { - state.Put("error", errors.Wrap(err, "unable to create manifest")) - return multistep.ActionHalt - } - - _, err = io.Copy(file, &s.mf) - if err != nil { - state.Put("error", errors.Wrap(err, "unable to write manifest")) - return multistep.ActionHalt - } - - err = file.Close() - if err != nil { - state.Put("error", errors.Wrap(err, "unable to close file")) - return multistep.ActionHalt - } - - ui.Message("Finished exporting...") - return multistep.ActionContinue -} - -func (s *StepExport) include(item *nfc.FileItem) bool { - if s.Images { - return true - } - - return filepath.Ext(item.Path) == ".vmdk" -} - -func (s *StepExport) newHash() (hash.Hash, bool) { - // check if function is nil to handle the 'none' case - if h, ok := sha[s.Manifest]; ok && h != nil { - return h(), true - } - - return nil, false -} - -func (s *StepExport) addHash(p string, h hash.Hash) { - _, _ = fmt.Fprintf(&s.mf, "%s(%s)= %x\n", strings.ToUpper(s.Manifest), p, h.Sum(nil)) -} - -func (s *StepExport) Download(ctx context.Context, lease *nfc.Lease, item nfc.FileItem) (int64, error) { - path := filepath.Join(s.OutputDir, item.Path) - opts := soap.Download{} - - if h, ok := s.newHash(); ok { - opts.Writer = h - defer s.addHash(item.Path, h) - } - - err := lease.DownloadFile(ctx, path, item, opts) - if err != nil { - return 0, err - } - - f, err := os.Stat(path) - if err != nil { - return 0, err - } - return f.Size(), err -} diff --git a/builder/vsphere/common/step_export.hcl2spec.go b/builder/vsphere/common/step_export.hcl2spec.go deleted file mode 100644 index 21824d5d5..000000000 --- a/builder/vsphere/common/step_export.hcl2spec.go +++ /dev/null @@ -1,45 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type ExportConfig"; DO NOT EDIT. - -package common - -import ( - "io/fs" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatExportConfig is an auto-generated flat version of ExportConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatExportConfig struct { - Name *string `mapstructure:"name" cty:"name" hcl:"name"` - Force *bool `mapstructure:"force" cty:"force" hcl:"force"` - Images *bool `mapstructure:"images" cty:"images" hcl:"images"` - Manifest *string `mapstructure:"manifest" cty:"manifest" hcl:"manifest"` - OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` - DirPerm *fs.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"` - Options []string `mapstructure:"options" cty:"options" hcl:"options"` -} - -// FlatMapstructure returns a new FlatExportConfig. -// FlatExportConfig is an auto-generated flat version of ExportConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*ExportConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatExportConfig) -} - -// HCL2Spec returns the hcl spec of a ExportConfig. -// This spec is used by HCL to read the fields of ExportConfig. -// The decoded values from this spec will then be applied to a FlatExportConfig. -func (*FlatExportConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, - "force": &hcldec.AttrSpec{Name: "force", Type: cty.Bool, Required: false}, - "images": &hcldec.AttrSpec{Name: "images", Type: cty.Bool, Required: false}, - "manifest": &hcldec.AttrSpec{Name: "manifest", Type: cty.String, Required: false}, - "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, - "directory_permission": &hcldec.AttrSpec{Name: "directory_permission", Type: cty.Number, Required: false}, - "options": &hcldec.AttrSpec{Name: "options", Type: cty.List(cty.String), Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_hardware.go b/builder/vsphere/common/step_hardware.go deleted file mode 100644 index 853f363eb..000000000 --- a/builder/vsphere/common/step_hardware.go +++ /dev/null @@ -1,98 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type HardwareConfig - -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type HardwareConfig struct { - // Number of CPU cores. - CPUs int32 `mapstructure:"CPUs"` - // Number of CPU cores per socket. - CpuCores int32 `mapstructure:"cpu_cores"` - // Amount of reserved CPU resources in MHz. - CPUReservation int64 `mapstructure:"CPU_reservation"` - // Upper limit of available CPU resources in MHz. - CPULimit int64 `mapstructure:"CPU_limit"` - // Enable CPU hot plug setting for virtual machine. Defaults to `false`. - CpuHotAddEnabled bool `mapstructure:"CPU_hot_plug"` - // Amount of RAM in MB. - RAM int64 `mapstructure:"RAM"` - // Amount of reserved RAM in MB. - RAMReservation int64 `mapstructure:"RAM_reservation"` - // Reserve all available RAM. Defaults to `false`. Cannot be used together - // with `RAM_reservation`. - RAMReserveAll bool `mapstructure:"RAM_reserve_all"` - // Enable RAM hot plug setting for virtual machine. Defaults to `false`. - MemoryHotAddEnabled bool `mapstructure:"RAM_hot_plug"` - // Amount of video memory in KB. - VideoRAM int64 `mapstructure:"video_ram"` - // vGPU profile for accelerated graphics. See [NVIDIA GRID vGPU documentation](https://docs.nvidia.com/grid/latest/grid-vgpu-user-guide/index.html#configure-vmware-vsphere-vm-with-vgpu) - // for examples of profile names. Defaults to none. - VGPUProfile string `mapstructure:"vgpu_profile"` - // Enable nested hardware virtualization for VM. Defaults to `false`. - NestedHV bool `mapstructure:"NestedHV"` - // Set the Firmware for virtual machine. Supported values: `bios`, `efi` or `efi-secure`. Defaults to `bios`. - Firmware string `mapstructure:"firmware"` - // During the boot, force entry into the BIOS setup screen. Defaults to `false`. - ForceBIOSSetup bool `mapstructure:"force_bios_setup"` -} - -func (c *HardwareConfig) Prepare() []error { - var errs []error - - if c.RAMReservation > 0 && c.RAMReserveAll != false { - errs = append(errs, fmt.Errorf("'RAM_reservation' and 'RAM_reserve_all' cannot be used together")) - } - - if c.Firmware != "" && c.Firmware != "bios" && c.Firmware != "efi" && c.Firmware != "efi-secure" { - errs = append(errs, fmt.Errorf("'firmware' must be '', 'bios', 'efi' or 'efi-secure'")) - } - - return errs -} - -type StepConfigureHardware struct { - Config *HardwareConfig -} - -func (s *StepConfigureHardware) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(driver.VirtualMachine) - - if *s.Config != (HardwareConfig{}) { - ui.Say("Customizing hardware...") - - err := vm.Configure(&driver.HardwareConfig{ - CPUs: s.Config.CPUs, - CpuCores: s.Config.CpuCores, - CPUReservation: s.Config.CPUReservation, - CPULimit: s.Config.CPULimit, - RAM: s.Config.RAM, - RAMReservation: s.Config.RAMReservation, - RAMReserveAll: s.Config.RAMReserveAll, - NestedHV: s.Config.NestedHV, - CpuHotAddEnabled: s.Config.CpuHotAddEnabled, - MemoryHotAddEnabled: s.Config.MemoryHotAddEnabled, - VideoRAM: s.Config.VideoRAM, - VGPUProfile: s.Config.VGPUProfile, - Firmware: s.Config.Firmware, - ForceBIOSSetup: s.Config.ForceBIOSSetup, - }) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepConfigureHardware) Cleanup(multistep.StateBag) {} diff --git a/builder/vsphere/common/step_hardware.hcl2spec.go b/builder/vsphere/common/step_hardware.hcl2spec.go deleted file mode 100644 index 334e6a644..000000000 --- a/builder/vsphere/common/step_hardware.hcl2spec.go +++ /dev/null @@ -1,57 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type HardwareConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatHardwareConfig is an auto-generated flat version of HardwareConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatHardwareConfig struct { - CPUs *int32 `mapstructure:"CPUs" cty:"CPUs" hcl:"CPUs"` - CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores" hcl:"cpu_cores"` - CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation" hcl:"CPU_reservation"` - CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit" hcl:"CPU_limit"` - CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug" hcl:"CPU_hot_plug"` - RAM *int64 `mapstructure:"RAM" cty:"RAM" hcl:"RAM"` - RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation" hcl:"RAM_reservation"` - RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all" hcl:"RAM_reserve_all"` - MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug" hcl:"RAM_hot_plug"` - VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram" hcl:"video_ram"` - VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile" hcl:"vgpu_profile"` - NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV" hcl:"NestedHV"` - Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"` - ForceBIOSSetup *bool `mapstructure:"force_bios_setup" cty:"force_bios_setup" hcl:"force_bios_setup"` -} - -// FlatMapstructure returns a new FlatHardwareConfig. -// FlatHardwareConfig is an auto-generated flat version of HardwareConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*HardwareConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatHardwareConfig) -} - -// HCL2Spec returns the hcl spec of a HardwareConfig. -// This spec is used by HCL to read the fields of HardwareConfig. -// The decoded values from this spec will then be applied to a FlatHardwareConfig. -func (*FlatHardwareConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "CPUs": &hcldec.AttrSpec{Name: "CPUs", Type: cty.Number, Required: false}, - "cpu_cores": &hcldec.AttrSpec{Name: "cpu_cores", Type: cty.Number, Required: false}, - "CPU_reservation": &hcldec.AttrSpec{Name: "CPU_reservation", Type: cty.Number, Required: false}, - "CPU_limit": &hcldec.AttrSpec{Name: "CPU_limit", Type: cty.Number, Required: false}, - "CPU_hot_plug": &hcldec.AttrSpec{Name: "CPU_hot_plug", Type: cty.Bool, Required: false}, - "RAM": &hcldec.AttrSpec{Name: "RAM", Type: cty.Number, Required: false}, - "RAM_reservation": &hcldec.AttrSpec{Name: "RAM_reservation", Type: cty.Number, Required: false}, - "RAM_reserve_all": &hcldec.AttrSpec{Name: "RAM_reserve_all", Type: cty.Bool, Required: false}, - "RAM_hot_plug": &hcldec.AttrSpec{Name: "RAM_hot_plug", Type: cty.Bool, Required: false}, - "video_ram": &hcldec.AttrSpec{Name: "video_ram", Type: cty.Number, Required: false}, - "vgpu_profile": &hcldec.AttrSpec{Name: "vgpu_profile", Type: cty.String, Required: false}, - "NestedHV": &hcldec.AttrSpec{Name: "NestedHV", Type: cty.Bool, Required: false}, - "firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false}, - "force_bios_setup": &hcldec.AttrSpec{Name: "force_bios_setup", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_hardware_test.go b/builder/vsphere/common/step_hardware_test.go deleted file mode 100644 index 58b0e930a..000000000 --- a/builder/vsphere/common/step_hardware_test.go +++ /dev/null @@ -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, - } -} diff --git a/builder/vsphere/common/step_http_ip_discover.go b/builder/vsphere/common/step_http_ip_discover.go deleted file mode 100644 index 933cdbfe7..000000000 --- a/builder/vsphere/common/step_http_ip_discover.go +++ /dev/null @@ -1,68 +0,0 @@ -package common - -import ( - "context" - "fmt" - "net" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -// Step to discover the http ip -// which guests use to reach the vm host -// To make sure the IP is set before boot command and http server steps -type StepHTTPIPDiscover struct { - HTTPIP string - Network *net.IPNet -} - -func (s *StepHTTPIPDiscover) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ip, err := getHostIP(s.HTTPIP, s.Network) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - state.Put("http_ip", ip) - - return multistep.ActionContinue -} - -func (s *StepHTTPIPDiscover) Cleanup(state multistep.StateBag) {} - -func getHostIP(s string, network *net.IPNet) (string, error) { - if s != "" { - if net.ParseIP(s) != nil { - return s, nil - } else { - return "", fmt.Errorf("invalid IP address") - } - } - - addrs, err := net.InterfaceAddrs() - if err != nil { - return "", err - } - - // look for an IP that is contained in the ip_wait_address range - if network != nil { - for _, a := range addrs { - ipnet, ok := a.(*net.IPNet) - if ok && !ipnet.IP.IsLoopback() { - if network.Contains(ipnet.IP) { - return ipnet.IP.String(), nil - } - } - } - } - - // fallback to an ipv4 address if an IP is not found in the range - for _, a := range addrs { - ipnet, ok := a.(*net.IPNet) - if ok && !ipnet.IP.IsLoopback() { - if ipnet.IP.To4() != nil { - return ipnet.IP.String(), nil - } - } - } - return "", fmt.Errorf("IP not found") -} diff --git a/builder/vsphere/common/step_http_ip_discover_test.go b/builder/vsphere/common/step_http_ip_discover_test.go deleted file mode 100644 index f1ca79d3a..000000000 --- a/builder/vsphere/common/step_http_ip_discover_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/common/step_import_to_content_library.go b/builder/vsphere/common/step_import_to_content_library.go deleted file mode 100644 index 935fa750c..000000000 --- a/builder/vsphere/common/step_import_to_content_library.go +++ /dev/null @@ -1,180 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type ContentLibraryDestinationConfig -package common - -import ( - "context" - "fmt" - - "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/vmware/govmomi/vapi/vcenter" -) - -// With this configuration Packer creates a library item in a content library whose content is a VM template -// or an OVF template created from the just built VM. -// The template is stored in a existing or newly created library item. -type ContentLibraryDestinationConfig struct { - // Name of the library in which the new library item containing the template should be created/updated. - // The Content Library should be of type Local to allow deploying virtual machines. - Library string `mapstructure:"library"` - // Name of the library item that will be created or updated. - // For VM templates, the name of the item should be different from [vm_name](#vm_name) and - // the default is [vm_name](#vm_name) + timestamp when not set. VM templates will be always imported to a new library item. - // For OVF templates, the name defaults to [vm_name](#vm_name) when not set, and if an item with the same name already - // exists it will be then updated with the new OVF template, otherwise a new item will be created. - // - // ~> **Note**: It's not possible to update existing library items with a new VM template. If updating an existing library - // item is necessary, use an OVF template instead by setting the [ovf](#ovf) option as `true`. - // - Name string `mapstructure:"name"` - // Description of the library item that will be created. - // This option is not used when importing OVF templates. - // Defaults to "Packer imported [vm_name](#vm_name) VM template". - Description string `mapstructure:"description"` - // Cluster onto which the virtual machine template should be placed. - // If cluster and resource_pool are both specified, resource_pool must belong to cluster. - // If cluster and host are both specified, host must be a member of cluster. - // This option is not used when importing OVF templates. - // Defaults to [cluster](#cluster). - Cluster string `mapstructure:"cluster"` - // Virtual machine folder into which the virtual machine template should be placed. - // This option is not used when importing OVF templates. - // Defaults to the same folder as the source virtual machine. - Folder string `mapstructure:"folder"` - // Host onto which the virtual machine template should be placed. - // If host and resource_pool are both specified, resource_pool must belong to host. - // If host and cluster are both specified, host must be a member of cluster. - // This option is not used when importing OVF templates. - // Defaults to [host](#host). - Host string `mapstructure:"host"` - // Resource pool into which the virtual machine template should be placed. - // Defaults to [resource_pool](#resource_pool). if [resource_pool](#resource_pool) is also unset, - // the system will attempt to choose a suitable resource pool for the virtual machine template. - ResourcePool string `mapstructure:"resource_pool"` - // The datastore for the virtual machine template's configuration and log files. - // This option is not used when importing OVF templates. - // Defaults to the storage backing associated with the library specified by library. - Datastore string `mapstructure:"datastore"` - // If set to true, the VM will be destroyed after deploying the template to the Content Library. - // Defaults to `false`. - Destroy bool `mapstructure:"destroy"` - // When set to true, Packer will import and OVF template to the content library item. Defaults to `false`. - Ovf bool `mapstructure:"ovf"` -} - -func (c *ContentLibraryDestinationConfig) Prepare(lc *LocationConfig) []error { - var errs *packersdk.MultiError - - if c.Library == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("a library name must be provided")) - } - - if c.Ovf { - if c.Name == "" { - c.Name = lc.VMName - } - } else { - if c.Name == lc.VMName { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("the content library destination name must be different from the VM name")) - } - - if c.Name == "" { - // Add timestamp to the name to differentiate from the original VM - // otherwise vSphere won't be able to create the template which will be imported - name, err := interpolate.Render(lc.VMName+"{{timestamp}}", nil) - if err != nil { - errs = packersdk.MultiErrorAppend(errs, - fmt.Errorf("unable to parse content library VM template name: %s", err)) - } - c.Name = name - } - if c.Cluster == "" { - c.Cluster = lc.Cluster - } - if c.Host == "" { - c.Host = lc.Host - } - if c.ResourcePool == "" { - c.ResourcePool = lc.ResourcePool - } - if c.Description == "" { - c.Description = fmt.Sprintf("Packer imported %s VM template", lc.VMName) - } - } - - if errs != nil && len(errs.Errors) > 0 { - return errs.Errors - } - - return nil -} - -type StepImportToContentLibrary struct { - ContentLibConfig *ContentLibraryDestinationConfig -} - -func (s *StepImportToContentLibrary) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - var err error - - if s.ContentLibConfig.Ovf { - ui.Say(fmt.Sprintf("Importing VM OVF template %s to Content Library...", s.ContentLibConfig.Name)) - err = s.importOvfTemplate(vm) - } else { - ui.Say(fmt.Sprintf("Importing VM template %s to Content Library...", s.ContentLibConfig.Name)) - err = s.importVmTemplate(vm) - } - - if err != nil { - ui.Error(fmt.Sprintf("Failed to import template %s: %s", s.ContentLibConfig.Name, err.Error())) - state.Put("error", err) - return multistep.ActionHalt - } - - if s.ContentLibConfig.Destroy { - state.Put("destroy_vm", s.ContentLibConfig.Destroy) - } - - return multistep.ActionContinue -} - -func (s *StepImportToContentLibrary) importOvfTemplate(vm *driver.VirtualMachineDriver) error { - ovf := vcenter.OVF{ - Spec: vcenter.CreateSpec{ - Name: s.ContentLibConfig.Name, - }, - Target: vcenter.LibraryTarget{ - LibraryID: s.ContentLibConfig.Library, - }, - } - return vm.ImportOvfToContentLibrary(ovf) -} - -func (s *StepImportToContentLibrary) importVmTemplate(vm *driver.VirtualMachineDriver) error { - template := vcenter.Template{ - Name: s.ContentLibConfig.Name, - Description: s.ContentLibConfig.Description, - Library: s.ContentLibConfig.Library, - Placement: &vcenter.Placement{ - Cluster: s.ContentLibConfig.Cluster, - Folder: s.ContentLibConfig.Folder, - Host: s.ContentLibConfig.Host, - ResourcePool: s.ContentLibConfig.ResourcePool, - }, - } - - if s.ContentLibConfig.Datastore != "" { - template.VMHomeStorage = &vcenter.DiskStorage{ - Datastore: s.ContentLibConfig.Datastore, - } - } - - return vm.ImportToContentLibrary(template) -} - -func (s *StepImportToContentLibrary) Cleanup(multistep.StateBag) { -} diff --git a/builder/vsphere/common/step_import_to_content_library.hcl2spec.go b/builder/vsphere/common/step_import_to_content_library.hcl2spec.go deleted file mode 100644 index 2c42538fb..000000000 --- a/builder/vsphere/common/step_import_to_content_library.hcl2spec.go +++ /dev/null @@ -1,49 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type ContentLibraryDestinationConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatContentLibraryDestinationConfig is an auto-generated flat version of ContentLibraryDestinationConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatContentLibraryDestinationConfig struct { - Library *string `mapstructure:"library" cty:"library" hcl:"library"` - Name *string `mapstructure:"name" cty:"name" hcl:"name"` - Description *string `mapstructure:"description" cty:"description" hcl:"description"` - Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"` - Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"` - Host *string `mapstructure:"host" cty:"host" hcl:"host"` - ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"` - Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"` - Destroy *bool `mapstructure:"destroy" cty:"destroy" hcl:"destroy"` - Ovf *bool `mapstructure:"ovf" cty:"ovf" hcl:"ovf"` -} - -// FlatMapstructure returns a new FlatContentLibraryDestinationConfig. -// FlatContentLibraryDestinationConfig is an auto-generated flat version of ContentLibraryDestinationConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*ContentLibraryDestinationConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatContentLibraryDestinationConfig) -} - -// HCL2Spec returns the hcl spec of a ContentLibraryDestinationConfig. -// This spec is used by HCL to read the fields of ContentLibraryDestinationConfig. -// The decoded values from this spec will then be applied to a FlatContentLibraryDestinationConfig. -func (*FlatContentLibraryDestinationConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "library": &hcldec.AttrSpec{Name: "library", Type: cty.String, Required: false}, - "name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false}, - "description": &hcldec.AttrSpec{Name: "description", Type: cty.String, Required: false}, - "cluster": &hcldec.AttrSpec{Name: "cluster", Type: cty.String, Required: false}, - "folder": &hcldec.AttrSpec{Name: "folder", Type: cty.String, Required: false}, - "host": &hcldec.AttrSpec{Name: "host", Type: cty.String, Required: false}, - "resource_pool": &hcldec.AttrSpec{Name: "resource_pool", Type: cty.String, Required: false}, - "datastore": &hcldec.AttrSpec{Name: "datastore", Type: cty.String, Required: false}, - "destroy": &hcldec.AttrSpec{Name: "destroy", Type: cty.Bool, Required: false}, - "ovf": &hcldec.AttrSpec{Name: "ovf", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_remote_upload.go b/builder/vsphere/common/step_remote_upload.go deleted file mode 100644 index 92728f5c8..000000000 --- a/builder/vsphere/common/step_remote_upload.go +++ /dev/null @@ -1,117 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "path/filepath" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type StepRemoteUpload struct { - Datastore string - Host string - SetHostForDatastoreUploads bool - UploadedCustomCD bool -} - -func (s *StepRemoteUpload) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - d := state.Get("driver").(driver.Driver) - - if path, ok := state.GetOk("iso_path"); ok { - // user-supplied boot iso - fullRemotePath, err := s.uploadFile(path.(string), d, ui) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - state.Put("iso_remote_path", fullRemotePath) - } - if cdPath, ok := state.GetOk("cd_path"); ok { - // Packer-created cd_files disk - fullRemotePath, err := s.uploadFile(cdPath.(string), d, ui) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - s.UploadedCustomCD = true - state.Put("cd_path", fullRemotePath) - } - - return multistep.ActionContinue -} - -func GetRemoteDirectoryAndPath(path string, ds driver.Datastore) (string, string, string, string) { - filename := filepath.Base(path) - remotePath := fmt.Sprintf("packer_cache/%s", filename) - remoteDirectory := fmt.Sprintf("[%s] packer_cache/", ds.Name()) - fullRemotePath := fmt.Sprintf("%s/%s", remoteDirectory, filename) - - return filename, remotePath, remoteDirectory, fullRemotePath - -} -func (s *StepRemoteUpload) uploadFile(path string, d driver.Driver, ui packersdk.Ui) (string, error) { - ds, err := d.FindDatastore(s.Datastore, s.Host) - if err != nil { - return "", fmt.Errorf("datastore doesn't exist: %v", err) - } - - filename, remotePath, remoteDirectory, fullRemotePath := GetRemoteDirectoryAndPath(path, ds) - - if exists := ds.FileExists(remotePath); exists == true { - ui.Say(fmt.Sprintf("File %s already exists; skipping upload.", fullRemotePath)) - return fullRemotePath, nil - } - - ui.Say(fmt.Sprintf("Uploading %s to %s", filename, remotePath)) - - if exists := ds.DirExists(remotePath); exists == false { - log.Printf("Remote directory doesn't exist; creating...") - if err := ds.MakeDirectory(remoteDirectory); err != nil { - return "", err - } - } - - if err := ds.UploadFile(path, remotePath, s.Host, s.SetHostForDatastoreUploads); err != nil { - return "", err - } - return fullRemotePath, nil -} - -func (s *StepRemoteUpload) Cleanup(state multistep.StateBag) { - _, cancelled := state.GetOk(multistep.StateCancelled) - _, halted := state.GetOk(multistep.StateHalted) - if !cancelled && !halted { - return - } - - if !s.UploadedCustomCD { - return - } - - UploadedCDPath, ok := state.GetOk("cd_path") - if !ok { - return - } - - ui := state.Get("ui").(packersdk.Ui) - d := state.Get("driver").(*driver.VCenterDriver) - ui.Say("Deleting cd_files image from remote datastore ...") - - ds, err := d.FindDatastore(s.Datastore, s.Host) - if err != nil { - log.Printf("Error finding datastore to delete custom CD; please delete manually: %s", err) - return - } - - err = ds.Delete(UploadedCDPath.(string)) - if err != nil { - log.Printf("Error deleting custom CD from remote datastore; please delete manually: %s", err) - return - - } -} diff --git a/builder/vsphere/common/step_remote_upload_test.go b/builder/vsphere/common/step_remote_upload_test.go deleted file mode 100644 index dd9d8796f..000000000 --- a/builder/vsphere/common/step_remote_upload_test.go +++ /dev/null @@ -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") - } -} diff --git a/builder/vsphere/common/step_remove_cdrom.go b/builder/vsphere/common/step_remove_cdrom.go deleted file mode 100644 index 71d88c004..000000000 --- a/builder/vsphere/common/step_remove_cdrom.go +++ /dev/null @@ -1,46 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type RemoveCDRomConfig - -package common - -import ( - "context" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type RemoveCDRomConfig struct { - // Remove CD-ROM devices from template. Defaults to `false`. - RemoveCdrom bool `mapstructure:"remove_cdrom"` -} - -type StepRemoveCDRom struct { - Config *RemoveCDRomConfig -} - -func (s *StepRemoveCDRom) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(driver.VirtualMachine) - - ui.Say("Eject CD-ROM drives...") - err := vm.EjectCdroms() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - if s.Config.RemoveCdrom == true { - ui.Say("Deleting CD-ROM drives...") - err := vm.RemoveCdroms() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepRemoveCDRom) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_remove_cdrom.hcl2spec.go b/builder/vsphere/common/step_remove_cdrom.hcl2spec.go deleted file mode 100644 index 826cacdf4..000000000 --- a/builder/vsphere/common/step_remove_cdrom.hcl2spec.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type RemoveCDRomConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatRemoveCDRomConfig is an auto-generated flat version of RemoveCDRomConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatRemoveCDRomConfig struct { - RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom" hcl:"remove_cdrom"` -} - -// FlatMapstructure returns a new FlatRemoveCDRomConfig. -// FlatRemoveCDRomConfig is an auto-generated flat version of RemoveCDRomConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*RemoveCDRomConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatRemoveCDRomConfig) -} - -// HCL2Spec returns the hcl spec of a RemoveCDRomConfig. -// This spec is used by HCL to read the fields of RemoveCDRomConfig. -// The decoded values from this spec will then be applied to a FlatRemoveCDRomConfig. -func (*FlatRemoveCDRomConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "remove_cdrom": &hcldec.AttrSpec{Name: "remove_cdrom", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_remove_cdrom_test.go b/builder/vsphere/common/step_remove_cdrom_test.go deleted file mode 100644 index 0461256b2..000000000 --- a/builder/vsphere/common/step_remove_cdrom_test.go +++ /dev/null @@ -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) - } - }) - } -} diff --git a/builder/vsphere/common/step_remove_floppy.go b/builder/vsphere/common/step_remove_floppy.go deleted file mode 100644 index b48376bd0..000000000 --- a/builder/vsphere/common/step_remove_floppy.go +++ /dev/null @@ -1,49 +0,0 @@ -package common - -import ( - "context" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type StepRemoveFloppy struct { - Datastore string - Host string -} - -func (s *StepRemoveFloppy) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(driver.VirtualMachine) - d := state.Get("driver").(driver.Driver) - - ui.Say("Deleting Floppy drives...") - floppies, err := vm.FloppyDevices() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - if err = vm.RemoveDevice(true, floppies...); err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - if UploadedFloppyPath, ok := state.GetOk("uploaded_floppy_path"); ok { - ui.Say("Deleting Floppy image...") - ds, err := d.FindDatastore(s.Datastore, s.Host) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - if err := ds.Delete(UploadedFloppyPath.(string)); err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - state.Remove("uploaded_floppy_path") - } - - return multistep.ActionContinue -} - -func (s *StepRemoveFloppy) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_remove_floppy_test.go b/builder/vsphere/common/step_remove_floppy_test.go deleted file mode 100644 index bf1a578d1..000000000 --- a/builder/vsphere/common/step_remove_floppy_test.go +++ /dev/null @@ -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) - } - }) - } -} diff --git a/builder/vsphere/common/step_run.go b/builder/vsphere/common/step_run.go deleted file mode 100644 index 0f6bc0b56..000000000 --- a/builder/vsphere/common/step_run.go +++ /dev/null @@ -1,80 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type RunConfig - -package common - -import ( - "context" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type RunConfig struct { - // Priority of boot devices. Defaults to `disk,cdrom` - BootOrder string `mapstructure:"boot_order"` // example: "floppy,cdrom,ethernet,disk" -} - -type StepRun struct { - Config *RunConfig - SetOrder bool -} - -func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - if s.Config.BootOrder != "" { - ui.Say("Set boot order...") - order := strings.Split(s.Config.BootOrder, ",") - if err := vm.SetBootOrder(order); err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } else { - if s.SetOrder { - ui.Say("Set boot order temporary...") - if err := vm.SetBootOrder([]string{"disk", "cdrom"}); err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } - } - - ui.Say("Power on VM...") - err := vm.PowerOn() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *StepRun) Cleanup(state multistep.StateBag) { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - if s.Config.BootOrder == "" && s.SetOrder { - ui.Say("Clear boot order...") - if err := vm.SetBootOrder([]string{"-"}); err != nil { - state.Put("error", err) - return - } - } - - _, cancelled := state.GetOk(multistep.StateCancelled) - _, halted := state.GetOk(multistep.StateHalted) - if !cancelled && !halted { - return - } - - ui.Say("Power off VM...") - - err := vm.PowerOff() - if err != nil { - ui.Error(err.Error()) - } -} diff --git a/builder/vsphere/common/step_run.hcl2spec.go b/builder/vsphere/common/step_run.hcl2spec.go deleted file mode 100644 index 5ecc99cae..000000000 --- a/builder/vsphere/common/step_run.hcl2spec.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type RunConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatRunConfig is an auto-generated flat version of RunConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatRunConfig struct { - BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"` -} - -// FlatMapstructure returns a new FlatRunConfig. -// FlatRunConfig is an auto-generated flat version of RunConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*RunConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatRunConfig) -} - -// HCL2Spec returns the hcl spec of a RunConfig. -// This spec is used by HCL to read the fields of RunConfig. -// The decoded values from this spec will then be applied to a FlatRunConfig. -func (*FlatRunConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.String, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_shutdown.go b/builder/vsphere/common/step_shutdown.go deleted file mode 100644 index 685bf04c1..000000000 --- a/builder/vsphere/common/step_shutdown.go +++ /dev/null @@ -1,109 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type ShutdownConfig - -package common - -import ( - "bytes" - "context" - "fmt" - "log" - "time" - - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type ShutdownConfig struct { - // Specify a VM guest shutdown command. This command will be executed using - // the `communicator`. Otherwise the VMware guest tools are used to gracefully - // shutdown the VM guest. - Command string `mapstructure:"shutdown_command"` - // Amount of time to wait for graceful VM shutdown. - // Defaults to 5m or five minutes. - // This will likely need to be modified if the `communicator` is 'none'. - Timeout time.Duration `mapstructure:"shutdown_timeout"` - // Packer normally halts the virtual machine after all provisioners have - // run when no `shutdown_command` is defined. If this is set to `true`, Packer - // *will not* halt the virtual machine but will assume that you will send the stop - // signal yourself through a preseed.cfg, a script or the final provisioner. - // Packer will wait for a default of five minutes until the virtual machine is shutdown. - // The timeout can be changed using `shutdown_timeout` option. - DisableShutdown bool `mapstructure:"disable_shutdown"` -} - -func (c *ShutdownConfig) Prepare(comm communicator.Config) (warnings []string, errs []error) { - - if c.Timeout == 0 { - c.Timeout = 5 * time.Minute - } - - if comm.Type == "none" && c.Command != "" { - warnings = append(warnings, "The parameter `shutdown_command` is ignored as it requires a `communicator`.") - } - - return -} - -type StepShutdown struct { - Config *ShutdownConfig -} - -func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - if off, _ := vm.IsPoweredOff(); off { - // Probably power off initiated by last provisioner, though disable_shutdown is not set - ui.Say("VM is already powered off") - return multistep.ActionContinue - } - - comm, _ := state.Get("communicator").(packersdk.Communicator) - if comm == nil { - - msg := fmt.Sprintf("Please shutdown virtual machine within %s.", s.Config.Timeout) - ui.Message(msg) - - } else if s.Config.DisableShutdown { - ui.Say("Automatic shutdown disabled. Please shutdown virtual machine.") - } else if s.Config.Command != "" { - // Communicator is not needed unless shutdown_command is populated - - ui.Say("Executing shutdown command...") - log.Printf("Shutdown command: %s", s.Config.Command) - - var stdout, stderr bytes.Buffer - cmd := &packersdk.RemoteCmd{ - Command: s.Config.Command, - Stdout: &stdout, - Stderr: &stderr, - } - err := comm.Start(ctx, cmd) - if err != nil { - state.Put("error", fmt.Errorf("Failed to send shutdown command: %s", err)) - return multistep.ActionHalt - } - } else { - ui.Say("Shutting down VM...") - - err := vm.StartShutdown() - if err != nil { - state.Put("error", fmt.Errorf("Cannot shut down VM: %v", err)) - return multistep.ActionHalt - } - } - - log.Printf("Waiting max %s for shutdown to complete", s.Config.Timeout) - err := vm.WaitForShutdown(ctx, s.Config.Timeout) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *StepShutdown) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_shutdown.hcl2spec.go b/builder/vsphere/common/step_shutdown.hcl2spec.go deleted file mode 100644 index 323e771c8..000000000 --- a/builder/vsphere/common/step_shutdown.hcl2spec.go +++ /dev/null @@ -1,35 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type ShutdownConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatShutdownConfig is an auto-generated flat version of ShutdownConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatShutdownConfig struct { - Command *string `mapstructure:"shutdown_command" cty:"shutdown_command" hcl:"shutdown_command"` - Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout" hcl:"shutdown_timeout"` - DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown" hcl:"disable_shutdown"` -} - -// FlatMapstructure returns a new FlatShutdownConfig. -// FlatShutdownConfig is an auto-generated flat version of ShutdownConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*ShutdownConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatShutdownConfig) -} - -// HCL2Spec returns the hcl spec of a ShutdownConfig. -// This spec is used by HCL to read the fields of ShutdownConfig. -// The decoded values from this spec will then be applied to a FlatShutdownConfig. -func (*FlatShutdownConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false}, - "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false}, - "disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/step_snapshot.go b/builder/vsphere/common/step_snapshot.go deleted file mode 100644 index a83efe521..000000000 --- a/builder/vsphere/common/step_snapshot.go +++ /dev/null @@ -1,32 +0,0 @@ -package common - -import ( - "context" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type StepCreateSnapshot struct { - CreateSnapshot bool -} - -func (s *StepCreateSnapshot) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - if s.CreateSnapshot { - ui.Say("Creating snapshot...") - - err := vm.CreateSnapshot("Created by Packer") - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepCreateSnapshot) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_ssh_key_pair.go b/builder/vsphere/common/step_ssh_key_pair.go deleted file mode 100644 index d339175cb..000000000 --- a/builder/vsphere/common/step_ssh_key_pair.go +++ /dev/null @@ -1,115 +0,0 @@ -package common - -import ( - "context" - "fmt" - "io/ioutil" - "os" - - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/communicator/ssh" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/uuid" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -// StepSshKeyPair executes the business logic for setting the SSH key pair in -// the specified communicator.Config. -type StepSshKeyPair struct { - Debug bool - DebugKeyPath string - Comm *communicator.Config -} - -func (s *StepSshKeyPair) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - if s.Comm.Type != "ssh" || s.Comm.SSHPassword != "" { - return multistep.ActionContinue - } - - ui := state.Get("ui").(packersdk.Ui) - - comment := fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()) - if s.Comm.SSHPrivateKeyFile != "" { - ui.Say("Using existing SSH private key for the communicator...") - privateKeyBytes, err := s.Comm.ReadSSHPrivateKeyFile() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - kp, err := ssh.KeyPairFromPrivateKey(ssh.FromPrivateKeyConfig{ - RawPrivateKeyPemBlock: privateKeyBytes, - Comment: comment, - }) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - s.Comm.SSHPrivateKey = privateKeyBytes - s.Comm.SSHKeyPairName = kp.Comment - s.Comm.SSHTemporaryKeyPairName = kp.Comment - s.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine - - return multistep.ActionContinue - } - - if s.Comm.SSHAgentAuth { - ui.Say("Using local SSH Agent to authenticate connections for the communicator...") - return multistep.ActionContinue - } - - ui.Say("Creating ephemeral key pair for SSH communicator...") - - if s.Comm.SSHTemporaryKeyPairName != "" { - comment = s.Comm.SSHTemporaryKeyPairName - } - - kp, err := ssh.NewKeyPair(ssh.CreateKeyPairConfig{ - Comment: comment, - Type: ssh.Rsa, - }) - if err != nil { - state.Put("error", fmt.Errorf("Error creating temporary keypair: %s", err)) - return multistep.ActionHalt - } - - s.Comm.SSHKeyPairName = kp.Comment - s.Comm.SSHTemporaryKeyPairName = kp.Comment - s.Comm.SSHPrivateKey = kp.PrivateKeyPemBlock - s.Comm.SSHPublicKey = kp.PublicKeyAuthorizedKeysLine - s.Comm.SSHClearAuthorizedKeys = true - - vm := state.Get("vm").(*driver.VirtualMachineDriver) - err = vm.AddPublicKeys(ctx, string(s.Comm.SSHPublicKey)) - if err != nil { - state.Put("error", fmt.Errorf("error saving temporary keypair in the vm: %s", err)) - return multistep.ActionHalt - } - - ui.Say("Created ephemeral SSH key pair for communicator") - - // If we're in debug mode, output the private key to the working - // directory. - if s.Debug { - ui.Message(fmt.Sprintf("Saving communicator private key for debug purposes: %s", s.DebugKeyPath)) - // Write the key out - if err := ioutil.WriteFile(s.DebugKeyPath, kp.PrivateKeyPemBlock, 0600); err != nil { - state.Put("error", fmt.Errorf("Error saving debug key: %s", err)) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepSshKeyPair) Cleanup(state multistep.StateBag) { - if s.Debug { - if err := os.Remove(s.DebugKeyPath); err != nil { - ui := state.Get("ui").(packersdk.Ui) - ui.Error(fmt.Sprintf( - "Error removing debug key '%s': %s", s.DebugKeyPath, err)) - } - } -} diff --git a/builder/vsphere/common/step_template.go b/builder/vsphere/common/step_template.go deleted file mode 100644 index 535729909..000000000 --- a/builder/vsphere/common/step_template.go +++ /dev/null @@ -1,31 +0,0 @@ -package common - -import ( - "context" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type StepConvertToTemplate struct { - ConvertToTemplate bool -} - -func (s *StepConvertToTemplate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - if s.ConvertToTemplate { - ui.Say("Convert VM into template...") - err := vm.ConvertToTemplate() - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepConvertToTemplate) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_wait_for_ip.go b/builder/vsphere/common/step_wait_for_ip.go deleted file mode 100644 index 72a68e7a8..000000000 --- a/builder/vsphere/common/step_wait_for_ip.go +++ /dev/null @@ -1,182 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type WaitIpConfig - -package common - -import ( - "context" - "fmt" - "log" - "net" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/builder/vsphere/driver" -) - -type WaitIpConfig struct { - // Amount of time to wait for VM's IP, similar to 'ssh_timeout'. - // Defaults to 30m (30 minutes). See the Golang - // [ParseDuration](https://golang.org/pkg/time/#ParseDuration) documentation - // for full details. - WaitTimeout time.Duration `mapstructure:"ip_wait_timeout"` - // Amount of time to wait for VM's IP to settle down, sometimes VM may - // report incorrect IP initially, then its recommended to set that - // parameter to apx. 2 minutes. Examples 45s and 10m. Defaults to - // 5s(5 seconds). See the Golang - // [ParseDuration](https://golang.org/pkg/time/#ParseDuration) documentation - // for full details. - SettleTimeout time.Duration `mapstructure:"ip_settle_timeout"` - // Set this to a CIDR address to cause the service to wait for an address that is contained in - // this network range. Defaults to "0.0.0.0/0" for any ipv4 address. Examples include: - // - // * empty string ("") - remove all filters - // * `0:0:0:0:0:0:0:0/0` - allow only ipv6 addresses - // * `192.168.1.0/24` - only allow ipv4 addresses from 192.168.1.1 to 192.168.1.254 - WaitAddress *string `mapstructure:"ip_wait_address"` - ipnet *net.IPNet - - // WaitTimeout is a total timeout, so even if VM changes IP frequently and it doesn't settle down we will end waiting. -} - -type StepWaitForIp struct { - Config *WaitIpConfig -} - -func (c *WaitIpConfig) Prepare() []error { - var errs []error - - if c.SettleTimeout == 0 { - c.SettleTimeout = 5 * time.Second - } - if c.WaitTimeout == 0 { - c.WaitTimeout = 30 * time.Minute - } - if c.WaitAddress == nil { - addr := "0.0.0.0/0" - c.WaitAddress = &addr - } - - if *c.WaitAddress != "" { - var err error - _, c.ipnet, err = net.ParseCIDR(*c.WaitAddress) - if err != nil { - errs = append(errs, fmt.Errorf("unable to parse \"ip_wait_address\": %w", err)) - } - } - - return errs -} - -func (c *WaitIpConfig) GetIPNet() *net.IPNet { - return c.ipnet -} - -func (s *StepWaitForIp) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - vm := state.Get("vm").(*driver.VirtualMachineDriver) - - var ip string - var err error - - sub, cancel := context.WithCancel(ctx) - waitDone := make(chan bool, 1) - defer func() { - cancel() - }() - - go func() { - ui.Say("Waiting for IP...") - ip, err = doGetIp(vm, sub, s.Config) - waitDone <- true - }() - - log.Printf("[INFO] Waiting for IP, up to total timeout: %s, settle timeout: %s", s.Config.WaitTimeout, s.Config.SettleTimeout) - timeout := time.After(s.Config.WaitTimeout) - for { - select { - case <-timeout: - cancel() - <-waitDone - if ip != "" { - state.Put("ip", ip) - log.Printf("[WARN] API timeout waiting for IP but one IP was found. Using IP: %s", ip) - return multistep.ActionContinue - } - err := fmt.Errorf("Timeout waiting for IP.") - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - case <-ctx.Done(): - cancel() - log.Println("[WARN] Interrupt detected, quitting waiting for IP.") - return multistep.ActionHalt - case <-waitDone: - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - state.Put("ip", ip) - ui.Say(fmt.Sprintf("IP address: %v", ip)) - return multistep.ActionContinue - case <-time.After(1 * time.Second): - if _, ok := state.GetOk(multistep.StateCancelled); ok { - return multistep.ActionHalt - } - } - } -} - -func doGetIp(vm *driver.VirtualMachineDriver, ctx context.Context, c *WaitIpConfig) (string, error) { - var prevIp = "" - var stopTime time.Time - var interval time.Duration - if c.SettleTimeout.Seconds() >= 120 { - interval = 30 * time.Second - } else if c.SettleTimeout.Seconds() >= 60 { - interval = 15 * time.Second - } else if c.SettleTimeout.Seconds() >= 10 { - interval = 5 * time.Second - } else { - interval = 1 * time.Second - } -loop: - ip, err := vm.WaitForIP(ctx, c.ipnet) - if err != nil { - return "", err - } - - // Check for ctx cancellation to avoid printing any IP logs at the timeout - select { - case <-ctx.Done(): - return ip, fmt.Errorf("IP wait cancelled.") - default: - } - - if prevIp == "" || prevIp != ip { - if prevIp == "" { - log.Printf("VM IP aquired: %s", ip) - } else { - log.Printf("VM IP changed from %s to %s", prevIp, ip) - } - prevIp = ip - stopTime = time.Now().Add(c.SettleTimeout) - goto loop - } else { - log.Printf("VM IP is still the same: %s", prevIp) - if time.Now().After(stopTime) { - log.Printf("VM IP seems stable enough: %s", ip) - return ip, nil - } - select { - case <-ctx.Done(): - return "", fmt.Errorf("IP wait cancelled") - case <-time.After(interval): - goto loop - } - } - -} - -func (s *StepWaitForIp) Cleanup(state multistep.StateBag) {} diff --git a/builder/vsphere/common/step_wait_for_ip.hcl2spec.go b/builder/vsphere/common/step_wait_for_ip.hcl2spec.go deleted file mode 100644 index c65302f31..000000000 --- a/builder/vsphere/common/step_wait_for_ip.hcl2spec.go +++ /dev/null @@ -1,35 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type WaitIpConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatWaitIpConfig is an auto-generated flat version of WaitIpConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatWaitIpConfig struct { - WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"` - SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"` - WaitAddress *string `mapstructure:"ip_wait_address" cty:"ip_wait_address" hcl:"ip_wait_address"` -} - -// FlatMapstructure returns a new FlatWaitIpConfig. -// FlatWaitIpConfig is an auto-generated flat version of WaitIpConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*WaitIpConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatWaitIpConfig) -} - -// HCL2Spec returns the hcl spec of a WaitIpConfig. -// This spec is used by HCL to read the fields of WaitIpConfig. -// The decoded values from this spec will then be applied to a FlatWaitIpConfig. -func (*FlatWaitIpConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "ip_wait_timeout": &hcldec.AttrSpec{Name: "ip_wait_timeout", Type: cty.String, Required: false}, - "ip_settle_timeout": &hcldec.AttrSpec{Name: "ip_settle_timeout", Type: cty.String, Required: false}, - "ip_wait_address": &hcldec.AttrSpec{Name: "ip_wait_address", Type: cty.String, Required: false}, - } - return s -} diff --git a/builder/vsphere/common/storage_config.go b/builder/vsphere/common/storage_config.go deleted file mode 100644 index 6650616d5..000000000 --- a/builder/vsphere/common/storage_config.go +++ /dev/null @@ -1,118 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type StorageConfig,DiskConfig - -package common - -import ( - "fmt" -) - -// Defines the disk storage for a VM. -// -// Example that will create a 15GB and a 20GB disk on the VM. The second disk will be thin provisioned: -// -// In JSON: -// ```json -// "storage": [ -// { -// "disk_size": 15000 -// }, -// { -// "disk_size": 20000, -// "disk_thin_provisioned": true -// } -// ], -// ``` -// In HCL2: -// ```hcl -// storage { -// disk_size = 15000 -// } -// storage { -// disk_size = 20000 -// disk_thin_provisioned = true -// } -// ``` -// -// Example that creates 2 pvscsi controllers and adds 2 disks to each one: -// -// In JSON: -// ```json -// "disk_controller_type": ["pvscsi", "pvscsi"], -// "storage": [ -// { -// "disk_size": 15000, -// "disk_controller_index": 0 -// }, -// { -// "disk_size": 15000, -// "disk_controller_index": 0 -// }, -// { -// "disk_size": 15000, -// "disk_controller_index": 1 -// }, -// { -// "disk_size": 15000, -// "disk_controller_index": 1 -// } -// ], -// ``` -// -// In HCL2: -// ```hcl -// disk_controller_type = ["pvscsi", "pvscsi"] -// storage { -// disk_size = 15000, -// disk_controller_index = 0 -// } -// storage { -// disk_size = 15000 -// disk_controller_index = 0 -// } -// storage { -// disk_size = 15000 -// disk_controller_index = 1 -// } -// storage { -// disk_size = 15000 -// disk_controller_index = 1 -// } -// ``` -type DiskConfig struct { - // The size of the disk in MB. - DiskSize int64 `mapstructure:"disk_size" required:"true"` - // Enable VMDK thin provisioning for VM. Defaults to `false`. - DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"` - // Enable VMDK eager scrubbing for VM. Defaults to `false`. - DiskEagerlyScrub bool `mapstructure:"disk_eagerly_scrub"` - // The assigned disk controller. Defaults to the first one (0) - DiskControllerIndex int `mapstructure:"disk_controller_index"` -} - -type StorageConfig struct { - // Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers. - // Defaults to `lsilogic`. See - // [SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362) - // for additional details. - DiskControllerType []string `mapstructure:"disk_controller_type"` - // Configures a collection of one or more disks to be provisioned along with the VM. See the [Storage Configuration](#storage-configuration). - Storage []DiskConfig `mapstructure:"storage"` -} - -func (c *StorageConfig) Prepare() []error { - var errs []error - - if len(c.Storage) > 0 { - for i, storage := range c.Storage { - if storage.DiskSize == 0 { - errs = append(errs, fmt.Errorf("storage[%d].'disk_size' is required", i)) - } - if storage.DiskControllerIndex >= len(c.DiskControllerType) { - errs = append(errs, fmt.Errorf("storage[%d].'disk_controller_index' references an unknown disk controller", i)) - } - } - } - - return errs -} diff --git a/builder/vsphere/common/storage_config.hcl2spec.go b/builder/vsphere/common/storage_config.hcl2spec.go deleted file mode 100644 index 1d8fbd8c5..000000000 --- a/builder/vsphere/common/storage_config.hcl2spec.go +++ /dev/null @@ -1,62 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type StorageConfig,DiskConfig"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatDiskConfig is an auto-generated flat version of DiskConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatDiskConfig struct { - DiskSize *int64 `mapstructure:"disk_size" required:"true" cty:"disk_size" hcl:"disk_size"` - DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned" hcl:"disk_thin_provisioned"` - DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub" hcl:"disk_eagerly_scrub"` - DiskControllerIndex *int `mapstructure:"disk_controller_index" cty:"disk_controller_index" hcl:"disk_controller_index"` -} - -// FlatMapstructure returns a new FlatDiskConfig. -// FlatDiskConfig is an auto-generated flat version of DiskConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*DiskConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatDiskConfig) -} - -// HCL2Spec returns the hcl spec of a DiskConfig. -// This spec is used by HCL to read the fields of DiskConfig. -// The decoded values from this spec will then be applied to a FlatDiskConfig. -func (*FlatDiskConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false}, - "disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false}, - "disk_eagerly_scrub": &hcldec.AttrSpec{Name: "disk_eagerly_scrub", Type: cty.Bool, Required: false}, - "disk_controller_index": &hcldec.AttrSpec{Name: "disk_controller_index", Type: cty.Number, Required: false}, - } - return s -} - -// FlatStorageConfig is an auto-generated flat version of StorageConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatStorageConfig struct { - DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"` - Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"` -} - -// FlatMapstructure returns a new FlatStorageConfig. -// FlatStorageConfig is an auto-generated flat version of StorageConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*StorageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatStorageConfig) -} - -// HCL2Spec returns the hcl spec of a StorageConfig. -// This spec is used by HCL to read the fields of StorageConfig. -// The decoded values from this spec will then be applied to a FlatStorageConfig. -func (*FlatStorageConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false}, - "storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*FlatDiskConfig)(nil).HCL2Spec())}, - } - return s -} diff --git a/builder/vsphere/common/testing/utility.go b/builder/vsphere/common/testing/utility.go deleted file mode 100644 index 72bc8c3f5..000000000 --- a/builder/vsphere/common/testing/utility.go +++ /dev/null @@ -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 -} diff --git a/builder/vsphere/driver/cluster.go b/builder/vsphere/driver/cluster.go deleted file mode 100644 index d17031b82..000000000 --- a/builder/vsphere/driver/cluster.go +++ /dev/null @@ -1,19 +0,0 @@ -package driver - -import "github.com/vmware/govmomi/object" - -type Cluster struct { - driver *VCenterDriver - cluster *object.ClusterComputeResource -} - -func (d *VCenterDriver) FindCluster(name string) (*Cluster, error) { - c, err := d.finder.ClusterComputeResource(d.ctx, name) - if err != nil { - return nil, err - } - return &Cluster{ - cluster: c, - driver: d, - }, nil -} diff --git a/builder/vsphere/driver/datastore.go b/builder/vsphere/driver/datastore.go deleted file mode 100644 index ae371b79f..000000000 --- a/builder/vsphere/driver/datastore.go +++ /dev/null @@ -1,235 +0,0 @@ -package driver - -import ( - "fmt" - "path" - "regexp" - "strings" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/property" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/soap" - "github.com/vmware/govmomi/vim25/types" -) - -type Datastore interface { - Info(params ...string) (*mo.Datastore, error) - FileExists(path string) bool - DirExists(path string) bool - Name() string - ResolvePath(path string) string - UploadFile(src, dst, host string, setHost bool) error - Delete(path string) error - MakeDirectory(path string) error - Reference() types.ManagedObjectReference -} - -type DatastoreDriver struct { - ds *object.Datastore - driver *VCenterDriver -} - -func (d *VCenterDriver) NewDatastore(ref *types.ManagedObjectReference) Datastore { - return &DatastoreDriver{ - ds: object.NewDatastore(d.client.Client, *ref), - driver: d, - } -} - -// If name is an empty string, then resolve host's one -func (d *VCenterDriver) FindDatastore(name string, host string) (Datastore, error) { - if name == "" { - h, err := d.FindHost(host) - if err != nil { - return nil, fmt.Errorf("Error finding host for to get datastore: %s", err) - } - - i, err := h.Info("datastore") - if err != nil { - return nil, fmt.Errorf("Error getting datastore info from host: %s", err) - } - - if len(i.Datastore) > 1 { - return nil, fmt.Errorf("Host has multiple datastores. Specify it explicitly") - } - - ds := d.NewDatastore(&i.Datastore[0]) - inf, err := ds.Info("name") - if err != nil { - return nil, fmt.Errorf("Error getting datastore name: %s", err) - } - name = inf.Name - } - - ds, err := d.finder.Datastore(d.ctx, name) - if err != nil { - return nil, fmt.Errorf("Error finding datastore with name %s: %s", name, err) - } - - return &DatastoreDriver{ - ds: ds, - driver: d, - }, nil -} - -func (d *VCenterDriver) GetDatastoreName(id string) (string, error) { - obj := types.ManagedObjectReference{ - Type: "Datastore", - Value: id, - } - pc := property.DefaultCollector(d.vimClient) - var me mo.ManagedEntity - - err := pc.RetrieveOne(d.ctx, obj, []string{"name"}, &me) - if err != nil { - return id, err - } - return me.Name, nil -} - -func (ds *DatastoreDriver) Info(params ...string) (*mo.Datastore, error) { - var p []string - if len(params) == 0 { - p = []string{"*"} - } else { - p = params - } - var info mo.Datastore - err := ds.ds.Properties(ds.driver.ctx, ds.ds.Reference(), p, &info) - if err != nil { - return nil, err - } - return &info, nil -} - -func (ds *DatastoreDriver) DirExists(filepath string) bool { - _, err := ds.ds.Stat(ds.driver.ctx, filepath) - if _, ok := err.(object.DatastoreNoSuchDirectoryError); ok { - return false - } - return true -} - -func (ds *DatastoreDriver) FileExists(path string) bool { - _, err := ds.ds.Stat(ds.driver.ctx, path) - return err == nil -} - -func (ds *DatastoreDriver) Name() string { - return ds.ds.Name() -} - -func (ds *DatastoreDriver) Reference() types.ManagedObjectReference { - return ds.ds.Reference() -} - -func (ds *DatastoreDriver) ResolvePath(path string) string { - return ds.ds.Path(path) -} - -// The file ID isn't available via the API, so we use DatastoreBrowser to search -func (d *VCenterDriver) GetDatastoreFilePath(datastoreID, dir, filename string) (string, error) { - ref := types.ManagedObjectReference{Type: "Datastore", Value: datastoreID} - ds := object.NewDatastore(d.vimClient, ref) - - b, err := ds.Browser(d.ctx) - if err != nil { - return filename, err - } - ext := path.Ext(filename) - pat := strings.Replace(filename, ext, "*"+ext, 1) - spec := types.HostDatastoreBrowserSearchSpec{ - MatchPattern: []string{pat}, - } - - task, err := b.SearchDatastore(d.ctx, dir, &spec) - if err != nil { - return filename, err - } - - info, err := task.WaitForResult(d.ctx, nil) - if err != nil { - return filename, err - } - - res, ok := info.Result.(types.HostDatastoreBrowserSearchResults) - if !ok { - return filename, fmt.Errorf("search(%s) result type=%T", pat, info.Result) - } - - if len(res.File) != 1 { - return filename, fmt.Errorf("search(%s) result files=%d", pat, len(res.File)) - } - return res.File[0].GetFileInfo().Path, nil -} - -func (ds *DatastoreDriver) UploadFile(src, dst, host string, setHost bool) error { - p := soap.DefaultUpload - ctx := ds.driver.ctx - - if setHost && host != "" { - h, err := ds.driver.FindHost(host) - if err != nil { - return err - } - ctx = ds.ds.HostContext(ctx, h.host) - } - - return ds.ds.UploadFile(ctx, src, dst, &p) -} - -func (ds *DatastoreDriver) Delete(path string) error { - dc, err := ds.driver.finder.Datacenter(ds.driver.ctx, ds.ds.DatacenterPath) - if err != nil { - return err - } - fm := ds.ds.NewFileManager(dc, false) - return fm.Delete(ds.driver.ctx, path) -} - -func (ds *DatastoreDriver) MakeDirectory(path string) error { - dc, err := ds.driver.finder.Datacenter(ds.driver.ctx, ds.ds.DatacenterPath) - if err != nil { - return err - } - fm := ds.ds.NewFileManager(dc, false) - return fm.FileManager.MakeDirectory(ds.driver.ctx, path, dc, true) -} - -// Cuts out the datastore prefix -// Example: "[datastore1] file.ext" --> "file.ext" -func RemoveDatastorePrefix(path string) string { - res := object.DatastorePath{} - if hadPrefix := res.FromString(path); hadPrefix { - return res.Path - } else { - return path - } -} - -type DatastoreIsoPath struct { - path string -} - -func (d *DatastoreIsoPath) Validate() bool { - // Matches: - // [datastore] /dir/subdir/file - // [datastore] dir/subdir/file - // [] /dir/subdir/file - // [data-store] /dir/subdir/file - // dir/subdir/file or dir/subdir/file - matched, _ := regexp.MatchString(`^\s*(\[[^\[\]\/]*\])?\s*[^\[\]]+\s*$`, d.path) - return matched -} - -func (d *DatastoreIsoPath) GetFilePath() string { - filePath := d.path - parts := strings.Split(d.path, "]") - if len(parts) > 1 { - // removes datastore name from path - filePath = parts[1] - filePath = strings.TrimSpace(filePath) - } - return filePath -} diff --git a/builder/vsphere/driver/datastore_acc_test.go b/builder/vsphere/driver/datastore_acc_test.go deleted file mode 100644 index 45cc4e76e..000000000 --- a/builder/vsphere/driver/datastore_acc_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/driver/datastore_mock.go b/builder/vsphere/driver/datastore_mock.go deleted file mode 100644 index 9330d9227..000000000 --- a/builder/vsphere/driver/datastore_mock.go +++ /dev/null @@ -1,81 +0,0 @@ -package driver - -import ( - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" -) - -type DatastoreMock struct { - FileExistsCalled bool - FileExistsReturn bool - - DirExistsCalled bool - DirExistsReturn bool - - NameReturn string - - MakeDirectoryCalled bool - - ResolvePathCalled bool - ResolvePathReturn string - - DeleteCalled bool - DeletePath string - DeleteErr error - - UploadFileCalled bool - UploadFileSrc string - UploadFileDst string - UploadFileHost string - UploadFileSetHost bool - UploadFileErr error -} - -func (ds *DatastoreMock) Info(params ...string) (*mo.Datastore, error) { - return nil, nil -} - -func (ds *DatastoreMock) FileExists(path string) bool { - ds.FileExistsCalled = true - return ds.FileExistsReturn -} - -func (ds *DatastoreMock) DirExists(path string) bool { - ds.DirExistsCalled = true - return ds.DirExistsReturn -} -func (ds *DatastoreMock) Name() string { - if ds.NameReturn == "" { - return "datastore-mock" - } - return ds.NameReturn -} - -func (ds *DatastoreMock) Reference() types.ManagedObjectReference { - return types.ManagedObjectReference{} -} - -func (ds *DatastoreMock) ResolvePath(path string) string { - ds.ResolvePathCalled = true - return ds.ResolvePathReturn -} - -func (ds *DatastoreMock) UploadFile(src, dst, host string, setHost bool) error { - ds.UploadFileCalled = true - ds.UploadFileSrc = src - ds.UploadFileDst = dst - ds.UploadFileHost = host - ds.UploadFileSetHost = setHost - return ds.UploadFileErr -} - -func (ds *DatastoreMock) Delete(path string) error { - ds.DeleteCalled = true - ds.DeletePath = path - return ds.DeleteErr -} - -func (ds *DatastoreMock) MakeDirectory(path string) error { - ds.MakeDirectoryCalled = true - return nil -} diff --git a/builder/vsphere/driver/datastore_test.go b/builder/vsphere/driver/datastore_test.go deleted file mode 100644 index d2b296d92..000000000 --- a/builder/vsphere/driver/datastore_test.go +++ /dev/null @@ -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()) - } -} diff --git a/builder/vsphere/driver/disk.go b/builder/vsphere/driver/disk.go deleted file mode 100644 index a51201992..000000000 --- a/builder/vsphere/driver/disk.go +++ /dev/null @@ -1,85 +0,0 @@ -package driver - -import ( - "errors" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/types" -) - -type Disk struct { - DiskSize int64 - DiskEagerlyScrub bool - DiskThinProvisioned bool - ControllerIndex int -} - -type StorageConfig struct { - DiskControllerType []string // example: "scsi", "pvscsi", "nvme", "lsilogic" - Storage []Disk -} - -func (c *StorageConfig) AddStorageDevices(existingDevices object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) { - newDevices := object.VirtualDeviceList{} - - // Create new controller based on existing devices list and add it to the new devices list - // to confirm creation - var controllers []types.BaseVirtualController - for _, controllerType := range c.DiskControllerType { - var device types.BaseVirtualDevice - var err error - if controllerType == "nvme" { - device, err = existingDevices.CreateNVMEController() - } else { - device, err = existingDevices.CreateSCSIController(controllerType) - } - if err != nil { - return nil, err - } - existingDevices = append(existingDevices, device) - newDevices = append(newDevices, device) - controller, err := existingDevices.FindDiskController(existingDevices.Name(device)) - if err != nil { - return nil, err - } - controllers = append(controllers, controller) - } - - for _, dc := range c.Storage { - disk := &types.VirtualDisk{ - VirtualDevice: types.VirtualDevice{ - Key: existingDevices.NewKey(), - Backing: &types.VirtualDiskFlatVer2BackingInfo{ - DiskMode: string(types.VirtualDiskModePersistent), - ThinProvisioned: types.NewBool(dc.DiskThinProvisioned), - EagerlyScrub: types.NewBool(dc.DiskEagerlyScrub), - }, - }, - CapacityInKB: dc.DiskSize * 1024, - } - - existingDevices.AssignController(disk, controllers[dc.ControllerIndex]) - existingDevices = append(existingDevices, disk) - newDevices = append(newDevices, disk) - } - - return newDevices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd) -} - -func findDisk(devices object.VirtualDeviceList) (*types.VirtualDisk, error) { - var disks []*types.VirtualDisk - for _, device := range devices { - switch d := device.(type) { - case *types.VirtualDisk: - disks = append(disks, d) - } - } - - switch len(disks) { - case 0: - return nil, errors.New("VM has no disks") - case 1: - return disks[0], nil - } - return nil, errors.New("VM has multiple disks") -} diff --git a/builder/vsphere/driver/disk_test.go b/builder/vsphere/driver/disk_test.go deleted file mode 100644 index 174e008ba..000000000 --- a/builder/vsphere/driver/disk_test.go +++ /dev/null @@ -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)) - } -} diff --git a/builder/vsphere/driver/driver.go b/builder/vsphere/driver/driver.go deleted file mode 100644 index 8fbab96e5..000000000 --- a/builder/vsphere/driver/driver.go +++ /dev/null @@ -1,129 +0,0 @@ -package driver - -import ( - "context" - "fmt" - "net/url" - "time" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/vmware/govmomi" - "github.com/vmware/govmomi/find" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/session" - "github.com/vmware/govmomi/vapi/library" - "github.com/vmware/govmomi/vapi/rest" - "github.com/vmware/govmomi/vim25" - "github.com/vmware/govmomi/vim25/soap" - "github.com/vmware/govmomi/vim25/types" -) - -type Driver interface { - NewVM(ref *types.ManagedObjectReference) VirtualMachine - FindVM(name string) (VirtualMachine, error) - FindCluster(name string) (*Cluster, error) - PreCleanVM(ui packersdk.Ui, vmPath string, force bool) error - CreateVM(config *CreateConfig) (VirtualMachine, error) - - NewDatastore(ref *types.ManagedObjectReference) Datastore - FindDatastore(name string, host string) (Datastore, error) - GetDatastoreName(id string) (string, error) - GetDatastoreFilePath(datastoreID, dir, filename string) (string, error) - - NewFolder(ref *types.ManagedObjectReference) *Folder - FindFolder(name string) (*Folder, error) - NewHost(ref *types.ManagedObjectReference) *Host - FindHost(name string) (*Host, error) - NewNetwork(ref *types.ManagedObjectReference) *Network - FindNetwork(name string) (*Network, error) - FindNetworks(name string) ([]*Network, error) - NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool - FindResourcePool(cluster string, host string, name string) (*ResourcePool, error) - - FindContentLibraryByName(name string) (*Library, error) - FindContentLibraryItem(libraryId string, name string) (*library.Item, error) - FindContentLibraryFileDatastorePath(isoPath string) (string, error) -} - -type VCenterDriver struct { - // context that controls the authenticated sessions used to run the VM commands - ctx context.Context - client *govmomi.Client - vimClient *vim25.Client - restClient *RestClient - finder *find.Finder - datacenter *object.Datacenter -} - -type ConnectConfig struct { - VCenterServer string - Username string - Password string - InsecureConnection bool - Datacenter string -} - -func NewDriver(config *ConnectConfig) (Driver, error) { - ctx := context.TODO() - - vcenterUrl, err := url.Parse(fmt.Sprintf("https://%v/sdk", config.VCenterServer)) - if err != nil { - return nil, err - } - credentials := url.UserPassword(config.Username, config.Password) - vcenterUrl.User = credentials - - soapClient := soap.NewClient(vcenterUrl, config.InsecureConnection) - 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, credentials) - if err != nil { - return nil, err - } - - finder := find.NewFinder(client.Client, false) - datacenter, err := finder.DatacenterOrDefault(ctx, config.Datacenter) - if err != nil { - return nil, err - } - finder.SetDatacenter(datacenter) - - d := &VCenterDriver{ - ctx: ctx, - client: client, - vimClient: vimClient, - restClient: &RestClient{ - client: rest.NewClient(vimClient), - credentials: credentials, - }, - datacenter: datacenter, - finder: finder, - } - return d, nil -} - -// The rest.Client requires vCenter. -// RestClient is to modularize the rest.Client session and use it only when is necessary. -// This will allow users without vCenter to use the other features that doesn't use the rest.Client. -// To use the client login/logout must be done to create an authenticated session. -type RestClient struct { - client *rest.Client - credentials *url.Userinfo -} - -func (r *RestClient) Login(ctx context.Context) error { - return r.client.Login(ctx, r.credentials) -} - -func (r *RestClient) Logout(ctx context.Context) error { - return r.client.Logout(ctx) -} diff --git a/builder/vsphere/driver/driver_mock.go b/builder/vsphere/driver/driver_mock.go deleted file mode 100644 index 03fa736fb..000000000 --- a/builder/vsphere/driver/driver_mock.go +++ /dev/null @@ -1,119 +0,0 @@ -package driver - -import ( - "fmt" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/vmware/govmomi/vapi/library" - "github.com/vmware/govmomi/vim25/types" -) - -type DriverMock struct { - FindDatastoreCalled bool - DatastoreMock *DatastoreMock - FindDatastoreName string - FindDatastoreHost string - FindDatastoreErr error - - PreCleanShouldFail bool - PreCleanVMCalled bool - PreCleanForce bool - PreCleanVMPath string - - CreateVMShouldFail bool - CreateVMCalled bool - CreateConfig *CreateConfig - VM VirtualMachine - - FindVMCalled bool - FindVMName string -} - -func NewDriverMock() *DriverMock { - return new(DriverMock) -} - -func (d *DriverMock) FindDatastore(name string, host string) (Datastore, error) { - d.FindDatastoreCalled = true - if d.DatastoreMock == nil { - d.DatastoreMock = new(DatastoreMock) - } - d.FindDatastoreName = name - d.FindDatastoreHost = host - return d.DatastoreMock, d.FindDatastoreErr -} - -func (d *DriverMock) NewVM(ref *types.ManagedObjectReference) VirtualMachine { - return nil -} - -func (d *DriverMock) FindVM(name string) (VirtualMachine, error) { - d.FindVMCalled = true - if d.VM == nil { - d.VM = new(VirtualMachineMock) - } - d.FindVMName = name - return d.VM, d.FindDatastoreErr -} - -func (d *DriverMock) FindCluster(name string) (*Cluster, error) { - return nil, nil -} - -func (d *DriverMock) PreCleanVM(ui packersdk.Ui, vmPath string, force bool) error { - d.PreCleanVMCalled = true - if d.PreCleanShouldFail { - return fmt.Errorf("pre clean failed") - } - d.PreCleanForce = true - d.PreCleanVMPath = vmPath - return nil -} - -func (d *DriverMock) CreateVM(config *CreateConfig) (VirtualMachine, error) { - d.CreateVMCalled = true - if d.CreateVMShouldFail { - return nil, fmt.Errorf("create vm failed") - } - d.CreateConfig = config - d.VM = new(VirtualMachineDriver) - return d.VM, nil -} - -func (d *DriverMock) NewDatastore(ref *types.ManagedObjectReference) Datastore { return nil } - -func (d *DriverMock) GetDatastoreName(id string) (string, error) { return "", nil } - -func (d *DriverMock) GetDatastoreFilePath(datastoreID, dir, filename string) (string, error) { - return "", nil -} - -func (d *DriverMock) NewFolder(ref *types.ManagedObjectReference) *Folder { return nil } - -func (d *DriverMock) FindFolder(name string) (*Folder, error) { return nil, nil } - -func (d *DriverMock) NewHost(ref *types.ManagedObjectReference) *Host { return nil } - -func (d *DriverMock) FindHost(name string) (*Host, error) { return nil, nil } - -func (d *DriverMock) NewNetwork(ref *types.ManagedObjectReference) *Network { return nil } - -func (d *DriverMock) FindNetwork(name string) (*Network, error) { return nil, nil } - -func (d *DriverMock) FindNetworks(name string) ([]*Network, error) { return nil, nil } - -func (d *DriverMock) NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool { return nil } - -func (d *DriverMock) FindResourcePool(cluster string, host string, name string) (*ResourcePool, error) { - return nil, nil -} - -func (d *DriverMock) FindContentLibraryByName(name string) (*Library, error) { return nil, nil } - -func (d *DriverMock) FindContentLibraryItem(libraryId string, name string) (*library.Item, error) { - return nil, nil -} - -func (d *DriverMock) FindContentLibraryFileDatastorePath(isoPath string) (string, error) { - return "", nil -} diff --git a/builder/vsphere/driver/driver_test.go b/builder/vsphere/driver/driver_test.go deleted file mode 100644 index 534755858..000000000 --- a/builder/vsphere/driver/driver_test.go +++ /dev/null @@ -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 -} diff --git a/builder/vsphere/driver/folder.go b/builder/vsphere/driver/folder.go deleted file mode 100644 index 75e07e594..000000000 --- a/builder/vsphere/driver/folder.go +++ /dev/null @@ -1,93 +0,0 @@ -package driver - -import ( - "fmt" - "path" - "strings" - - "github.com/vmware/govmomi/find" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" -) - -type Folder struct { - driver *VCenterDriver - folder *object.Folder -} - -func (d *VCenterDriver) NewFolder(ref *types.ManagedObjectReference) *Folder { - return &Folder{ - folder: object.NewFolder(d.client.Client, *ref), - driver: d, - } -} - -func (d *VCenterDriver) FindFolder(name string) (*Folder, error) { - if name != "" { - // create folders if they don't exist - parent := "" - parentFolder, err := d.finder.Folder(d.ctx, path.Join(d.datacenter.InventoryPath, "vm")) - if err != nil { - return nil, err - } - folders := strings.Split(name, "/") - for _, folder := range folders { - parent = path.Join(parent, folder) - f, err := d.finder.Folder(d.ctx, path.Join(d.datacenter.InventoryPath, "vm", parent)) - if _, ok := err.(*find.NotFoundError); ok { - f, err = parentFolder.CreateFolder(d.ctx, folder) - } - if err != nil { - return nil, err - } - parentFolder = f - } - } - - f, err := d.finder.Folder(d.ctx, path.Join(d.datacenter.InventoryPath, "vm", name)) - if err != nil { - return nil, err - } - - return &Folder{ - folder: f, - driver: d, - }, nil -} - -func (f *Folder) Info(params ...string) (*mo.Folder, error) { - var p []string - if len(params) == 0 { - p = []string{"*"} - } else { - p = params - } - var info mo.Folder - err := f.folder.Properties(f.driver.ctx, f.folder.Reference(), p, &info) - if err != nil { - return nil, err - } - return &info, nil -} - -func (f *Folder) Path() (string, error) { - info, err := f.Info("name", "parent") - if err != nil { - return "", err - } - if info.Parent.Type == "Datacenter" { - return "", nil - } else { - parent := f.driver.NewFolder(info.Parent) - path, err := parent.Path() - if err != nil { - return "", err - } - if path == "" { - return info.Name, nil - } else { - return fmt.Sprintf("%v/%v", path, info.Name), nil - } - } -} diff --git a/builder/vsphere/driver/folder_acc_test.go b/builder/vsphere/driver/folder_acc_test.go deleted file mode 100644 index 7f3b527b6..000000000 --- a/builder/vsphere/driver/folder_acc_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/driver/host.go b/builder/vsphere/driver/host.go deleted file mode 100644 index 31c193589..000000000 --- a/builder/vsphere/driver/host.go +++ /dev/null @@ -1,45 +0,0 @@ -package driver - -import ( - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" -) - -type Host struct { - driver *VCenterDriver - host *object.HostSystem -} - -func (d *VCenterDriver) NewHost(ref *types.ManagedObjectReference) *Host { - return &Host{ - host: object.NewHostSystem(d.client.Client, *ref), - driver: d, - } -} - -func (d *VCenterDriver) FindHost(name string) (*Host, error) { - h, err := d.finder.HostSystem(d.ctx, name) - if err != nil { - return nil, err - } - return &Host{ - host: h, - driver: d, - }, nil -} - -func (h *Host) Info(params ...string) (*mo.HostSystem, error) { - var p []string - if len(params) == 0 { - p = []string{"*"} - } else { - p = params - } - var info mo.HostSystem - err := h.host.Properties(h.driver.ctx, h.host.Reference(), p, &info) - if err != nil { - return nil, err - } - return &info, nil -} diff --git a/builder/vsphere/driver/host_acc_test.go b/builder/vsphere/driver/host_acc_test.go deleted file mode 100644 index faee0fdaa..000000000 --- a/builder/vsphere/driver/host_acc_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/driver/library.go b/builder/vsphere/driver/library.go deleted file mode 100644 index 25d7d6880..000000000 --- a/builder/vsphere/driver/library.go +++ /dev/null @@ -1,113 +0,0 @@ -package driver - -import ( - "fmt" - "log" - "path" - "strings" - - "github.com/vmware/govmomi/vapi/library" -) - -type Library struct { - driver *VCenterDriver - library *library.Library -} - -func (d *VCenterDriver) FindContentLibraryByName(name string) (*Library, error) { - lm := library.NewManager(d.restClient.client) - l, err := lm.GetLibraryByName(d.ctx, name) - if err != nil { - return nil, err - } - return &Library{ - library: l, - driver: d, - }, nil -} - -func (d *VCenterDriver) FindContentLibraryItem(libraryId string, name string) (*library.Item, error) { - lm := library.NewManager(d.restClient.client) - items, err := lm.GetLibraryItems(d.ctx, libraryId) - if err != nil { - return nil, err - } - for _, item := range items { - if item.Name == name { - return &item, nil - } - } - return nil, fmt.Errorf("Item %s not found", name) -} - -func (d *VCenterDriver) FindContentLibraryFileDatastorePath(isoPath string) (string, error) { - log.Printf("Check if ISO path is a Content Library path") - err := d.restClient.Login(d.ctx) - if err != nil { - log.Printf("vCenter client not available. ISO path not identified as a Content Library path") - return isoPath, err - } - - libraryFilePath := &LibraryFilePath{path: isoPath} - err = libraryFilePath.Validate() - if err != nil { - log.Printf("ISO path not identified as a Content Library path") - return isoPath, err - } - libraryName := libraryFilePath.GetLibraryName() - itemName := libraryFilePath.GetLibraryItemName() - isoFile := libraryFilePath.GetFileName() - - lib, err := d.FindContentLibraryByName(libraryName) - if err != nil { - log.Printf("ISO path not identified as a Content Library path") - return isoPath, err - } - log.Printf("ISO path identified as a Content Library path") - log.Printf("Finding the equivalent datastore path for the Content Library ISO file path") - libItem, err := d.FindContentLibraryItem(lib.library.ID, itemName) - if err != nil { - log.Printf("[WARN] Couldn't find item %s: %s", itemName, err.Error()) - return isoPath, err - } - datastoreName, err := d.GetDatastoreName(lib.library.Storage[0].DatastoreID) - if err != nil { - log.Printf("[WARN] Couldn't find datastore name for library %s", libraryName) - return isoPath, err - } - libItemDir := fmt.Sprintf("[%s] contentlib-%s/%s", datastoreName, lib.library.ID, libItem.ID) - - isoFilePath, err := d.GetDatastoreFilePath(lib.library.Storage[0].DatastoreID, libItemDir, isoFile) - if err != nil { - log.Printf("[WARN] Couldn't find datastore ID path for %s", isoFile) - return isoPath, err - } - - _ = d.restClient.Logout(d.ctx) - return path.Join(libItemDir, isoFilePath), nil -} - -type LibraryFilePath struct { - path string -} - -func (l *LibraryFilePath) Validate() error { - l.path = strings.TrimLeft(l.path, "/") - parts := strings.Split(l.path, "/") - if len(parts) != 3 { - return fmt.Errorf("Not a valid Content Library File path. The path must contain the nanmes for the library, item and file.") - } - return nil -} - -func (l *LibraryFilePath) GetLibraryName() string { - return strings.Split(l.path, "/")[0] -} - -func (l *LibraryFilePath) GetLibraryItemName() string { - return strings.Split(l.path, "/")[1] -} - -func (l *LibraryFilePath) GetFileName() string { - return strings.Split(l.path, "/")[2] -} diff --git a/builder/vsphere/driver/library_test.go b/builder/vsphere/driver/library_test.go deleted file mode 100644 index e0161eb8c..000000000 --- a/builder/vsphere/driver/library_test.go +++ /dev/null @@ -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) - } - } -} diff --git a/builder/vsphere/driver/network.go b/builder/vsphere/driver/network.go deleted file mode 100644 index f2d90d187..000000000 --- a/builder/vsphere/driver/network.go +++ /dev/null @@ -1,77 +0,0 @@ -package driver - -import ( - "fmt" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" -) - -type Network struct { - driver *VCenterDriver - network object.NetworkReference -} - -func (d *VCenterDriver) NewNetwork(ref *types.ManagedObjectReference) *Network { - return &Network{ - network: object.NewNetwork(d.client.Client, *ref), - driver: d, - } -} - -func (d *VCenterDriver) FindNetwork(name string) (*Network, error) { - n, err := d.finder.Network(d.ctx, name) - if err != nil { - return nil, err - } - return &Network{ - network: n, - driver: d, - }, nil -} - -func (d *VCenterDriver) FindNetworks(name string) ([]*Network, error) { - ns, err := d.finder.NetworkList(d.ctx, name) - if err != nil { - return nil, err - } - var networks []*Network - for _, n := range ns { - networks = append(networks, &Network{ - network: n, - driver: d, - }) - } - return networks, nil -} - -func (n *Network) Info(params ...string) (*mo.Network, error) { - var p []string - if len(params) == 0 { - p = []string{"*"} - } else { - p = params - } - var info mo.Network - - network, ok := n.network.(*object.Network) - if !ok { - return nil, fmt.Errorf("unexpected %t network object type", n.network) - } - - err := network.Properties(n.driver.ctx, network.Reference(), p, &info) - if err != nil { - return nil, err - } - return &info, nil -} - -type MultipleNetworkFoundError struct { - path string - append string -} - -func (e *MultipleNetworkFoundError) Error() string { - return fmt.Sprintf("path '%s' resolves to multiple networks. %s", e.path, e.append) -} diff --git a/builder/vsphere/driver/resource_pool.go b/builder/vsphere/driver/resource_pool.go deleted file mode 100644 index c982078b0..000000000 --- a/builder/vsphere/driver/resource_pool.go +++ /dev/null @@ -1,91 +0,0 @@ -package driver - -import ( - "fmt" - "log" - - "github.com/vmware/govmomi/find" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" -) - -type ResourcePool struct { - pool *object.ResourcePool - driver *VCenterDriver -} - -func (d *VCenterDriver) NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool { - return &ResourcePool{ - pool: object.NewResourcePool(d.client.Client, *ref), - driver: d, - } -} - -func (d *VCenterDriver) FindResourcePool(cluster string, host string, name string) (*ResourcePool, error) { - var res string - if cluster != "" { - res = cluster - } else { - res = host - } - - resourcePath := fmt.Sprintf("%v/Resources/%v", res, name) - p, err := d.finder.ResourcePool(d.ctx, resourcePath) - if err != nil { - log.Printf("[WARN] %s not found. Looking for default resource pool.", resourcePath) - dp, dperr := d.finder.DefaultResourcePool(d.ctx) - if _, ok := dperr.(*find.NotFoundError); ok { - // VirtualApp extends ResourcePool, so it should support VirtualApp types. - vapp, verr := d.finder.VirtualApp(d.ctx, name) - if verr != nil { - return nil, err - } - dp = vapp.ResourcePool - } else if dperr != nil { - return nil, err - } - p = dp - } - - return &ResourcePool{ - pool: p, - driver: d, - }, nil -} - -func (p *ResourcePool) Info(params ...string) (*mo.ResourcePool, error) { - var params2 []string - if len(params) == 0 { - params2 = []string{"*"} - } else { - params2 = params - } - var info mo.ResourcePool - err := p.pool.Properties(p.driver.ctx, p.pool.Reference(), params2, &info) - if err != nil { - return nil, err - } - return &info, nil -} - -func (p *ResourcePool) Path() (string, error) { - poolInfo, err := p.Info("name", "parent") - if err != nil { - return "", err - } - if poolInfo.Parent.Type == "ComputeResource" { - return "", nil - } else { - parent := p.driver.NewResourcePool(poolInfo.Parent) - parentPath, err := parent.Path() - if err != nil { - return "", err - } - if parentPath == "" { - return poolInfo.Name, nil - } else { - return fmt.Sprintf("%v/%v", parentPath, poolInfo.Name), nil - } - } -} diff --git a/builder/vsphere/driver/resource_pool_acc_test.go b/builder/vsphere/driver/resource_pool_acc_test.go deleted file mode 100644 index bfb38d2cc..000000000 --- a/builder/vsphere/driver/resource_pool_acc_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/driver/resource_pool_test.go b/builder/vsphere/driver/resource_pool_test.go deleted file mode 100644 index 32badbae9..000000000 --- a/builder/vsphere/driver/resource_pool_test.go +++ /dev/null @@ -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()) - } -} diff --git a/builder/vsphere/driver/vm.go b/builder/vsphere/driver/vm.go deleted file mode 100644 index 0c739d108..000000000 --- a/builder/vsphere/driver/vm.go +++ /dev/null @@ -1,1102 +0,0 @@ -package driver - -import ( - "context" - "errors" - "fmt" - "log" - "net" - "reflect" - "strings" - "time" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/vmware/govmomi/find" - "github.com/vmware/govmomi/nfc" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/ovf" - "github.com/vmware/govmomi/property" - "github.com/vmware/govmomi/vapi/vcenter" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" -) - -type VirtualMachine interface { - Info(params ...string) (*mo.VirtualMachine, error) - Devices() (object.VirtualDeviceList, error) - FloppyDevices() (object.VirtualDeviceList, error) - Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) - updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error) - AddPublicKeys(ctx context.Context, publicKeys string) error - Properties(ctx context.Context) (*mo.VirtualMachine, error) - Destroy() error - Configure(config *HardwareConfig) error - Customize(spec types.CustomizationSpec) error - ResizeDisk(diskSize int64) ([]types.BaseVirtualDeviceConfigSpec, error) - WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error) - PowerOn() error - PowerOff() error - IsPoweredOff() (bool, error) - StartShutdown() error - WaitForShutdown(ctx context.Context, timeout time.Duration) error - CreateSnapshot(name string) error - ConvertToTemplate() error - ImportOvfToContentLibrary(ovf vcenter.OVF) error - ImportToContentLibrary(template vcenter.Template) error - GetDir() (string, error) - AddFloppy(imgPath string) error - SetBootOrder(order []string) error - RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error - addDevice(device types.BaseVirtualDevice) error - AddConfigParams(params map[string]string, info *types.ToolsConfigInfo) error - Export() (*nfc.Lease, error) - CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) - NewOvfManager() *ovf.Manager - GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error) - - AddCdrom(controllerType string, datastoreIsoPath string) error - CreateCdrom(c *types.VirtualController) (*types.VirtualCdrom, error) - RemoveCdroms() error - EjectCdroms() error - AddSATAController() error - FindSATAController() (*types.VirtualAHCIController, error) -} - -type VirtualMachineDriver struct { - vm *object.VirtualMachine - driver *VCenterDriver -} - -type CloneConfig struct { - Name string - Folder string - Cluster string - Host string - ResourcePool string - Datastore string - LinkedClone bool - Network string - MacAddress string - Annotation string - VAppProperties map[string]string - PrimaryDiskSize int64 - StorageConfig StorageConfig -} - -type HardwareConfig struct { - CPUs int32 - CpuCores int32 - CPUReservation int64 - CPULimit int64 - RAM int64 - RAMReservation int64 - RAMReserveAll bool - NestedHV bool - CpuHotAddEnabled bool - MemoryHotAddEnabled bool - VideoRAM int64 - VGPUProfile string - Firmware string - ForceBIOSSetup bool -} - -type NIC struct { - Network string // "" for default network - NetworkCard string // example: vmxnet3 - MacAddress string // set mac if want specific address - Passthrough *bool // direct path i/o -} - -type CreateConfig struct { - Annotation string - Name string - Folder string - Cluster string - Host string - ResourcePool string - Datastore string - GuestOS string // example: otherGuest - NICs []NIC - USBController []string - Version uint // example: 10 - StorageConfig StorageConfig -} - -func (d *VCenterDriver) NewVM(ref *types.ManagedObjectReference) VirtualMachine { - return &VirtualMachineDriver{ - vm: object.NewVirtualMachine(d.client.Client, *ref), - driver: d, - } -} - -func (d *VCenterDriver) FindVM(name string) (VirtualMachine, error) { - vm, err := d.finder.VirtualMachine(d.ctx, name) - if err != nil { - return nil, err - } - return &VirtualMachineDriver{ - vm: vm, - driver: d, - }, nil -} - -func (d *VCenterDriver) PreCleanVM(ui packersdk.Ui, vmPath string, force bool) error { - vm, err := d.FindVM(vmPath) - if err != nil { - if _, ok := err.(*find.NotFoundError); !ok { - return fmt.Errorf("error looking up old vm: %v", err) - } - } - if force && vm != nil { - ui.Say(fmt.Sprintf("the vm/template %s already exists, but deleting it due to -force flag", vmPath)) - - // power off just in case it is still on - vm.PowerOff() - - err := vm.Destroy() - if err != nil { - return fmt.Errorf("error destroying %s: %v", vmPath, err) - } - } - if !force && vm != nil { - return fmt.Errorf("%s already exists, you can use -force flag to destroy it: %v", vmPath, err) - } - - return nil -} - -func (d *VCenterDriver) CreateVM(config *CreateConfig) (VirtualMachine, error) { - createSpec := types.VirtualMachineConfigSpec{ - Name: config.Name, - Annotation: config.Annotation, - GuestId: config.GuestOS, - } - if config.Version != 0 { - createSpec.Version = fmt.Sprintf("%s%d", "vmx-", config.Version) - } - - folder, err := d.FindFolder(config.Folder) - if err != nil { - return nil, err - } - - resourcePool, err := d.FindResourcePool(config.Cluster, config.Host, config.ResourcePool) - if err != nil { - return nil, err - } - - var host *object.HostSystem - if config.Cluster != "" && config.Host != "" { - h, err := d.FindHost(config.Host) - if err != nil { - return nil, err - } - host = h.host - } - - datastore, err := d.FindDatastore(config.Datastore, config.Host) - if err != nil { - return nil, err - } - - devices := object.VirtualDeviceList{} - storageConfigSpec, err := config.StorageConfig.AddStorageDevices(devices) - if err != nil { - return nil, err - } - createSpec.DeviceChange = append(createSpec.DeviceChange, storageConfigSpec...) - - devices, err = addNetwork(d, devices, config) - if err != nil { - return nil, err - } - - t := true - for _, usbType := range config.USBController { - var usb types.BaseVirtualDevice - switch usbType { - // handle "true" and "1" for backwards compatibility - case "usb", "true", "1": - usb = &types.VirtualUSBController{ - EhciEnabled: &t, - } - case "xhci": - usb = new(types.VirtualUSBXHCIController) - default: - continue - } - - devices = append(devices, usb) - } - - devicesConfigSpec, err := devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd) - if err != nil { - return nil, err - } - createSpec.DeviceChange = append(createSpec.DeviceChange, devicesConfigSpec...) - - createSpec.Files = &types.VirtualMachineFileInfo{ - VmPathName: fmt.Sprintf("[%s]", datastore.Name()), - } - - task, err := folder.folder.CreateVM(d.ctx, createSpec, resourcePool.pool, host) - if err != nil { - return nil, err - } - taskInfo, err := task.WaitForResult(d.ctx, nil) - if err != nil { - return nil, err - } - - vmRef, ok := taskInfo.Result.(types.ManagedObjectReference) - if !ok { - return nil, fmt.Errorf("something went wrong when creating the VM") - } - - return d.NewVM(&vmRef), nil -} - -func (vm *VirtualMachineDriver) Info(params ...string) (*mo.VirtualMachine, error) { - var p []string - if len(params) == 0 { - p = []string{"*"} - } else { - p = params - } - var info mo.VirtualMachine - err := vm.vm.Properties(vm.driver.ctx, vm.vm.Reference(), p, &info) - if err != nil { - return nil, err - } - return &info, nil -} - -func (vm *VirtualMachineDriver) Devices() (object.VirtualDeviceList, error) { - vmInfo, err := vm.Info("config.hardware.device") - if err != nil { - return nil, err - } - - return vmInfo.Config.Hardware.Device, nil -} - -func (vm *VirtualMachineDriver) FloppyDevices() (object.VirtualDeviceList, error) { - device, err := vm.Devices() - if err != nil { - return device, err - } - floppies := device.SelectByType((*types.VirtualFloppy)(nil)) - return floppies, nil -} - -func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) { - folder, err := vm.driver.FindFolder(config.Folder) - if err != nil { - return nil, fmt.Errorf("Error finding filder: %s", err) - } - - var relocateSpec types.VirtualMachineRelocateSpec - - pool, err := vm.driver.FindResourcePool(config.Cluster, config.Host, config.ResourcePool) - if err != nil { - return nil, fmt.Errorf("Error finding resource pool: %s", err) - } - poolRef := pool.pool.Reference() - relocateSpec.Pool = &poolRef - - datastore, err := vm.driver.FindDatastore(config.Datastore, config.Host) - if err != nil { - return nil, fmt.Errorf("Error finding datastore: %s", err) - } - datastoreRef := datastore.Reference() - relocateSpec.Datastore = &datastoreRef - - var cloneSpec types.VirtualMachineCloneSpec - cloneSpec.Location = relocateSpec - cloneSpec.PowerOn = false - - if config.LinkedClone == true { - cloneSpec.Location.DiskMoveType = "createNewChildDiskBacking" - - tpl, err := vm.Info("snapshot") - if err != nil { - return nil, fmt.Errorf("Error getting snapshot info for vm: %s", err) - } - if tpl.Snapshot == nil { - err = errors.New("`linked_clone=true`, but template has no snapshots") - return nil, err - } - cloneSpec.Snapshot = tpl.Snapshot.CurrentSnapshot - } - - var configSpec types.VirtualMachineConfigSpec - cloneSpec.Config = &configSpec - - if config.Annotation != "" { - configSpec.Annotation = config.Annotation - } - - devices, err := vm.vm.Device(vm.driver.ctx) - if err != nil { - return nil, err - } - - if config.PrimaryDiskSize > 0 { - deviceResizeSpec, err := vm.ResizeDisk(config.PrimaryDiskSize) - if err != nil { - return nil, fmt.Errorf("failed to resize primary disk: %s", err.Error()) - } - configSpec.DeviceChange = append(configSpec.DeviceChange, deviceResizeSpec...) - } - - virtualDisks := devices.SelectByType((*types.VirtualDisk)(nil)) - virtualControllers := devices.SelectByType((*types.VirtualController)(nil)) - - // Use existing devices to avoid overlapping configuration - existingDevices := object.VirtualDeviceList{} - existingDevices = append(existingDevices, virtualDisks...) - existingDevices = append(existingDevices, virtualControllers...) - - storageConfigSpec, err := config.StorageConfig.AddStorageDevices(existingDevices) - if err != nil { - return nil, fmt.Errorf("failed to add storage devices: %s", err.Error()) - } - configSpec.DeviceChange = append(configSpec.DeviceChange, storageConfigSpec...) - - if config.Network != "" { - net, err := vm.driver.FindNetwork(config.Network) - if err != nil { - return nil, fmt.Errorf("Error finding network: %s", err) - } - backing, err := net.network.EthernetCardBackingInfo(ctx) - if err != nil { - return nil, fmt.Errorf("Error finding ethernet card backing info: %s", err) - } - - devices, err := vm.vm.Device(ctx) - if err != nil { - return nil, fmt.Errorf("Error finding vm devices: %s", err) - } - - adapter, err := findNetworkAdapter(devices) - if err != nil { - return nil, fmt.Errorf("Error finding network adapter: %s", err) - } - - current := adapter.GetVirtualEthernetCard() - current.Backing = backing - current.MacAddress = config.MacAddress - - config := &types.VirtualDeviceConfigSpec{ - Device: adapter.(types.BaseVirtualDevice), - Operation: types.VirtualDeviceConfigSpecOperationEdit, - } - - configSpec.DeviceChange = append(configSpec.DeviceChange, config) - } - - vAppConfig, err := vm.updateVAppConfig(ctx, config.VAppProperties) - if err != nil { - return nil, fmt.Errorf("Error updating VAppConfig: %s", err) - } - configSpec.VAppConfig = vAppConfig - - task, err := vm.vm.Clone(vm.driver.ctx, folder.folder, config.Name, cloneSpec) - if err != nil { - return nil, fmt.Errorf("Error calling vm.vm.Clone task: %s", err) - } - - info, err := task.WaitForResult(ctx, nil) - if err != nil { - if ctx.Err() == context.Canceled { - err = task.Cancel(context.TODO()) - return nil, err - } - - return nil, fmt.Errorf("Error waiting for vm Clone to complete: %s", err) - } - - vmRef, ok := info.Result.(types.ManagedObjectReference) - if !ok { - return nil, fmt.Errorf("something went wrong when cloning the VM") - } - - created := vm.driver.NewVM(&vmRef) - return created, nil -} - -func (vm *VirtualMachineDriver) updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error) { - if len(newProps) == 0 { - return nil, nil - } - - vProps, _ := vm.Properties(ctx) - if vProps.Config.VAppConfig == nil { - return nil, fmt.Errorf("this VM lacks a vApp configuration and cannot have vApp properties set on it") - } - - allProperties := vProps.Config.VAppConfig.GetVmConfigInfo().Property - - var props []types.VAppPropertySpec - for _, p := range allProperties { - userValue, setByUser := newProps[p.Id] - if !setByUser { - continue - } - - if *p.UserConfigurable == false { - return nil, fmt.Errorf("vApp property with userConfigurable=false specified in vapp.properties: %+v", reflect.ValueOf(newProps).MapKeys()) - } - - prop := types.VAppPropertySpec{ - ArrayUpdateSpec: types.ArrayUpdateSpec{ - Operation: types.ArrayUpdateOperationEdit, - }, - Info: &types.VAppPropertyInfo{ - Key: p.Key, - Id: p.Id, - Value: userValue, - UserConfigurable: p.UserConfigurable, - }, - } - props = append(props, prop) - - delete(newProps, p.Id) - } - - if len(newProps) > 0 { - return nil, fmt.Errorf("unsupported vApp properties in vapp.properties: %+v", reflect.ValueOf(newProps).MapKeys()) - } - - return &types.VmConfigSpec{ - Property: props, - }, nil -} - -func (vm *VirtualMachineDriver) AddPublicKeys(ctx context.Context, publicKeys string) error { - newProps := map[string]string{"public-keys": publicKeys} - config, err := vm.updateVAppConfig(ctx, newProps) - if err != nil { - return fmt.Errorf("not possible to save temporary public key: %s", err.Error()) - } - - confSpec := types.VirtualMachineConfigSpec{VAppConfig: config} - task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec) - if err != nil { - return err - } - - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err -} - -func (vm *VirtualMachineDriver) Properties(ctx context.Context) (*mo.VirtualMachine, error) { - log.Printf("fetching properties for VM %q", vm.vm.InventoryPath) - var props mo.VirtualMachine - if err := vm.vm.Properties(ctx, vm.vm.Reference(), nil, &props); err != nil { - return nil, err - } - return &props, nil -} - -func (vm *VirtualMachineDriver) Destroy() error { - task, err := vm.vm.Destroy(vm.driver.ctx) - if err != nil { - return err - } - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err -} - -func (vm *VirtualMachineDriver) Configure(config *HardwareConfig) error { - var confSpec types.VirtualMachineConfigSpec - confSpec.NumCPUs = config.CPUs - confSpec.NumCoresPerSocket = config.CpuCores - confSpec.MemoryMB = config.RAM - - var cpuSpec types.ResourceAllocationInfo - cpuSpec.Reservation = &config.CPUReservation - if config.CPULimit != 0 { - cpuSpec.Limit = &config.CPULimit - } - confSpec.CpuAllocation = &cpuSpec - - var ramSpec types.ResourceAllocationInfo - ramSpec.Reservation = &config.RAMReservation - confSpec.MemoryAllocation = &ramSpec - - confSpec.MemoryReservationLockedToMax = &config.RAMReserveAll - confSpec.NestedHVEnabled = &config.NestedHV - - confSpec.CpuHotAddEnabled = &config.CpuHotAddEnabled - confSpec.MemoryHotAddEnabled = &config.MemoryHotAddEnabled - - if config.VideoRAM != 0 { - devices, err := vm.vm.Device(vm.driver.ctx) - if err != nil { - return err - } - l := devices.SelectByType((*types.VirtualMachineVideoCard)(nil)) - if len(l) != 1 { - return err - } - card := l[0].(*types.VirtualMachineVideoCard) - - card.VideoRamSizeInKB = config.VideoRAM - - spec := &types.VirtualDeviceConfigSpec{ - Device: card, - Operation: types.VirtualDeviceConfigSpecOperationEdit, - } - confSpec.DeviceChange = append(confSpec.DeviceChange, spec) - } - if config.VGPUProfile != "" { - devices, err := vm.vm.Device(vm.driver.ctx) - if err != nil { - return err - } - - pciDevices := devices.SelectByType((*types.VirtualPCIPassthrough)(nil)) - vGPUDevices := pciDevices.SelectByBackingInfo((*types.VirtualPCIPassthroughVmiopBackingInfo)(nil)) - var operation types.VirtualDeviceConfigSpecOperation - if len(vGPUDevices) > 1 { - return err - } else if len(pciDevices) == 1 { - operation = types.VirtualDeviceConfigSpecOperationEdit - } else if len(pciDevices) == 0 { - operation = types.VirtualDeviceConfigSpecOperationAdd - } - - vGPUProfile := newVGPUProfile(config.VGPUProfile) - spec := &types.VirtualDeviceConfigSpec{ - Device: &vGPUProfile, - Operation: operation, - } - log.Printf("Adding vGPU device with profile '%s'", config.VGPUProfile) - confSpec.DeviceChange = append(confSpec.DeviceChange, spec) - } - - efiSecureBootEnabled := false - firmware := config.Firmware - - if firmware == "efi-secure" { - firmware = "efi" - efiSecureBootEnabled = true - } - - confSpec.Firmware = firmware - confSpec.BootOptions = &types.VirtualMachineBootOptions{ - EnterBIOSSetup: types.NewBool(config.ForceBIOSSetup), - EfiSecureBootEnabled: types.NewBool(efiSecureBootEnabled), - } - - task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec) - if err != nil { - return err - } - - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err -} - -func (vm *VirtualMachineDriver) Customize(spec types.CustomizationSpec) error { - task, err := vm.vm.Customize(vm.driver.ctx, spec) - if err != nil { - return err - } - return task.Wait(vm.driver.ctx) -} - -func (vm *VirtualMachineDriver) ResizeDisk(diskSize int64) ([]types.BaseVirtualDeviceConfigSpec, error) { - devices, err := vm.vm.Device(vm.driver.ctx) - if err != nil { - return nil, err - } - - disk, err := findDisk(devices) - if err != nil { - return nil, err - } - - disk.CapacityInKB = diskSize * 1024 - - return []types.BaseVirtualDeviceConfigSpec{ - &types.VirtualDeviceConfigSpec{ - Device: disk, - Operation: types.VirtualDeviceConfigSpecOperationEdit, - }, - }, nil -} - -func (vm *VirtualMachineDriver) PowerOn() error { - task, err := vm.vm.PowerOn(vm.driver.ctx) - if err != nil { - return err - } - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err -} - -func (vm *VirtualMachineDriver) WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error) { - netIP, err := vm.vm.WaitForNetIP(ctx, false) - if err != nil { - return "", err - } - - for _, ips := range netIP { - for _, ip := range ips { - parseIP := net.ParseIP(ip) - if ipNet != nil && !ipNet.Contains(parseIP) { - // ip address is not in range - continue - } - // default to an ipv4 addresses if no ipNet is defined - if ipNet == nil && parseIP.To4() == nil { - continue - } - return ip, nil - } - } - - // unable to find an IP - return "", nil -} - -func (vm *VirtualMachineDriver) PowerOff() error { - state, err := vm.vm.PowerState(vm.driver.ctx) - if err != nil { - return err - } - - if state == types.VirtualMachinePowerStatePoweredOff { - return nil - } - - task, err := vm.vm.PowerOff(vm.driver.ctx) - if err != nil { - return err - } - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err -} - -func (vm *VirtualMachineDriver) IsPoweredOff() (bool, error) { - state, err := vm.vm.PowerState(vm.driver.ctx) - if err != nil { - return false, err - } - - return state == types.VirtualMachinePowerStatePoweredOff, nil -} - -func (vm *VirtualMachineDriver) StartShutdown() error { - err := vm.vm.ShutdownGuest(vm.driver.ctx) - return err -} - -func (vm *VirtualMachineDriver) WaitForShutdown(ctx context.Context, timeout time.Duration) error { - shutdownTimer := time.After(timeout) - for { - off, err := vm.IsPoweredOff() - if err != nil { - return err - } - if off { - break - } - - select { - case <-shutdownTimer: - err := errors.New("Timeout while waiting for machine to shut down.") - return err - case <-ctx.Done(): - return nil - default: - time.Sleep(1 * time.Second) - } - } - return nil -} - -func (vm *VirtualMachineDriver) CreateSnapshot(name string) error { - task, err := vm.vm.CreateSnapshot(vm.driver.ctx, name, "", false, false) - if err != nil { - return err - } - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err -} - -func (vm *VirtualMachineDriver) ConvertToTemplate() error { - return vm.vm.MarkAsTemplate(vm.driver.ctx) -} - -func (vm *VirtualMachineDriver) ImportOvfToContentLibrary(ovf vcenter.OVF) error { - err := vm.driver.restClient.Login(vm.driver.ctx) - if err != nil { - return err - } - - l, err := vm.driver.FindContentLibraryByName(ovf.Target.LibraryID) - if err != nil { - return err - } - if l.library.Type != "LOCAL" { - return fmt.Errorf("can not deploy a VM to the content library %s of type %s; "+ - "the content library must be of type LOCAL", ovf.Target.LibraryID, l.library.Type) - } - - item, err := vm.driver.FindContentLibraryItem(l.library.ID, ovf.Spec.Name) - if err == nil { - // Updates existing library item - ovf.Target.LibraryItemID = item.ID - } - - ovf.Target.LibraryID = l.library.ID - ovf.Source.Value = vm.vm.Reference().Value - ovf.Source.Type = "VirtualMachine" - - vcm := vcenter.NewManager(vm.driver.restClient.client) - _, err = vcm.CreateOVF(vm.driver.ctx, ovf) - if err != nil { - return err - } - - return vm.driver.restClient.Logout(vm.driver.ctx) -} - -func (vm *VirtualMachineDriver) ImportToContentLibrary(template vcenter.Template) error { - err := vm.driver.restClient.Login(vm.driver.ctx) - if err != nil { - return err - } - - l, err := vm.driver.FindContentLibraryByName(template.Library) - if err != nil { - return err - } - if l.library.Type != "LOCAL" { - return fmt.Errorf("can not deploy a VM to the content library %s of type %s; "+ - "the content library must be of type LOCAL", template.Library, l.library.Type) - } - - template.Library = l.library.ID - template.SourceVM = vm.vm.Reference().Value - - if template.Placement.Cluster != "" { - c, err := vm.driver.FindCluster(template.Placement.Cluster) - if err != nil { - return err - } - template.Placement.Cluster = c.cluster.Reference().Value - } - if template.Placement.Folder != "" { - f, err := vm.driver.FindFolder(template.Placement.Folder) - if err != nil { - return err - } - template.Placement.Folder = f.folder.Reference().Value - } - if template.Placement.Host != "" { - h, err := vm.driver.FindHost(template.Placement.Host) - if err != nil { - return err - } - template.Placement.Host = h.host.Reference().Value - } - if template.Placement.ResourcePool != "" { - rp, err := vm.driver.FindResourcePool(template.Placement.Cluster, template.Placement.Host, template.Placement.ResourcePool) - if err != nil { - return err - } - template.Placement.ResourcePool = rp.pool.Reference().Value - } - - if template.VMHomeStorage != nil { - d, err := vm.driver.FindDatastore(template.VMHomeStorage.Datastore, template.Placement.Host) - if err != nil { - return err - } - template.VMHomeStorage.Datastore = d.Reference().Value - } - - vcm := vcenter.NewManager(vm.driver.restClient.client) - _, err = vcm.CreateTemplate(vm.driver.ctx, template) - if err != nil { - return err - } - - return vm.driver.restClient.Logout(vm.driver.ctx) -} - -func (vm *VirtualMachineDriver) GetDir() (string, error) { - vmInfo, err := vm.Info("name", "layoutEx.file") - if err != nil { - return "", err - } - - vmxName := fmt.Sprintf("/%s.vmx", vmInfo.Name) - for _, file := range vmInfo.LayoutEx.File { - if strings.Contains(file.Name, vmInfo.Name) { - return RemoveDatastorePrefix(file.Name[:len(file.Name)-len(vmxName)]), nil - } - } - return "", fmt.Errorf("cannot find '%s'", vmxName) -} - -func addNetwork(d *VCenterDriver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) { - if len(config.NICs) == 0 { - return nil, errors.New("no network adapters have been defined") - } - - for _, nic := range config.NICs { - network, err := findNetwork(nic.Network, config.Host, d) - if err != nil { - return nil, err - } - - backing, err := network.EthernetCardBackingInfo(d.ctx) - if err != nil { - return nil, err - } - - device, err := object.EthernetCardTypes().CreateEthernetCard(nic.NetworkCard, backing) - if err != nil { - return nil, err - } - - card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() - if nic.MacAddress != "" { - card.AddressType = string(types.VirtualEthernetCardMacTypeManual) - card.MacAddress = nic.MacAddress - } - card.UptCompatibilityEnabled = nic.Passthrough - - devices = append(devices, device) - } - return devices, nil -} - -func findNetwork(network string, host string, d *VCenterDriver) (object.NetworkReference, error) { - if network != "" { - var err error - networks, err := d.FindNetworks(network) - if err != nil { - return nil, err - } - if len(networks) == 1 { - return networks[0].network, nil - } - - // If there are multiple networks then try to match the host - if host != "" { - h, err := d.FindHost(host) - if err != nil { - return nil, &MultipleNetworkFoundError{network, fmt.Sprintf("unable to match a network to the host %s: %s", host, err.Error())} - } - for _, n := range networks { - info, err := n.Info("host") - if err != nil { - continue - } - for _, host := range info.Host { - if h.host.Reference().Value == host.Reference().Value { - return n.network, nil - } - } - } - return nil, &MultipleNetworkFoundError{network, fmt.Sprintf("unable to match a network to the host %s", host)} - } - - return nil, &MultipleNetworkFoundError{network, "please provide a host to match or the network full path"} - } - - if host != "" { - h, err := d.FindHost(host) - if err != nil { - return nil, err - } - - i, err := h.Info("network") - if err != nil { - return nil, err - } - - if len(i.Network) > 1 { - return nil, fmt.Errorf("Host has multiple networks. Specify it explicitly") - } - - return object.NewNetwork(d.client.Client, i.Network[0]), nil - } - - return nil, fmt.Errorf("Couldn't find network; 'host' and 'network' not specified. At least one of the two must be specified.") -} - -func newVGPUProfile(vGPUProfile string) types.VirtualPCIPassthrough { - return types.VirtualPCIPassthrough{ - VirtualDevice: types.VirtualDevice{ - DeviceInfo: &types.Description{ - Summary: "", - Label: fmt.Sprintf("New vGPU %v PCI device", vGPUProfile), - }, - Backing: &types.VirtualPCIPassthroughVmiopBackingInfo{ - Vgpu: vGPUProfile, - }, - }, - } -} - -func (vm *VirtualMachineDriver) AddCdrom(controllerType string, datastoreIsoPath string) error { - devices, err := vm.vm.Device(vm.driver.ctx) - if err != nil { - return err - } - - var controller *types.VirtualController - if controllerType == "sata" { - c, err := vm.FindSATAController() - if err != nil { - return err - } - controller = c.GetVirtualController() - } else { - c, err := devices.FindIDEController("") - if err != nil { - return err - } - controller = c.GetVirtualController() - } - - cdrom, err := vm.CreateCdrom(controller) - if err != nil { - return err - } - - if datastoreIsoPath != "" { - ds := &DatastoreIsoPath{path: datastoreIsoPath} - if !ds.Validate() { - return fmt.Errorf("%s is not a valid iso path", datastoreIsoPath) - } - if libPath, err := vm.driver.FindContentLibraryFileDatastorePath(ds.GetFilePath()); err == nil { - datastoreIsoPath = libPath - } else { - log.Printf("Using %s as the datastore path", datastoreIsoPath) - } - - devices.InsertIso(cdrom, datastoreIsoPath) - } - - log.Printf("Creating CD-ROM on controller '%v' with iso '%v'", controller, datastoreIsoPath) - return vm.addDevice(cdrom) -} - -func (vm *VirtualMachineDriver) AddFloppy(imgPath string) error { - devices, err := vm.vm.Device(vm.driver.ctx) - if err != nil { - return err - } - - floppy, err := devices.CreateFloppy() - if err != nil { - return err - } - - if imgPath != "" { - floppy = devices.InsertImg(floppy, imgPath) - } - - return vm.addDevice(floppy) -} - -func (vm *VirtualMachineDriver) SetBootOrder(order []string) error { - devices, err := vm.vm.Device(vm.driver.ctx) - if err != nil { - return err - } - - bootOptions := types.VirtualMachineBootOptions{ - BootOrder: devices.BootOrder(order), - } - - return vm.vm.SetBootOptions(vm.driver.ctx, &bootOptions) -} - -func (vm *VirtualMachineDriver) RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error { - return vm.vm.RemoveDevice(vm.driver.ctx, keepFiles, device...) -} - -func (vm *VirtualMachineDriver) addDevice(device types.BaseVirtualDevice) error { - newDevices := object.VirtualDeviceList{device} - confSpec := types.VirtualMachineConfigSpec{} - var err error - confSpec.DeviceChange, err = newDevices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd) - if err != nil { - return err - } - - task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec) - if err != nil { - return err - } - - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err -} - -func (vm *VirtualMachineDriver) AddConfigParams(params map[string]string, info *types.ToolsConfigInfo) error { - var confSpec types.VirtualMachineConfigSpec - - var ov []types.BaseOptionValue - for k, v := range params { - o := types.OptionValue{ - Key: k, - Value: v, - } - ov = append(ov, &o) - } - confSpec.ExtraConfig = ov - - confSpec.Tools = info - - if len(confSpec.ExtraConfig) > 0 || confSpec.Tools != nil { - task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec) - if err != nil { - return err - } - - _, err = task.WaitForResult(vm.driver.ctx, nil) - return err - } - - return nil -} - -func (vm *VirtualMachineDriver) Export() (*nfc.Lease, error) { - return vm.vm.Export(vm.driver.ctx) -} - -func (vm *VirtualMachineDriver) CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) { - return m.CreateDescriptor(vm.driver.ctx, vm.vm, cdp) -} - -func (vm *VirtualMachineDriver) NewOvfManager() *ovf.Manager { - return ovf.NewManager(vm.vm.Client()) -} - -func (vm *VirtualMachineDriver) GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error) { - var mgr mo.OvfManager - err := property.DefaultCollector(vm.vm.Client()).RetrieveOne(vm.driver.ctx, m.Reference(), nil, &mgr) - if err != nil { - return nil, err - } - return mgr.OvfExportOption, nil -} - -func findNetworkAdapter(l object.VirtualDeviceList) (types.BaseVirtualEthernetCard, error) { - c := l.SelectByType((*types.VirtualEthernetCard)(nil)) - if len(c) == 0 { - return nil, errors.New("no network adapter device found") - } - - return c[0].(types.BaseVirtualEthernetCard), nil -} diff --git a/builder/vsphere/driver/vm_cdrom.go b/builder/vsphere/driver/vm_cdrom.go deleted file mode 100644 index 0eab0d196..000000000 --- a/builder/vsphere/driver/vm_cdrom.go +++ /dev/null @@ -1,89 +0,0 @@ -package driver - -import ( - "errors" - - "github.com/vmware/govmomi/vim25/types" -) - -var ( - ErrNoSataController = errors.New("no available SATA controller") -) - -func (vm *VirtualMachineDriver) AddSATAController() error { - sata := &types.VirtualAHCIController{} - return vm.addDevice(sata) -} - -func (vm *VirtualMachineDriver) FindSATAController() (*types.VirtualAHCIController, error) { - l, err := vm.Devices() - if err != nil { - return nil, err - } - - c := l.PickController((*types.VirtualAHCIController)(nil)) - if c == nil { - return nil, ErrNoSataController - } - - return c.(*types.VirtualAHCIController), nil -} - -func (vm *VirtualMachineDriver) CreateCdrom(c *types.VirtualController) (*types.VirtualCdrom, error) { - l, err := vm.Devices() - if err != nil { - return nil, err - } - - device := &types.VirtualCdrom{} - - l.AssignController(device, c) - - device.Backing = &types.VirtualCdromAtapiBackingInfo{ - VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{}, - } - - device.Connectable = &types.VirtualDeviceConnectInfo{ - AllowGuestControl: true, - Connected: true, - StartConnected: true, - } - - return device, nil -} - -func (vm *VirtualMachineDriver) RemoveCdroms() error { - devices, err := vm.Devices() - if err != nil { - return err - } - cdroms := devices.SelectByType((*types.VirtualCdrom)(nil)) - if err = vm.RemoveDevice(true, cdroms...); err != nil { - return err - } - - sata := devices.SelectByType((*types.VirtualAHCIController)(nil)) - if err = vm.RemoveDevice(true, sata...); err != nil { - return err - } - return nil -} - -func (vm *VirtualMachineDriver) EjectCdroms() error { - devices, err := vm.Devices() - if err != nil { - return err - } - cdroms := devices.SelectByType((*types.VirtualCdrom)(nil)) - for _, cd := range cdroms { - c := cd.(*types.VirtualCdrom) - c.Backing = &types.VirtualCdromRemotePassthroughBackingInfo{} - c.Connectable = &types.VirtualDeviceConnectInfo{} - err := vm.vm.EditDevice(vm.driver.ctx, c) - if err != nil { - return err - } - } - - return nil -} diff --git a/builder/vsphere/driver/vm_cdrom_test.go b/builder/vsphere/driver/vm_cdrom_test.go deleted file mode 100644 index 8a7b86ba1..000000000 --- a/builder/vsphere/driver/vm_cdrom_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/driver/vm_clone_acc_test.go b/builder/vsphere/driver/vm_clone_acc_test.go deleted file mode 100644 index 98d37d6cf..000000000 --- a/builder/vsphere/driver/vm_clone_acc_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/driver/vm_create_acc_test.go b/builder/vsphere/driver/vm_create_acc_test.go deleted file mode 100644 index c2c2d833f..000000000 --- a/builder/vsphere/driver/vm_create_acc_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/driver/vm_keyboard.go b/builder/vsphere/driver/vm_keyboard.go deleted file mode 100644 index d50e66e07..000000000 --- a/builder/vsphere/driver/vm_keyboard.go +++ /dev/null @@ -1,39 +0,0 @@ -package driver - -import ( - "github.com/vmware/govmomi/vim25/methods" - "github.com/vmware/govmomi/vim25/types" - "golang.org/x/mobile/event/key" -) - -type KeyInput struct { - Scancode key.Code - Alt bool - Ctrl bool - Shift bool -} - -func (vm *VirtualMachineDriver) TypeOnKeyboard(input KeyInput) (int32, error) { - var spec types.UsbScanCodeSpec - - spec.KeyEvents = append(spec.KeyEvents, types.UsbScanCodeSpecKeyEvent{ - UsbHidCode: int32(input.Scancode)<<16 | 7, - Modifiers: &types.UsbScanCodeSpecModifierType{ - LeftControl: &input.Ctrl, - LeftAlt: &input.Alt, - LeftShift: &input.Shift, - }, - }) - - req := &types.PutUsbScanCodes{ - This: vm.vm.Reference(), - Spec: spec, - } - - resp, err := methods.PutUsbScanCodes(vm.driver.ctx, vm.driver.client.RoundTripper, req) - if err != nil { - return 0, err - } - - return resp.Returnval, nil -} diff --git a/builder/vsphere/driver/vm_mock.go b/builder/vsphere/driver/vm_mock.go deleted file mode 100644 index daf62b3c9..000000000 --- a/builder/vsphere/driver/vm_mock.go +++ /dev/null @@ -1,235 +0,0 @@ -package driver - -import ( - "context" - "net" - "time" - - "github.com/vmware/govmomi/nfc" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/ovf" - "github.com/vmware/govmomi/vapi/vcenter" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" -) - -type VirtualMachineMock struct { - DestroyError error - DestroyCalled bool - - ConfigureError error - ConfigureCalled bool - ConfigureHardwareConfig *HardwareConfig - - FindSATAControllerCalled bool - FindSATAControllerErr error - - AddSATAControllerCalled bool - AddSATAControllerErr error - - AddCdromCalled bool - AddCdromCalledTimes int - AddCdromErr error - AddCdromTypes []string - AddCdromPaths []string - - GetDirCalled bool - GetDirResponse string - GetDirErr error - - AddFloppyCalled bool - AddFloppyImagePath string - AddFloppyErr error - - FloppyDevicesErr error - FloppyDevicesReturn object.VirtualDeviceList - FloppyDevicesCalled bool - - RemoveDeviceErr error - RemoveDeviceCalled bool - RemoveDeviceKeepFiles bool - RemoveDeviceDevices []types.BaseVirtualDevice - - EjectCdromsCalled bool - EjectCdromsErr error - - RemoveCdromsCalled bool - RemoveCdromsErr error - CloneCalled bool - CloneConfig *CloneConfig - CloneError error -} - -func (vm *VirtualMachineMock) Info(params ...string) (*mo.VirtualMachine, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) Devices() (object.VirtualDeviceList, error) { - return object.VirtualDeviceList{}, nil -} - -func (vm *VirtualMachineMock) FloppyDevices() (object.VirtualDeviceList, error) { - vm.FloppyDevicesCalled = true - return vm.FloppyDevicesReturn, vm.FloppyDevicesErr -} - -func (vm *VirtualMachineMock) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) { - vm.CloneCalled = true - vm.CloneConfig = config - return vm, vm.CloneError -} - -func (vm *VirtualMachineMock) updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) AddPublicKeys(ctx context.Context, publicKeys string) error { - return nil -} - -func (vm *VirtualMachineMock) Properties(ctx context.Context) (*mo.VirtualMachine, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) Destroy() error { - vm.DestroyCalled = true - if vm.DestroyError != nil { - return vm.DestroyError - } - return nil -} - -func (vm *VirtualMachineMock) Configure(config *HardwareConfig) error { - vm.ConfigureCalled = true - vm.ConfigureHardwareConfig = config - if vm.ConfigureError != nil { - return vm.ConfigureError - } - return nil -} - -func (vm *VirtualMachineMock) Customize(spec types.CustomizationSpec) error { - return nil -} - -func (vm *VirtualMachineMock) ResizeDisk(diskSize int64) ([]types.BaseVirtualDeviceConfigSpec, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) PowerOn() error { - return nil -} - -func (vm *VirtualMachineMock) WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error) { - return "", nil -} - -func (vm *VirtualMachineMock) PowerOff() error { - return nil -} - -func (vm *VirtualMachineMock) IsPoweredOff() (bool, error) { - return false, nil -} - -func (vm *VirtualMachineMock) StartShutdown() error { - return nil -} - -func (vm *VirtualMachineMock) WaitForShutdown(ctx context.Context, timeout time.Duration) error { - return nil -} - -func (vm *VirtualMachineMock) CreateSnapshot(name string) error { - return nil -} - -func (vm *VirtualMachineMock) ConvertToTemplate() error { - return nil -} - -func (vm *VirtualMachineMock) ImportOvfToContentLibrary(ovf vcenter.OVF) error { - return nil -} - -func (vm *VirtualMachineMock) ImportToContentLibrary(template vcenter.Template) error { - return nil -} - -func (vm *VirtualMachineMock) GetDir() (string, error) { - vm.GetDirCalled = true - return vm.GetDirResponse, vm.GetDirErr -} - -func (vm *VirtualMachineMock) AddCdrom(cdromType string, isoPath string) error { - vm.AddCdromCalledTimes++ - vm.AddCdromCalled = true - vm.AddCdromTypes = append(vm.AddCdromTypes, cdromType) - vm.AddCdromPaths = append(vm.AddCdromPaths, isoPath) - return vm.AddCdromErr -} - -func (vm *VirtualMachineMock) AddFloppy(imgPath string) error { - vm.AddFloppyCalled = true - vm.AddFloppyImagePath = imgPath - return vm.AddFloppyErr -} - -func (vm *VirtualMachineMock) SetBootOrder(order []string) error { - return nil -} - -func (vm *VirtualMachineMock) RemoveDevice(keepFiles bool, device ...types.BaseVirtualDevice) error { - vm.RemoveDeviceCalled = true - vm.RemoveDeviceKeepFiles = keepFiles - vm.RemoveDeviceDevices = device - return vm.RemoveDeviceErr -} - -func (vm *VirtualMachineMock) addDevice(device types.BaseVirtualDevice) error { - return nil -} - -func (vm *VirtualMachineMock) AddConfigParams(params map[string]string, info *types.ToolsConfigInfo) error { - return nil -} - -func (vm *VirtualMachineMock) Export() (*nfc.Lease, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) NewOvfManager() *ovf.Manager { - return nil -} - -func (vm *VirtualMachineMock) GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) AddSATAController() error { - vm.AddSATAControllerCalled = true - return vm.AddSATAControllerErr -} - -func (vm *VirtualMachineMock) FindSATAController() (*types.VirtualAHCIController, error) { - vm.FindSATAControllerCalled = true - return nil, vm.FindSATAControllerErr -} - -func (vm *VirtualMachineMock) CreateCdrom(c *types.VirtualController) (*types.VirtualCdrom, error) { - return nil, nil -} - -func (vm *VirtualMachineMock) RemoveCdroms() error { - vm.RemoveCdromsCalled = true - return vm.RemoveCdromsErr -} - -func (vm *VirtualMachineMock) EjectCdroms() error { - vm.EjectCdromsCalled = true - return vm.EjectCdromsErr -} diff --git a/builder/vsphere/driver/vm_test.go b/builder/vsphere/driver/vm_test.go deleted file mode 100644 index 186538974..000000000 --- a/builder/vsphere/driver/vm_test.go +++ /dev/null @@ -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) - } -} diff --git a/builder/vsphere/examples/alpine/alpine-3.8.json b/builder/vsphere/examples/alpine/alpine-3.8.json deleted file mode 100644 index f16895dcc..000000000 --- a/builder/vsphere/examples/alpine/alpine-3.8.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "builders": [ - { - "type": "vsphere-iso", - "CPUs": 1, - "RAM": 512, - "RAM_reserve_all": true, - "boot_command": [ - "root", - "mount -t vfat /dev/fd0 /media/floppy", - "setup-alpine -f /media/floppy/answerfile", - "", - "jetbrains", - "jetbrains", - "", - "y", - "", - "reboot", - "", - "root", - "jetbrains", - "mount -t vfat /dev/fd0 /media/floppy", - "/media/floppy/SETUP.SH" - ], - "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" - } - ] -} \ No newline at end of file diff --git a/builder/vsphere/examples/alpine/alpine-3.8.pkr.hcl b/builder/vsphere/examples/alpine/alpine-3.8.pkr.hcl deleted file mode 100644 index a4879333b..000000000 --- a/builder/vsphere/examples/alpine/alpine-3.8.pkr.hcl +++ /dev/null @@ -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", "mount -t vfat /dev/fd0 /media/floppy", "setup-alpine -f /media/floppy/answerfile", "", "jetbrains", "jetbrains", "", "y", "", "reboot", "", "root", "jetbrains", "mount -t vfat /dev/fd0 /media/floppy", "/media/floppy/SETUP.SH"] - 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 /"] - } -} diff --git a/builder/vsphere/examples/alpine/answerfile b/builder/vsphere/examples/alpine/answerfile deleted file mode 100644 index e278b737b..000000000 --- a/builder/vsphere/examples/alpine/answerfile +++ /dev/null @@ -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" diff --git a/builder/vsphere/examples/alpine/setup.sh b/builder/vsphere/examples/alpine/setup.sh deleted file mode 100644 index de9b9179a..000000000 --- a/builder/vsphere/examples/alpine/setup.sh +++ /dev/null @@ -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 <", - "ut", - "/Volumes/setup/setup.sh" - ], - "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" - } - ] -} \ No newline at end of file diff --git a/builder/vsphere/examples/macos/macos-10.13.pkr.hcl b/builder/vsphere/examples/macos/macos-10.13.pkr.hcl deleted file mode 100644 index 544d37f12..000000000 --- a/builder/vsphere/examples/macos/macos-10.13.pkr.hcl +++ /dev/null @@ -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 = ["", "ut", "/Volumes/setup/setup.sh"] - 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"] - -} diff --git a/builder/vsphere/examples/macos/setup/.gitignore b/builder/vsphere/examples/macos/setup/.gitignore deleted file mode 100644 index 89f9ac04a..000000000 --- a/builder/vsphere/examples/macos/setup/.gitignore +++ /dev/null @@ -1 +0,0 @@ -out/ diff --git a/builder/vsphere/examples/macos/setup/iso-macos.sh b/builder/vsphere/examples/macos/setup/iso-macos.sh deleted file mode 100644 index fa24728f4..000000000 --- a/builder/vsphere/examples/macos/setup/iso-macos.sh +++ /dev/null @@ -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 diff --git a/builder/vsphere/examples/macos/setup/iso-setup.sh b/builder/vsphere/examples/macos/setup/iso-setup.sh deleted file mode 100644 index 116b9259b..000000000 --- a/builder/vsphere/examples/macos/setup/iso-setup.sh +++ /dev/null @@ -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 diff --git a/builder/vsphere/examples/macos/setup/postinstall b/builder/vsphere/examples/macos/setup/postinstall deleted file mode 100644 index d9c8c8562..000000000 --- a/builder/vsphere/examples/macos/setup/postinstall +++ /dev/null @@ -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" diff --git a/builder/vsphere/examples/macos/setup/setup.sh b/builder/vsphere/examples/macos/setup/setup.sh deleted file mode 100644 index 9fb49a9f5..000000000 --- a/builder/vsphere/examples/macos/setup/setup.sh +++ /dev/null @@ -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" diff --git a/builder/vsphere/examples/ubuntu/preseed.cfg b/builder/vsphere/examples/ubuntu/preseed.cfg deleted file mode 100644 index ec963b6b2..000000000 --- a/builder/vsphere/examples/ubuntu/preseed.cfg +++ /dev/null @@ -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 diff --git a/builder/vsphere/examples/ubuntu/ubuntu-16.04.json b/builder/vsphere/examples/ubuntu/ubuntu-16.04.json deleted file mode 100644 index f5c87b2c5..000000000 --- a/builder/vsphere/examples/ubuntu/ubuntu-16.04.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "builders": [ - { - "type": "vsphere-iso", - "CPUs": 1, - "RAM": 1024, - "RAM_reserve_all": true, - "boot_command": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "/install/vmlinuz", - " initrd=/install/initrd.gz", - " priority=critical", - " locale=en_US", - " file=/media/preseed.cfg", - "" - ], - "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" - } - ] -} \ No newline at end of file diff --git a/builder/vsphere/examples/ubuntu/ubuntu-16.04.pkr.hcl b/builder/vsphere/examples/ubuntu/ubuntu-16.04.pkr.hcl deleted file mode 100644 index 9901293b6..000000000 --- a/builder/vsphere/examples/ubuntu/ubuntu-16.04.pkr.hcl +++ /dev/null @@ -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 = ["", - "", - "", - "", - "", - "", - "", - "", - "", - "", "/install/vmlinuz", - " initrd=/install/initrd.gz", " priority=critical", - " locale=en_US", " file=/media/preseed.cfg", - ""] - 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 /"] - } -} diff --git a/builder/vsphere/examples/windows/.gitattributes b/builder/vsphere/examples/windows/.gitattributes deleted file mode 100644 index da5ccf8df..000000000 --- a/builder/vsphere/examples/windows/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -*.cmd text eol=crlf -*.ps1 text eol=crlf diff --git a/builder/vsphere/examples/windows/setup/Autounattend.xml b/builder/vsphere/examples/windows/setup/Autounattend.xml deleted file mode 100644 index 9c3d30416..000000000 --- a/builder/vsphere/examples/windows/setup/Autounattend.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - - - en-US - - - - - - - B:\ - - - - - - - true - - - - - - - - - /IMAGE/NAME - Windows 10 Pro - - - true - - - - - - 0 - - - 1 - true - Primary - - - - - - - - - - - false - - - - - - - - 1 - - a:\vmtools.cmd - Always - - - - - - - - en-US - - - - - - 3 - - - - - - - - jetbrains - - jetbrains - 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> diff --git a/builder/vsphere/examples/windows/setup/setup.ps1 b/builder/vsphere/examples/windows/setup/setup.ps1 deleted file mode 100644 index 27e65a55e..000000000 --- a/builder/vsphere/examples/windows/setup/setup.ps1 +++ /dev/null @@ -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 diff --git a/builder/vsphere/examples/windows/setup/vmtools.cmd b/builder/vsphere/examples/windows/setup/vmtools.cmd deleted file mode 100644 index 19a942d80..000000000 --- a/builder/vsphere/examples/windows/setup/vmtools.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@rem Silent mode, basic UI, no reboot -e:\setup64 /s /v "/qb REBOOT=R" diff --git a/builder/vsphere/examples/windows/windows-10.json b/builder/vsphere/examples/windows/windows-10.json deleted file mode 100644 index e9df38503..000000000 --- a/builder/vsphere/examples/windows/windows-10.json +++ /dev/null @@ -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" - } - ] -} \ No newline at end of file diff --git a/builder/vsphere/examples/windows/windows-10.pkr.hcl b/builder/vsphere/examples/windows/windows-10.pkr.hcl deleted file mode 100644 index e2b2ad670..000000000 --- a/builder/vsphere/examples/windows/windows-10.pkr.hcl +++ /dev/null @@ -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:\\"] - } -} diff --git a/builder/vsphere/iso/builder.go b/builder/vsphere/iso/builder.go deleted file mode 100644 index f975bad84..000000000 --- a/builder/vsphere/iso/builder.go +++ /dev/null @@ -1,179 +0,0 @@ -package iso - -import ( - "context" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "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" -) - -type Builder struct { - config Config - runner multistep.Runner -} - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - warnings, errs := b.config.Prepare(raws...) - if errs != nil { - return nil, warnings, errs - } - - return nil, warnings, nil -} - -func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) { - state := new(multistep.BasicStateBag) - state.Put("debug", b.config.PackerDebug) - state.Put("hook", hook) - state.Put("ui", ui) - - var steps []multistep.Step - - steps = append(steps, - &common.StepConnect{ - Config: &b.config.ConnectConfig, - }, - &common.StepDownload{ - DownloadStep: &commonsteps.StepDownload{ - Checksum: b.config.ISOChecksum, - Description: "ISO", - Extension: b.config.TargetExtension, - ResultKey: "iso_path", - TargetPath: b.config.TargetPath, - Url: b.config.ISOUrls, - }, - Url: b.config.ISOUrls, - ResultKey: "iso_path", - Datastore: b.config.Datastore, - Host: b.config.Host, - }, - &commonsteps.StepCreateCD{ - Files: b.config.CDConfig.CDFiles, - Label: b.config.CDConfig.CDLabel, - }, - &common.StepRemoteUpload{ - Datastore: b.config.Datastore, - Host: b.config.Host, - SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads, - }, - &StepCreateVM{ - Config: &b.config.CreateConfig, - Location: &b.config.LocationConfig, - Force: b.config.PackerConfig.PackerForce, - }, - &common.StepConfigureHardware{ - Config: &b.config.HardwareConfig, - }, - &common.StepAddCDRom{ - Config: &b.config.CDRomConfig, - }, - &common.StepConfigParams{ - Config: &b.config.ConfigParamsConfig, - }, - &commonsteps.StepCreateFloppy{ - Files: b.config.FloppyFiles, - Directories: b.config.FloppyDirectories, - Label: b.config.FloppyLabel, - }, - &common.StepAddFloppy{ - Config: &b.config.FloppyConfig, - Datastore: b.config.Datastore, - Host: b.config.Host, - SetHostForDatastoreUploads: b.config.SetHostForDatastoreUploads, - }, - &common.StepHTTPIPDiscover{ - HTTPIP: b.config.BootConfig.HTTPIP, - Network: b.config.WaitIpConfig.GetIPNet(), - }, - commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), - &common.StepRun{ - Config: &b.config.RunConfig, - SetOrder: true, - }, - &common.StepBootCommand{ - Config: &b.config.BootConfig, - Ctx: b.config.ctx, - VMName: b.config.VMName, - }, - ) - - if b.config.Comm.Type != "none" { - steps = append(steps, - &common.StepWaitForIp{ - Config: &b.config.WaitIpConfig, - }, - &communicator.StepConnect{ - Config: &b.config.Comm, - Host: common.CommHost(b.config.Comm.Host()), - SSHConfig: b.config.Comm.SSHConfigFunc(), - }, - &commonsteps.StepProvision{}, - ) - } - - steps = append(steps, - &common.StepShutdown{ - Config: &b.config.ShutdownConfig, - }, - &common.StepRemoveFloppy{ - Datastore: b.config.Datastore, - Host: b.config.Host, - }, - &common.StepRemoveCDRom{ - Config: &b.config.RemoveCDRomConfig, - }, - &common.StepCreateSnapshot{ - CreateSnapshot: b.config.CreateSnapshot, - }, - &common.StepConvertToTemplate{ - ConvertToTemplate: b.config.ConvertToTemplate, - }, - ) - - if b.config.ContentLibraryDestinationConfig != nil { - steps = append(steps, &common.StepImportToContentLibrary{ - ContentLibConfig: b.config.ContentLibraryDestinationConfig, - }) - } - - if b.config.Export != nil { - steps = append(steps, &common.StepExport{ - Name: b.config.Export.Name, - Force: b.config.Export.Force, - Images: b.config.Export.Images, - Manifest: b.config.Export.Manifest, - OutputDir: b.config.Export.OutputDir.OutputDir, - Options: b.config.Export.Options, - }) - } - - b.runner = commonsteps.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) - b.runner.Run(ctx, state) - - if rawErr, ok := state.GetOk("error"); ok { - return nil, rawErr.(error) - } - - if _, ok := state.GetOk("vm"); !ok { - return nil, nil - } - - artifact := &common.Artifact{ - Name: b.config.VMName, - VM: state.Get("vm").(*driver.VirtualMachineDriver), - StateData: map[string]interface{}{"generated_data": state.Get("generated_data")}, - } - - if b.config.Export != nil { - artifact.Outconfig = &b.config.Export.OutputDir - } - - return artifact, nil -} diff --git a/builder/vsphere/iso/builder_acc_test.go b/builder/vsphere/iso/builder_acc_test.go deleted file mode 100644 index 63dc6b520..000000000 --- a/builder/vsphere/iso/builder_acc_test.go +++ /dev/null @@ -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) -} diff --git a/builder/vsphere/iso/common_test.go b/builder/vsphere/iso/common_test.go deleted file mode 100644 index f35c006a1..000000000 --- a/builder/vsphere/iso/common_test.go +++ /dev/null @@ -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 -} diff --git a/builder/vsphere/iso/config.go b/builder/vsphere/iso/config.go deleted file mode 100644 index f0edbde1d..000000000 --- a/builder/vsphere/iso/config.go +++ /dev/null @@ -1,107 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type Config - -package iso - -import ( - packerCommon "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - 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" -) - -type Config struct { - packerCommon.PackerConfig `mapstructure:",squash"` - commonsteps.HTTPConfig `mapstructure:",squash"` - commonsteps.CDConfig `mapstructure:",squash"` - - common.ConnectConfig `mapstructure:",squash"` - CreateConfig `mapstructure:",squash"` - common.LocationConfig `mapstructure:",squash"` - common.HardwareConfig `mapstructure:",squash"` - common.ConfigParamsConfig `mapstructure:",squash"` - - commonsteps.ISOConfig `mapstructure:",squash"` - - common.CDRomConfig `mapstructure:",squash"` - common.RemoveCDRomConfig `mapstructure:",squash"` - common.FloppyConfig `mapstructure:",squash"` - common.RunConfig `mapstructure:",squash"` - common.BootConfig `mapstructure:",squash"` - common.WaitIpConfig `mapstructure:",squash"` - Comm communicator.Config `mapstructure:",squash"` - - common.ShutdownConfig `mapstructure:",squash"` - - // Create a snapshot when set to `true`, so the VM can be used as a base - // for linked clones. Defaults to `false`. - CreateSnapshot bool `mapstructure:"create_snapshot"` - // Convert VM to a template. Defaults to `false`. - ConvertToTemplate bool `mapstructure:"convert_to_template"` - // Configuration for exporting VM to an ovf file. - // The VM will not be exported if no [Export Configuration](#export-configuration) is specified. - Export *common.ExportConfig `mapstructure:"export"` - // Configuration for importing the VM template to a Content Library. - // The VM template will not be imported if no [Content Library Import Configuration](#content-library-import-configuration) is specified. - // The import doesn't work if [convert_to_template](#convert_to_template) is set to true. - ContentLibraryDestinationConfig *common.ContentLibraryDestinationConfig `mapstructure:"content_library_destination"` - - ctx interpolate.Context -} - -func (c *Config) Prepare(raws ...interface{}) ([]string, error) { - err := config.Decode(c, &config.DecodeOpts{ - PluginType: common.BuilderId, - Interpolate: true, - InterpolateContext: &c.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{ - "boot_command", - }, - }, - }, raws...) - if err != nil { - return nil, err - } - - warnings := make([]string, 0) - errs := new(packersdk.MultiError) - - if c.ISOUrls != nil || c.RawSingleISOUrl != "" { - isoWarnings, isoErrs := c.ISOConfig.Prepare(&c.ctx) - warnings = append(warnings, isoWarnings...) - errs = packersdk.MultiErrorAppend(errs, isoErrs...) - } - - errs = packersdk.MultiErrorAppend(errs, c.ConnectConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.CreateConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.LocationConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...) - - errs = packersdk.MultiErrorAppend(errs, c.CDRomConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.CDConfig.Prepare(&c.ctx)...) - errs = packersdk.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.ctx)...) - errs = packersdk.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...) - errs = packersdk.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) - - shutdownWarnings, shutdownErrs := c.ShutdownConfig.Prepare(c.Comm) - warnings = append(warnings, shutdownWarnings...) - errs = packersdk.MultiErrorAppend(errs, shutdownErrs...) - - if c.Export != nil { - errs = packersdk.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...) - } - if c.ContentLibraryDestinationConfig != nil { - errs = packersdk.MultiErrorAppend(errs, c.ContentLibraryDestinationConfig.Prepare(&c.LocationConfig)...) - } - - if len(errs.Errors) > 0 { - return warnings, errs - } - - return warnings, nil -} diff --git a/builder/vsphere/iso/config.hcl2spec.go b/builder/vsphere/iso/config.hcl2spec.go deleted file mode 100644 index ee8298e49..000000000 --- a/builder/vsphere/iso/config.hcl2spec.go +++ /dev/null @@ -1,286 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT. - -package iso - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/vsphere/common" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"` - CDFiles []string `mapstructure:"cd_files" cty:"cd_files" hcl:"cd_files"` - CDLabel *string `mapstructure:"cd_label" cty:"cd_label" hcl:"cd_label"` - VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server" hcl:"vcenter_server"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection" hcl:"insecure_connection"` - Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"` - Version *uint `mapstructure:"vm_version" cty:"vm_version" hcl:"vm_version"` - GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"` - DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"` - Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"` - NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` - USBController []string `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"` - Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"` - Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"` - Host *string `mapstructure:"host" cty:"host" hcl:"host"` - ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"` - Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"` - SetHostForDatastoreUploads *bool `mapstructure:"set_host_for_datastore_uploads" cty:"set_host_for_datastore_uploads" hcl:"set_host_for_datastore_uploads"` - CPUs *int32 `mapstructure:"CPUs" cty:"CPUs" hcl:"CPUs"` - CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores" hcl:"cpu_cores"` - CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation" hcl:"CPU_reservation"` - CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit" hcl:"CPU_limit"` - CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug" hcl:"CPU_hot_plug"` - RAM *int64 `mapstructure:"RAM" cty:"RAM" hcl:"RAM"` - RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation" hcl:"RAM_reservation"` - RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all" hcl:"RAM_reserve_all"` - MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug" hcl:"RAM_hot_plug"` - VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram" hcl:"video_ram"` - VGPUProfile *string `mapstructure:"vgpu_profile" cty:"vgpu_profile" hcl:"vgpu_profile"` - NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV" hcl:"NestedHV"` - Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"` - ForceBIOSSetup *bool `mapstructure:"force_bios_setup" cty:"force_bios_setup" hcl:"force_bios_setup"` - ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters" hcl:"configuration_parameters"` - ToolsSyncTime *bool `mapstructure:"tools_sync_time" cty:"tools_sync_time" hcl:"tools_sync_time"` - ToolsUpgradePolicy *bool `mapstructure:"tools_upgrade_policy" cty:"tools_upgrade_policy" hcl:"tools_upgrade_policy"` - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` - CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type" hcl:"cdrom_type"` - ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths" hcl:"iso_paths"` - RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom" hcl:"remove_cdrom"` - FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path" hcl:"floppy_img_path"` - FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"` - FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"` - FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"` - BootOrder *string `mapstructure:"boot_order" cty:"boot_order" hcl:"boot_order"` - BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"` - BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"` - BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"` - HTTPIP *string `mapstructure:"http_ip" cty:"http_ip" hcl:"http_ip"` - WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout" hcl:"ip_wait_timeout"` - SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout" hcl:"ip_settle_timeout"` - WaitAddress *string `mapstructure:"ip_wait_address" cty:"ip_wait_address" hcl:"ip_wait_address"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` - SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - Command *string `mapstructure:"shutdown_command" cty:"shutdown_command" hcl:"shutdown_command"` - Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout" hcl:"shutdown_timeout"` - DisableShutdown *bool `mapstructure:"disable_shutdown" cty:"disable_shutdown" hcl:"disable_shutdown"` - CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot" hcl:"create_snapshot"` - ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template" hcl:"convert_to_template"` - Export *common.FlatExportConfig `mapstructure:"export" cty:"export" hcl:"export"` - ContentLibraryDestinationConfig *common.FlatContentLibraryDestinationConfig `mapstructure:"content_library_destination" cty:"content_library_destination" hcl:"content_library_destination"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, - "http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false}, - "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, - "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, - "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, - "http_interface": &hcldec.AttrSpec{Name: "http_interface", Type: cty.String, Required: false}, - "cd_files": &hcldec.AttrSpec{Name: "cd_files", Type: cty.List(cty.String), Required: false}, - "cd_label": &hcldec.AttrSpec{Name: "cd_label", Type: cty.String, Required: false}, - "vcenter_server": &hcldec.AttrSpec{Name: "vcenter_server", Type: cty.String, Required: false}, - "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "insecure_connection": &hcldec.AttrSpec{Name: "insecure_connection", Type: cty.Bool, Required: false}, - "datacenter": &hcldec.AttrSpec{Name: "datacenter", Type: cty.String, Required: false}, - "vm_version": &hcldec.AttrSpec{Name: "vm_version", Type: cty.Number, Required: false}, - "guest_os_type": &hcldec.AttrSpec{Name: "guest_os_type", Type: cty.String, Required: false}, - "disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false}, - "storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())}, - "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())}, - "usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.List(cty.String), Required: false}, - "notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "folder": &hcldec.AttrSpec{Name: "folder", Type: cty.String, Required: false}, - "cluster": &hcldec.AttrSpec{Name: "cluster", Type: cty.String, Required: false}, - "host": &hcldec.AttrSpec{Name: "host", Type: cty.String, Required: false}, - "resource_pool": &hcldec.AttrSpec{Name: "resource_pool", Type: cty.String, Required: false}, - "datastore": &hcldec.AttrSpec{Name: "datastore", Type: cty.String, Required: false}, - "set_host_for_datastore_uploads": &hcldec.AttrSpec{Name: "set_host_for_datastore_uploads", Type: cty.Bool, Required: false}, - "CPUs": &hcldec.AttrSpec{Name: "CPUs", Type: cty.Number, Required: false}, - "cpu_cores": &hcldec.AttrSpec{Name: "cpu_cores", Type: cty.Number, Required: false}, - "CPU_reservation": &hcldec.AttrSpec{Name: "CPU_reservation", Type: cty.Number, Required: false}, - "CPU_limit": &hcldec.AttrSpec{Name: "CPU_limit", Type: cty.Number, Required: false}, - "CPU_hot_plug": &hcldec.AttrSpec{Name: "CPU_hot_plug", Type: cty.Bool, Required: false}, - "RAM": &hcldec.AttrSpec{Name: "RAM", Type: cty.Number, Required: false}, - "RAM_reservation": &hcldec.AttrSpec{Name: "RAM_reservation", Type: cty.Number, Required: false}, - "RAM_reserve_all": &hcldec.AttrSpec{Name: "RAM_reserve_all", Type: cty.Bool, Required: false}, - "RAM_hot_plug": &hcldec.AttrSpec{Name: "RAM_hot_plug", Type: cty.Bool, Required: false}, - "video_ram": &hcldec.AttrSpec{Name: "video_ram", Type: cty.Number, Required: false}, - "vgpu_profile": &hcldec.AttrSpec{Name: "vgpu_profile", Type: cty.String, Required: false}, - "NestedHV": &hcldec.AttrSpec{Name: "NestedHV", Type: cty.Bool, Required: false}, - "firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false}, - "force_bios_setup": &hcldec.AttrSpec{Name: "force_bios_setup", Type: cty.Bool, Required: false}, - "configuration_parameters": &hcldec.AttrSpec{Name: "configuration_parameters", Type: cty.Map(cty.String), Required: false}, - "tools_sync_time": &hcldec.AttrSpec{Name: "tools_sync_time", Type: cty.Bool, Required: false}, - "tools_upgrade_policy": &hcldec.AttrSpec{Name: "tools_upgrade_policy", Type: cty.Bool, Required: false}, - "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, - "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, - "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, - "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, - "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, - "cdrom_type": &hcldec.AttrSpec{Name: "cdrom_type", Type: cty.String, Required: false}, - "iso_paths": &hcldec.AttrSpec{Name: "iso_paths", Type: cty.List(cty.String), Required: false}, - "remove_cdrom": &hcldec.AttrSpec{Name: "remove_cdrom", Type: cty.Bool, Required: false}, - "floppy_img_path": &hcldec.AttrSpec{Name: "floppy_img_path", Type: cty.String, Required: false}, - "floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false}, - "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, - "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, - "boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.String, Required: false}, - "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, - "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, - "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "http_ip": &hcldec.AttrSpec{Name: "http_ip", Type: cty.String, Required: false}, - "ip_wait_timeout": &hcldec.AttrSpec{Name: "ip_wait_timeout", Type: cty.String, Required: false}, - "ip_settle_timeout": &hcldec.AttrSpec{Name: "ip_settle_timeout", Type: cty.String, Required: false}, - "ip_wait_address": &hcldec.AttrSpec{Name: "ip_wait_address", Type: cty.String, Required: false}, - "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, - "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, - "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, - "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, - "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, - "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, - "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, - "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, - "temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false}, - "temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false}, - "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, - "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, - "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, - "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, - "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, - "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, - "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, - "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, - "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, - "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, - "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, - "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, - "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, - "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, - "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, - "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, - "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, - "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, - "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, - "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, - "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, - "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, - "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, - "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, - "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, - "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, - "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, - "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, - "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, - "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, - "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, - "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, - "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, - "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, - "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, - "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, - "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, - "shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false}, - "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false}, - "disable_shutdown": &hcldec.AttrSpec{Name: "disable_shutdown", Type: cty.Bool, Required: false}, - "create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false}, - "convert_to_template": &hcldec.AttrSpec{Name: "convert_to_template", Type: cty.Bool, Required: false}, - "export": &hcldec.BlockSpec{TypeName: "export", Nested: hcldec.ObjectSpec((*common.FlatExportConfig)(nil).HCL2Spec())}, - "content_library_destination": &hcldec.BlockSpec{TypeName: "content_library_destination", Nested: hcldec.ObjectSpec((*common.FlatContentLibraryDestinationConfig)(nil).HCL2Spec())}, - } - return s -} diff --git a/builder/vsphere/iso/step_create.go b/builder/vsphere/iso/step_create.go deleted file mode 100644 index 87f0fc12c..000000000 --- a/builder/vsphere/iso/step_create.go +++ /dev/null @@ -1,188 +0,0 @@ -//go:generate struct-markdown -//go:generate mapstructure-to-hcl2 -type NIC,CreateConfig - -package iso - -import ( - "context" - "fmt" - "path" - - "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" -) - -// Defines a Network Adapter -// -// Example that creates two network adapters: -// -// In JSON: -// ```json -// "network_adapters": [ -// { -// "network": "VM Network", -// "network_card": "vmxnet3" -// }, -// { -// "network": "OtherNetwork", -// "network_card": "vmxnet3" -// } -// ], -// ``` -// In HCL2: -// ```hcl -// network_adapters { -// network = "VM Network" -// network_card = "vmxnet3" -// } -// network_adapters { -// network = "OtherNetwork" -// network_card = "vmxnet3" -// } -// ``` -type NIC struct { - // Set the network in which the VM will be connected to. If no network is - // specified, `host` must be specified to allow Packer to look for the - // available network. If the network is inside a network folder in vCenter, - // you need to provide the full path to the network. - Network string `mapstructure:"network"` - // Set VM network card type. Example `vmxnet3`. - NetworkCard string `mapstructure:"network_card" required:"true"` - // Set network card MAC address - MacAddress string `mapstructure:"mac_address"` - // Enable DirectPath I/O passthrough - Passthrough *bool `mapstructure:"passthrough"` -} - -type CreateConfig struct { - // Set VM hardware version. Defaults to the most current VM hardware - // version supported by vCenter. See - // [VMWare article 1003746](https://kb.vmware.com/s/article/1003746) for - // the full list of supported VM hardware versions. - Version uint `mapstructure:"vm_version"` - // Set VM OS type. Defaults to `otherGuest`. See [ - // here](https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html) - // for a full list of possible values. - GuestOSType string `mapstructure:"guest_os_type"` - StorageConfig common.StorageConfig `mapstructure:",squash"` - // Network adapters - NICs []NIC `mapstructure:"network_adapters"` - // Create USB controllers for the virtual machine. "usb" for a usb 2.0 controller. "xhci" for a usb 3.0 controller. There can only be at most one of each. - USBController []string `mapstructure:"usb_controller"` - // VM notes. - Notes string `mapstructure:"notes"` -} - -func (c *CreateConfig) Prepare() []error { - var errs []error - - if len(c.StorageConfig.DiskControllerType) == 0 { - c.StorageConfig.DiskControllerType = append(c.StorageConfig.DiskControllerType, "") - } - - // there should be at least one - if len(c.StorageConfig.Storage) == 0 { - errs = append(errs, fmt.Errorf("no storage devices have been defined")) - } - errs = append(errs, c.StorageConfig.Prepare()...) - - if c.GuestOSType == "" { - c.GuestOSType = "otherGuest" - } - - usbCount := 0 - xhciCount := 0 - - for i, s := range c.USBController { - switch s { - // 1 and true for backwards compatibility - case "usb", "1", "true": - usbCount++ - case "xhci": - xhciCount++ - // 0 and false for backwards compatibility - case "false", "0": - continue - default: - errs = append(errs, fmt.Errorf("usb_controller[%d] references an unknown usb controller", i)) - } - } - if usbCount > 1 || xhciCount > 1 { - errs = append(errs, fmt.Errorf("there can only be one usb controller and one xhci controller")) - } - - return errs -} - -type StepCreateVM struct { - Config *CreateConfig - Location *common.LocationConfig - Force bool -} - -func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - d := state.Get("driver").(driver.Driver) - vmPath := path.Join(s.Location.Folder, s.Location.VMName) - - err := d.PreCleanVM(ui, vmPath, s.Force) - if err != nil { - state.Put("error", err) - return multistep.ActionHalt - } - - ui.Say("Creating VM...") - - // add network/network card an the first nic for backwards compatibility in the type is defined - var networkCards []driver.NIC - for _, nic := range s.Config.NICs { - networkCards = append(networkCards, driver.NIC{ - Network: nic.Network, - NetworkCard: nic.NetworkCard, - MacAddress: nic.MacAddress, - Passthrough: nic.Passthrough, - }) - } - - // add disk as the first drive for backwards compatibility if the type is defined - var disks []driver.Disk - for _, disk := range s.Config.StorageConfig.Storage { - disks = append(disks, driver.Disk{ - DiskSize: disk.DiskSize, - DiskEagerlyScrub: disk.DiskEagerlyScrub, - DiskThinProvisioned: disk.DiskThinProvisioned, - ControllerIndex: disk.DiskControllerIndex, - }) - } - - vm, err := d.CreateVM(&driver.CreateConfig{ - StorageConfig: driver.StorageConfig{ - DiskControllerType: s.Config.StorageConfig.DiskControllerType, - Storage: disks, - }, - Annotation: s.Config.Notes, - Name: s.Location.VMName, - Folder: s.Location.Folder, - Cluster: s.Location.Cluster, - Host: s.Location.Host, - ResourcePool: s.Location.ResourcePool, - Datastore: s.Location.Datastore, - GuestOS: s.Config.GuestOSType, - NICs: networkCards, - USBController: s.Config.USBController, - Version: s.Config.Version, - }) - if err != nil { - state.Put("error", fmt.Errorf("error creating vm: %v", err)) - return multistep.ActionHalt - } - state.Put("vm", vm) - - return multistep.ActionContinue -} - -func (s *StepCreateVM) Cleanup(state multistep.StateBag) { - common.CleanupVM(state) -} diff --git a/builder/vsphere/iso/step_create.hcl2spec.go b/builder/vsphere/iso/step_create.hcl2spec.go deleted file mode 100644 index 9d9699529..000000000 --- a/builder/vsphere/iso/step_create.hcl2spec.go +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type NIC,CreateConfig"; DO NOT EDIT. - -package iso - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer/builder/vsphere/common" - "github.com/zclconf/go-cty/cty" -) - -// FlatCreateConfig is an auto-generated flat version of CreateConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatCreateConfig struct { - Version *uint `mapstructure:"vm_version" cty:"vm_version" hcl:"vm_version"` - GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"` - DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"` - Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"` - NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"` - USBController []string `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"` - Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"` -} - -// FlatMapstructure returns a new FlatCreateConfig. -// FlatCreateConfig is an auto-generated flat version of CreateConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*CreateConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatCreateConfig) -} - -// HCL2Spec returns the hcl spec of a CreateConfig. -// This spec is used by HCL to read the fields of CreateConfig. -// The decoded values from this spec will then be applied to a FlatCreateConfig. -func (*FlatCreateConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "vm_version": &hcldec.AttrSpec{Name: "vm_version", Type: cty.Number, Required: false}, - "guest_os_type": &hcldec.AttrSpec{Name: "guest_os_type", Type: cty.String, Required: false}, - "disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false}, - "storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())}, - "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())}, - "usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.List(cty.String), Required: false}, - "notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false}, - } - return s -} - -// FlatNIC is an auto-generated flat version of NIC. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatNIC struct { - Network *string `mapstructure:"network" cty:"network" hcl:"network"` - NetworkCard *string `mapstructure:"network_card" required:"true" cty:"network_card" hcl:"network_card"` - MacAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"` - Passthrough *bool `mapstructure:"passthrough" cty:"passthrough" hcl:"passthrough"` -} - -// FlatMapstructure returns a new FlatNIC. -// FlatNIC is an auto-generated flat version of NIC. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*NIC) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatNIC) -} - -// HCL2Spec returns the hcl spec of a NIC. -// This spec is used by HCL to read the fields of NIC. -// The decoded values from this spec will then be applied to a FlatNIC. -func (*FlatNIC) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false}, - "network_card": &hcldec.AttrSpec{Name: "network_card", Type: cty.String, Required: false}, - "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, - "passthrough": &hcldec.AttrSpec{Name: "passthrough", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/vsphere/iso/step_create_test.go b/builder/vsphere/iso/step_create_test.go deleted file mode 100644 index b05b0d1c6..000000000 --- a/builder/vsphere/iso/step_create_test.go +++ /dev/null @@ -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, - } -} diff --git a/builder/vsphere/test/lab.ovpn b/builder/vsphere/test/lab.ovpn deleted file mode 100644 index 45941a2af..000000000 --- a/builder/vsphere/test/lab.ovpn +++ /dev/null @@ -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 diff --git a/builder/vsphere/test/lab.p12 b/builder/vsphere/test/lab.p12 deleted file mode 100644 index e628d471c1566966c8d66deadfa728888015faa6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4141 zcmY+GXD}R!yN4}yb<S#G_1;<H=px#xQ6fUrV2R#^V<T9-trjh6bkVKeqeqPvT{aR{ z^d)+`IWza(|GgjHd1s#A%scO=-#k#{Ujq050w|K|5JVyvsTp}r0U!btAgM5fNUGI8 zcoB*uP5e&;DnOEk{6TN<0eF9w-+vMSlo>?&-xtUMASfjvv75f3hPq__Pkel0ybvU* zrhdePU;}`9{#T!3#&oK)7T&z^(xaluj26y5kDkijX*4k~6rjN`3D&yZZp!V@G9?Xh zIVc%-yJhu%JF}`J7iD{_w&}Fy<-GWkA}e8=R2{~qn(m&aBC0D8mzp36uz#c;&I<g! zd8V@Z1lGIXBjc`#v94n-0A-wP3wAz+^i5cCKa-+6+g>_rZeXm9!MhHvmUvONG-Ns& z3?3eC9*$8f2K`p1>+2Vr+xi5Nx3f2y(B#xsfOA&oVcfHDANv2k<{uDg-5|{UD@A6S ze<d0nO`x!G8qDW!=9t~N3K$_<6OArMIcez71bb>>Ps5p3PWTs#UbRxK{UFVn0VjRt zcn->rxZAwG_4gU48;c$MF5&PE;vyW)+Aw=~8^Uga|4OKAy(6AIrAFduV2TiyAjh9C zZNndCd#WjSi4W|pEGTV~S*3BM;_T$Ha@8zVr)wKC9^G4Pn9wPeo}=3ZD5HI_w`8py zv&4;IpWg<H{d&-}pj~IcBp9qTqD=el_NsKoT*Ti?Qd@EVLbN*%z-40^)7k}E0r>UG ziE~M*F#V)UEbhfnlBWJLSywj%VK30<^5lSLTCG-t496r0Vp2O_S-cM%V9`ZA0C(A5 z)xk9{NX(m3PTNn+(A9W)Ovnngb1t~I8Q@2-(?6#96g)4u2kGYP>vV%(IE+PW$lWzx zDiJY_{XPV|;l3WGGSg2#(B=KsGa^k=acviCu=!bZfo$r=#_A%@PUMRc>_^+q#-4*F zeWamY7;WFHfjAobk37aY#*!IhMygf>1ef&q!<Up_1~2!gCkbUpxOnyGk~Y-PCAde^ z5(}2ldAMCzJfXyTdoX_Wws9`Y(<Q73s_tAQ&i|+P<}ZL2Ikuk98JselKZUErh{g`8 zw|`b~33;Uxo(nH!_lyN*8oaIGI*}tbUVPr}3F-DqZGcpUF;vbvRlQHAIq23nS7hk2 zUwLihXTdTiRX6XnER(G3e<Y=lyNN+&;tt|cly(vx#U|8>jt9AaL_`ciRwp>38eR^x zRVN~lWBF2745eXB998RLiXAL7Fy#ow+HLcFZd-v0^Xmg9oGiBq#U%)Euc#NhJd1NX z;FS#Ia9pgUFlS2hS&ud*_+&h2cB(`o^G4vl^&ge~9<A(->9Z#rU#C-f2-iK4PnXey zClfEeCquKePyLooxxL(}-zb=H6f&eADXVK9%2U&Pf27`7OQBP8b4C(Fcu~4$5C!9x z_AcD^ux$C5b5}?c72WLdWV14FW%_&0C#b%COtUmH<-qXM`WkMNhYA#Dq{XU`xy-L_ zpz%@GE{+U%BgKuUfwSYf=4J~s!7$RC*`^)x^dK&^CASKr>v(WGuxNm>{K1jA;51@% zd=i&rS8Q>WnfT#UG}Wh^2MeQmw|+Jl$cpoD2x<$cHEb1+-3otJXGoomi>E<SN`mO> z;s#81*Pt3^&V1e6=+o=1;nFvX_gl8R(&~88#ZypI6&r_RVRksR*Q|}Wuhye{GpF<0 zc8{+Dc|vfJ_sUZcbN~v@NEsEzPnkvq7L|*P?{f05&5)HHKWn!RBhc+}7_|iTq`QF; zu8d+_<X%ZO<#MdZawqL;NAqjhAG0pqD3`sd+L}AfpQ^qbvZrZofjp_^Ktmuans);3 z&Se|G_hd*(uAw6>vh3|fV~seMHK#-2a?ZOz!|&}Y=}xR=MIwa?zJHg<3n<|W0~jCI z{BCf1oc?T&S_Xrw|G98eMYJ~o`tw<C$yt^?&Tm7F%cNl^+M0}bnyH^7uq&rxi67i6 zo8SStyNF-%rlNvk;5%mS8Uj6dv@&bSl!>z#;OU$@&ojzaV#9rkcIOX+Mqb%Tx4ubq z1Wx)bWmUoU_IX2z4|Ebo#_tR&f%^-uA`I!kH4|+$A{-kmR1+^pakE}yIY?2A|IN3d zs`K?<n}m{38&Rdi&TpOiFC5q*ccFdNuc4MO8gDUuyh~jajKY8z^o~Z>Kx$v2CM8yz zGS@husnYKSWFbp9uQ`$YXp{7iYp|2T8O*)OA8MVpoUrjcy7yvj2j8I`Vq~B`ihpK# zX!w538{GmTLJVUpb;}%AUc#jnZ&p9r7PrC<tEj6gMtnLq;obC}%1h9t$nxR=-tJOb zF8#y1AQ^O}LWdhcTQ%*{$dq-r-T9dLKVSKAL#iIp(s`Mh!D%F2`$}}kspa3-5;C8_ zVZ>1NbVvItoF|>6s%j(h@awVYdTn3a5h@H8m5^hMzCIo;PEAYlU##-sT<65sTD&Va zCnaqRwN7Yy>Y`bV?w%IDH#Vou%C%0MLKUR#RIxV#E0X4J&l(oWX9j{lHGlm(@Ju`R zW5sg5iBE$Wn_wC1MqZ|M&fFlNsKvcR?-<+5_bGJd#=B#Pu`*h%zC*~*=mDL`gU&c@ z?rPYF`o``Q;|<%`wB>r7)@&6fi?C(iA;C&FK83?Z`!vzQTH&>aSJ`e)(8PDD%f3@4 zlG3lX=kJsZ4V@W=t!C8Zay0$vO*$K@MqNrVQDVn!59TR_9?!ktaE_yM-%6IB`9%Yb z1Y1OnMqVM}gnJYcr8zb8GOiqjdQRiv#C#Eh&IALYdlo|zVxHU?3z(oI=r3P*G5E_t zQZiu^bJO0dP#T|<<kBqWCCRw)iS*r!id{+%3F&K;yis-L^$*Kx58>pA6XyN3Z;au% zxIC+&Y*d1idTx6_ZU_0n*INNvR`eCc7v^U-Ly^#YdN<PLP5*!`#;(!Bk5GK{7f2t2 zR5f=BkMv*6N4k#~-<pn2wOzi_6P6p0oJTP%8y%mpI;FT4^$BF{yu_K$*1{%1Hyn9~ zQb)~^IYK)iM<pf2Q}xxH;m3-3=#J0(tLIyTGFvuRW5YYP^p;!X;WdK}vKO*+9P-b) z7MG34dS)+=%&KuhdXA!IiQ=S%c;}6QUU(DpHM`GuaMSm-)-xQQwqvU+b3aaRmoM_( zFPlr4w~&ZrVMQFGbP*>qjdX~0<JUqj*6Lj&<QSQaUHII&B-p*j6&U@Ig&|6P#C`Fz z?;m3HG^lpJ2MYw(-CmY=9pQNz1=tG$@f!|+a-9Q968JwBP}j$AV?Jw?Sj=gJF;BYQ z3RwyApN>(P<JELP#E`#d9<HfXO{q68zI=wcbH68eCQZ)&6yje7avMo$dfPpH6(7Zl zG!gnnx7zS#MJ0lIFFSoTrSDDPHWdggw%M{gE(nHnG&@?nc#av((`8Dypl2`Q|7|L# zY){M!Y4SBFxW`?KoOpvPGE7R$qD0I#90RRj4s_ybNQzKh@Ym3dEt1Aij>6mKAXYb4 z&dBI`s+`@yKt+m-dF?}=osYCnJ|%6iefc&8-5tr%-BmSqK%;aV<|nx;=eC(tTfZj} zu{tE(#2kO~O|F2acCvR`FR0l+#!LL$#g@TNjh?r+3yl<l;KB#2u&adOSuhcj&B>p! z=XtWR<tp!0l2;JYDsZc*`f3sCYzw3F(mggP5~%!t#IpbilpsU`MgL&IKf?<m`yUM@ z1>hGT2@jx1!kzzTrv(4n>Bfw6k7rwT*S~g3h$I~8FYb?0Rt5H#NadbY$j;&SWHQH? zJ`GwkZ0H*it;rXs)ec)g;g`s<Lf`@wHj3^U2o}!EDd+9<XQ;E`wALhjmY?t?8Y0a7 zX9It`>j$0z<K5{9bFYi)vZ4g_4d+VhuU32`$T$Av{@-aL_M{L$OwILw#>TsqP?zA* z>PpNdWuE)<VqX@QC;KtlQorD5*6g;L|CJp*WC)AlGt6eG_Wtk*#2y|+7W^!irby9I z3s<y}mW(1J%8X3N(xthu71}{m5S51<(QpNYFFqwW7DIVj`Q3bv)BoUHS1AxZN!(7! zZ?Tu(5l6+vme~)%e$i4V&5}fT+}xDGSJ(IemlT-%1aaAE_$_lwcd1FsT_n?W=LFhH ziLfvLtfYldcRz44L6r4~u-y1=XIxKKBIZ$^(Kwrjn(>B-S_Khp2vtt`c{Bp%m|n|V z#kN52W+oVR_@Ek9{1f}iRy5AdS*Pp`f$95Oh2os&R*?%i-(p+%7EQ@wf{N>zVl;z% zL7cT-A9t`@jpFDZby}L~gQaTHHe`u*Gc^ztQbv!i7CGGk)?(4G2En@%glPw<^R)2R zt$E?TnIZx&Uc>ss1@p4HmVGAv%8OhU%nL0QuiZVR?vIt*wk1uY4DG$r&eW0KRwCLi z!hVJlvhAl-4}f7e2~pb&9SL6g2{DS=F3OdiA#-@CRg7x}Ch*1~JquBSH8%%lSkvJ4 zD_-QLZh8_>PA<Gtf^}lmmlQcsVeoaTGv7y0X^2aCVlpvtoVlT(FRa{|$gN|4_(`J> z_bH29MB1Gb=9b;PGRAoO<E4U|ZHDp`K-rZiuEq5Vrq8$0DCCA_U}LGgYs*i{lrDKO zi9b9~dsMvxcI&Hmvb1{c_5S+P%(i5eP+b<rftBcSeSQy`1;AKhysL*pV3`c4l#W%* z={M{<8X7j`@rKJmF6<SeDFM_9ObmsB*n1r+4beMO>((GHwkD<YF8h>%;ihnFj-!O_ zndGkfe+mSOq)PA>nROv0p+JhA>9)m3x5DG3@}pFTJYzA9510h9Eqjuis{Td{LZA8( zRr|RAE_DxikV68H$x-G6T<UpveZFVcue_Z4V3~UPjhvjQ+((!+5bNx7pVgz9z9L-M zH&kL_lNvmF-t5gr5VBUjPc2g{i%MZmq->*U`p|dAKQ;C+xcT^gDy`PG<s;a$ur*sb zqQKNbioAMNKa&uDA$2!U5xz;lQu_rLdSHYiTJ2?e6_&XN#1fI(`&&veJ7!!Bsd48E z1daRRPTn$67bkqk?#34lX0M1j8z|{KS?z|Ayn@p`Fr-I>myi4f(z)V@EQ<0sDYPAS z=fzeKSg{bi&WKyVackG#%f5^CcGkgT5)Tqi|4<kA({{O44cqua?w6dC9yOMgXT8xj zD49CN6)ImMm&i6=+?K4-FdJb{A#j*{d?ZAhMW_p;4P$5T&-zWApShTzJiEUp5z&F1 zd<&xv`5FpQ;oA`$e;+|j62=~RaqD!I3{36N81US`I|-Lg=7};EN<?OhcFo(2I`TfI z$6ys7O4h0kJ_PO#IK)b2&b&Ukpw0y>II8-8ITFDWd^lgixG>x+&$Iphr}c9Gyz3J> zlK|fEE^!_x*Z;O737t4SAuX#d%Tm|*Y5Q5Z;UJ2p^nfLGMII^+<$#iafI^f6_z)l- nA#J|)!OE23(Ua}T!MlHm;~}uz(myQ;uh8C`^y9()+minU{|(y8 diff --git a/builder/vsphere/test/test-key.pem b/builder/vsphere/test/test-key.pem deleted file mode 100644 index 8dad2ecd3..000000000 --- a/builder/vsphere/test/test-key.pem +++ /dev/null @@ -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----- diff --git a/builder/vsphere/test/test-key.pub b/builder/vsphere/test/test-key.pub deleted file mode 100644 index c4c14bb04..000000000 --- a/builder/vsphere/test/test-key.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYn3DdxuowlINMJS0VbepEeGqBdtI5bfZqeoRZBi9bjxYpcmZma65JWILS1wAwKdfym7lgaUAwKLlEEO12gT2ZnNQJ8ThDU6bjZLaMpGtJJuFT1OzyNNEvRXzVONrrhIS3mXV0MdLmyA0nLwLidZpahvUdP5iWg8SWWPzSiDChCgve5+mvmZ79M6sDcCkdd7BabR94GSSS43o2QvVn2wgsKy0uuMP5FUQ68j/CsdkRoulgng8uBLwuZM0poVp+arCBwLhVwDiRVuHHD1ffzm/6ZAuqmI4lr69LnV1Paog0TD7zRj4cvuTs4hlMuDzTfC5sjetRlD/Y9f9JMGrXM71H diff --git a/builder/vsphere/version/version.go b/builder/vsphere/version/version.go deleted file mode 100644 index 001eefe9c..000000000 --- a/builder/vsphere/version/version.go +++ /dev/null @@ -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) -} diff --git a/command/plugin.go b/command/plugin.go index 57ccbf1d2..f5bb2ab61 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -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), } diff --git a/post-processor/vsphere-template/post-processor.go b/post-processor/vsphere-template/post-processor.go deleted file mode 100644 index 852ce677f..000000000 --- a/post-processor/vsphere-template/post-processor.go +++ /dev/null @@ -1,153 +0,0 @@ -//go:generate mapstructure-to-hcl2 -type Config - -package vsphere_template - -import ( - "context" - "errors" - "fmt" - "net/url" - "strings" - "time" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/common" - "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-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" - vmwcommon "github.com/hashicorp/packer/builder/vmware/common" - vsphere "github.com/hashicorp/packer/builder/vsphere/common" - "github.com/hashicorp/packer/post-processor/artifice" - vspherepost "github.com/hashicorp/packer/post-processor/vsphere" - "github.com/vmware/govmomi" -) - -var builtins = map[string]string{ - vspherepost.BuilderId: "vmware", - vmwcommon.BuilderIdESX: "vmware", - vsphere.BuilderId: "vsphere", - artifice.BuilderId: "artifice", -} - -type Config struct { - common.PackerConfig `mapstructure:",squash"` - Host string `mapstructure:"host"` - Insecure bool `mapstructure:"insecure"` - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` - Datacenter string `mapstructure:"datacenter"` - Folder string `mapstructure:"folder"` - SnapshotEnable bool `mapstructure:"snapshot_enable"` - SnapshotName string `mapstructure:"snapshot_name"` - SnapshotDescription string `mapstructure:"snapshot_description"` - ReregisterVM config.Trilean `mapstructure:"reregister_vm"` - - ctx interpolate.Context -} - -type PostProcessor struct { - config Config - url *url.URL -} - -func (p *PostProcessor) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() } - -func (p *PostProcessor) Configure(raws ...interface{}) error { - err := config.Decode(&p.config, &config.DecodeOpts{ - PluginType: vsphere.BuilderId, - Interpolate: true, - InterpolateContext: &p.config.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{}, - }, - }, raws...) - - if err != nil { - return err - } - - errs := new(packersdk.MultiError) - vc := map[string]*string{ - "host": &p.config.Host, - "username": &p.config.Username, - "password": &p.config.Password, - } - - for key, ptr := range vc { - if *ptr == "" { - errs = packersdk.MultiErrorAppend( - errs, fmt.Errorf("%s must be set", key)) - } - } - - if p.config.Folder != "" && !strings.HasPrefix(p.config.Folder, "/") { - errs = packersdk.MultiErrorAppend( - errs, fmt.Errorf("Folder must be bound to the root")) - } - - sdk, err := url.Parse(fmt.Sprintf("https://%v/sdk", p.config.Host)) - if err != nil { - errs = packersdk.MultiErrorAppend( - errs, fmt.Errorf("Error invalid vSphere sdk endpoint: %s", err)) - return errs - } - - sdk.User = url.UserPassword(p.config.Username, p.config.Password) - p.url = sdk - - if len(errs.Errors) > 0 { - return errs - } - return nil -} - -func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifact packersdk.Artifact) (packersdk.Artifact, bool, bool, error) { - if _, ok := builtins[artifact.BuilderId()]; !ok { - return nil, false, false, fmt.Errorf("The Packer vSphere Template post-processor "+ - "can only take an artifact from the VMware-iso builder, built on "+ - "ESXi (i.e. remote) or an artifact from the vSphere post-processor. "+ - "Artifact type %s does not fit this requirement", artifact.BuilderId()) - } - - f := artifact.State(vmwcommon.ArtifactConfFormat) - k := artifact.State(vmwcommon.ArtifactConfKeepRegistered) - s := artifact.State(vmwcommon.ArtifactConfSkipExport) - - if f != "" && k != "true" && s == "false" { - return nil, false, false, errors.New("To use this post-processor with exporting behavior you need set keep_registered as true") - } - - // In some occasions the VM state is powered on and if we immediately try to mark as template - // (after the ESXi creates it) it will fail. If vSphere is given a few seconds this behavior doesn't reappear. - ui.Message("Waiting 10s for VMware vSphere to start") - time.Sleep(10 * time.Second) - c, err := govmomi.NewClient(context.Background(), p.url, p.config.Insecure) - if err != nil { - return nil, false, false, fmt.Errorf("Error connecting to vSphere: %s", err) - } - - defer c.Logout(context.Background()) - - state := new(multistep.BasicStateBag) - state.Put("ui", ui) - state.Put("client", c) - - steps := []multistep.Step{ - &stepChooseDatacenter{ - Datacenter: p.config.Datacenter, - }, - &stepCreateFolder{ - Folder: p.config.Folder, - }, - NewStepCreateSnapshot(artifact, p), - NewStepMarkAsTemplate(artifact, p), - } - runner := commonsteps.NewRunnerWithPauseFn(steps, p.config.PackerConfig, ui, state) - runner.Run(ctx, state) - if rawErr, ok := state.GetOk("error"); ok { - return nil, false, false, rawErr.(error) - } - return artifact, true, true, nil -} diff --git a/post-processor/vsphere-template/post-processor.hcl2spec.go b/post-processor/vsphere-template/post-processor.hcl2spec.go deleted file mode 100644 index 214568087..000000000 --- a/post-processor/vsphere-template/post-processor.hcl2spec.go +++ /dev/null @@ -1,65 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT. - -package vsphere_template - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - Host *string `mapstructure:"host" cty:"host" hcl:"host"` - Insecure *bool `mapstructure:"insecure" cty:"insecure" hcl:"insecure"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"` - Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"` - SnapshotEnable *bool `mapstructure:"snapshot_enable" cty:"snapshot_enable" hcl:"snapshot_enable"` - SnapshotName *string `mapstructure:"snapshot_name" cty:"snapshot_name" hcl:"snapshot_name"` - SnapshotDescription *string `mapstructure:"snapshot_description" cty:"snapshot_description" hcl:"snapshot_description"` - ReregisterVM *bool `mapstructure:"reregister_vm" cty:"reregister_vm" hcl:"reregister_vm"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "host": &hcldec.AttrSpec{Name: "host", Type: cty.String, Required: false}, - "insecure": &hcldec.AttrSpec{Name: "insecure", Type: cty.Bool, Required: false}, - "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "datacenter": &hcldec.AttrSpec{Name: "datacenter", Type: cty.String, Required: false}, - "folder": &hcldec.AttrSpec{Name: "folder", Type: cty.String, Required: false}, - "snapshot_enable": &hcldec.AttrSpec{Name: "snapshot_enable", Type: cty.Bool, Required: false}, - "snapshot_name": &hcldec.AttrSpec{Name: "snapshot_name", Type: cty.String, Required: false}, - "snapshot_description": &hcldec.AttrSpec{Name: "snapshot_description", Type: cty.String, Required: false}, - "reregister_vm": &hcldec.AttrSpec{Name: "reregister_vm", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/post-processor/vsphere-template/post-processor_test.go b/post-processor/vsphere-template/post-processor_test.go deleted file mode 100644 index b1f682d60..000000000 --- a/post-processor/vsphere-template/post-processor_test.go +++ /dev/null @@ -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.") - } -} diff --git a/post-processor/vsphere-template/step_choose_datacenter.go b/post-processor/vsphere-template/step_choose_datacenter.go deleted file mode 100644 index 6645c4dc5..000000000 --- a/post-processor/vsphere-template/step_choose_datacenter.go +++ /dev/null @@ -1,35 +0,0 @@ -package vsphere_template - -import ( - "context" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/vmware/govmomi" - "github.com/vmware/govmomi/find" -) - -type stepChooseDatacenter struct { - Datacenter string -} - -func (s *stepChooseDatacenter) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - cli := state.Get("client").(*govmomi.Client) - finder := find.NewFinder(cli.Client, false) - - ui.Message("Choosing datacenter...") - - dc, err := finder.DatacenterOrDefault(context.Background(), s.Datacenter) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - state.Put("dcPath", dc.InventoryPath) - - return multistep.ActionContinue -} - -func (s *stepChooseDatacenter) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/step_create_folder.go b/post-processor/vsphere-template/step_create_folder.go deleted file mode 100644 index 282848434..000000000 --- a/post-processor/vsphere-template/step_create_folder.go +++ /dev/null @@ -1,86 +0,0 @@ -package vsphere_template - -import ( - "context" - "fmt" - "path" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/vmware/govmomi" - "github.com/vmware/govmomi/object" -) - -type stepCreateFolder struct { - Folder string -} - -func (s *stepCreateFolder) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - cli := state.Get("client").(*govmomi.Client) - dcPath := state.Get("dcPath").(string) - - ui.Message("Creating or checking destination folders...") - - base := path.Join(dcPath, "vm") - fullPath := path.Join(base, s.Folder) - si := object.NewSearchIndex(cli.Client) - - var folders []string - var err error - var ref object.Reference - - // We iterate over the path starting with full path - // If we don't find it, we save the folder name and continue with the previous path - // The iteration ends when we find an existing path otherwise it throws error - for { - ref, err = si.FindByInventoryPath(context.Background(), fullPath) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if ref == nil { - dir, folder := path.Split(fullPath) - fullPath = path.Clean(dir) - - if fullPath == dcPath { - err = fmt.Errorf("vSphere base path %s not found", base) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - folders = append(folders, folder) - } else { - break - } - } - - if root, ok := ref.(*object.Folder); ok { - for i := len(folders) - 1; i >= 0; i-- { - ui.Message(fmt.Sprintf("Creating folder: %v", folders[i])) - - root, err = root.CreateFolder(context.Background(), folders[i]) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - fullPath = path.Join(fullPath, folders[i]) - } - root.SetInventoryPath(fullPath) - state.Put("folder", root) - } else { - err = fmt.Errorf("folder not found: '%v'", ref) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *stepCreateFolder) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/step_create_snapshot.go b/post-processor/vsphere-template/step_create_snapshot.go deleted file mode 100644 index da815abb3..000000000 --- a/post-processor/vsphere-template/step_create_snapshot.go +++ /dev/null @@ -1,76 +0,0 @@ -package vsphere_template - -import ( - "context" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer/post-processor/vsphere" - "github.com/vmware/govmomi" -) - -type stepCreateSnapshot struct { - VMName string - RemoteFolder string - SnapshotName string - SnapshotDescription string - SnapshotEnable bool -} - -func NewStepCreateSnapshot(artifact packersdk.Artifact, p *PostProcessor) *stepCreateSnapshot { - remoteFolder := "Discovered virtual machine" - vmname := artifact.Id() - - if artifact.BuilderId() == vsphere.BuilderId { - id := strings.Split(artifact.Id(), "::") - remoteFolder = id[1] - vmname = id[2] - } - - return &stepCreateSnapshot{ - VMName: vmname, - RemoteFolder: remoteFolder, - SnapshotEnable: p.config.SnapshotEnable, - SnapshotName: p.config.SnapshotName, - SnapshotDescription: p.config.SnapshotDescription, - } -} - -func (s *stepCreateSnapshot) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - cli := state.Get("client").(*govmomi.Client) - dcPath := state.Get("dcPath").(string) - - if !s.SnapshotEnable { - return multistep.ActionContinue - } - - ui.Message("Creating a Snapshot...") - - vm, err := findRuntimeVM(cli, dcPath, s.VMName, s.RemoteFolder) - - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - task, err := vm.CreateSnapshot(context.Background(), s.SnapshotName, s.SnapshotDescription, false, false) - - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if err = task.Wait(context.Background()); err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *stepCreateSnapshot) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/step_mark_as_template.go b/post-processor/vsphere-template/step_mark_as_template.go deleted file mode 100644 index 6b5bc81ce..000000000 --- a/post-processor/vsphere-template/step_mark_as_template.go +++ /dev/null @@ -1,186 +0,0 @@ -package vsphere_template - -import ( - "context" - "fmt" - "path" - "regexp" - "strings" - - "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/post-processor/vsphere" - "github.com/vmware/govmomi" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/types" -) - -type stepMarkAsTemplate struct { - VMName string - RemoteFolder string - ReregisterVM config.Trilean -} - -func NewStepMarkAsTemplate(artifact packersdk.Artifact, p *PostProcessor) *stepMarkAsTemplate { - remoteFolder := "Discovered virtual machine" - vmname := artifact.Id() - - if artifact.BuilderId() == vsphere.BuilderId { - id := strings.Split(artifact.Id(), "::") - remoteFolder = id[1] - vmname = id[2] - } - - return &stepMarkAsTemplate{ - VMName: vmname, - RemoteFolder: remoteFolder, - ReregisterVM: p.config.ReregisterVM, - } -} - -func (s *stepMarkAsTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - cli := state.Get("client").(*govmomi.Client) - folder := state.Get("folder").(*object.Folder) - dcPath := state.Get("dcPath").(string) - - vm, err := findRuntimeVM(cli, dcPath, s.VMName, s.RemoteFolder) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // Use a simple "MarkAsTemplate" method unless `reregister_vm` is true - if s.ReregisterVM.False() { - ui.Message("Marking as a template...") - - if err := vm.MarkAsTemplate(context.Background()); err != nil { - state.Put("error", err) - ui.Error("vm.MarkAsTemplate:" + err.Error()) - return multistep.ActionHalt - } - return multistep.ActionContinue - } - - ui.Message("Re-register VM as a template...") - - dsPath, err := datastorePath(vm) - if err != nil { - state.Put("error", err) - ui.Error("datastorePath:" + err.Error()) - return multistep.ActionHalt - } - - host, err := vm.HostSystem(context.Background()) - if err != nil { - state.Put("error", err) - ui.Error("vm.HostSystem:" + err.Error()) - return multistep.ActionHalt - } - - if err := vm.Unregister(context.Background()); err != nil { - state.Put("error", err) - ui.Error("vm.Unregister:" + err.Error()) - return multistep.ActionHalt - } - - if err := unregisterPreviousVM(cli, folder, s.VMName); err != nil { - state.Put("error", err) - ui.Error("unregisterPreviousVM:" + err.Error()) - return multistep.ActionHalt - } - - task, err := folder.RegisterVM(context.Background(), dsPath.String(), s.VMName, true, nil, host) - if err != nil { - state.Put("error", err) - ui.Error("RegisterVM:" + err.Error()) - return multistep.ActionHalt - } - - if err = task.Wait(context.Background()); err != nil { - state.Put("error", err) - ui.Error("task.Wait:" + err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func datastorePath(vm *object.VirtualMachine) (*object.DatastorePath, error) { - devices, err := vm.Device(context.Background()) - if err != nil { - return nil, err - } - - disk := "" - for _, device := range devices { - if d, ok := device.(*types.VirtualDisk); ok { - if b, ok := d.Backing.(types.BaseVirtualDeviceFileBackingInfo); ok { - disk = b.GetVirtualDeviceFileBackingInfo().FileName - } - break - } - } - - if disk == "" { - return nil, fmt.Errorf("disk not found in '%v'", vm.Name()) - } - - re := regexp.MustCompile("\\[(.*?)\\]") - - datastore := re.FindStringSubmatch(disk)[1] - vmxPath := path.Join("/", path.Dir(strings.Split(disk, " ")[1]), vm.Name()+".vmx") - - return &object.DatastorePath{ - Datastore: datastore, - Path: vmxPath, - }, nil -} - -func findRuntimeVM(cli *govmomi.Client, dcPath, name, remoteFolder string) (*object.VirtualMachine, error) { - si := object.NewSearchIndex(cli.Client) - fullPath := path.Join(dcPath, "vm", remoteFolder, name) - - ref, err := si.FindByInventoryPath(context.Background(), fullPath) - if err != nil { - return nil, err - } - - if ref == nil { - return nil, fmt.Errorf("VM at path %s not found", fullPath) - } - - vm := ref.(*object.VirtualMachine) - if vm.InventoryPath == "" { - vm.SetInventoryPath(fullPath) - } - - return vm, nil -} - -// If in the target folder a virtual machine or template already exists -// it will be removed to maintain consistency -func unregisterPreviousVM(cli *govmomi.Client, folder *object.Folder, name string) error { - si := object.NewSearchIndex(cli.Client) - fullPath := path.Join(folder.InventoryPath, name) - - ref, err := si.FindByInventoryPath(context.Background(), fullPath) - if err != nil { - return err - } - - if ref != nil { - if vm, ok := ref.(*object.VirtualMachine); ok { - return vm.Unregister(context.Background()) - } else { - return fmt.Errorf("an object name '%v' already exists", name) - } - - } - - return nil -} - -func (s *stepMarkAsTemplate) Cleanup(multistep.StateBag) {} diff --git a/post-processor/vsphere-template/version/version.go b/post-processor/vsphere-template/version/version.go deleted file mode 100644 index 46226fc6e..000000000 --- a/post-processor/vsphere-template/version/version.go +++ /dev/null @@ -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) -} diff --git a/post-processor/vsphere/artifact.go b/post-processor/vsphere/artifact.go deleted file mode 100644 index 90e475a28..000000000 --- a/post-processor/vsphere/artifact.go +++ /dev/null @@ -1,47 +0,0 @@ -package vsphere - -import ( - "fmt" -) - -const BuilderId = "packer.post-processor.vsphere" - -type Artifact struct { - files []string - datastore string - vmfolder string - vmname string -} - -func NewArtifact(datastore, vmfolder, vmname string, files []string) *Artifact { - return &Artifact{ - files: files, - datastore: datastore, - vmfolder: vmfolder, - vmname: vmname, - } -} - -func (*Artifact) BuilderId() string { - return BuilderId -} - -func (a *Artifact) Files() []string { - return a.files -} - -func (a *Artifact) Id() string { - return fmt.Sprintf("%s::%s::%s", a.datastore, a.vmfolder, a.vmname) -} - -func (a *Artifact) String() string { - return fmt.Sprintf("VM: %s Folder: %s Datastore: %s", a.vmname, a.vmfolder, a.datastore) -} - -func (*Artifact) State(name string) interface{} { - return nil -} - -func (a *Artifact) Destroy() error { - return nil -} diff --git a/post-processor/vsphere/artifact_test.go b/post-processor/vsphere/artifact_test.go deleted file mode 100644 index c5cf8c9cc..000000000 --- a/post-processor/vsphere/artifact_test.go +++ /dev/null @@ -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") - } -} diff --git a/post-processor/vsphere/post-processor.go b/post-processor/vsphere/post-processor.go deleted file mode 100644 index 827ad7273..000000000 --- a/post-processor/vsphere/post-processor.go +++ /dev/null @@ -1,280 +0,0 @@ -//go:generate mapstructure-to-hcl2 -type Config - -package vsphere - -import ( - "bytes" - "context" - "fmt" - "log" - "net/url" - "os/exec" - "regexp" - "runtime" - "strings" - "time" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/common" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - shelllocal "github.com/hashicorp/packer-plugin-sdk/shell-local" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -var ovftool string = "ovftool" - -var ( - // Regular expression to validate RFC1035 hostnames from full fqdn or simple hostname. - // For example "packer-esxi1". Requires proper DNS setup and/or correct DNS search domain setting. - hostnameRegex = regexp.MustCompile(`^[[:alnum:]][[:alnum:]\-]{0,61}[[:alnum:]]|[[:alpha:]]$`) - - // Simple regular expression to validate IPv4 values. - // For example "192.168.1.1". - ipv4Regex = regexp.MustCompile(`^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`) -) - -type Config struct { - common.PackerConfig `mapstructure:",squash"` - - Cluster string `mapstructure:"cluster"` - Datacenter string `mapstructure:"datacenter"` - Datastore string `mapstructure:"datastore"` - DiskMode string `mapstructure:"disk_mode"` - Host string `mapstructure:"host"` - ESXiHost string `mapstructure:"esxi_host"` - Insecure bool `mapstructure:"insecure"` - Options []string `mapstructure:"options"` - Overwrite bool `mapstructure:"overwrite"` - Password string `mapstructure:"password"` - ResourcePool string `mapstructure:"resource_pool"` - Username string `mapstructure:"username"` - VMFolder string `mapstructure:"vm_folder"` - VMName string `mapstructure:"vm_name"` - VMNetwork string `mapstructure:"vm_network"` - - ctx interpolate.Context -} - -type PostProcessor struct { - config Config -} - -func (p *PostProcessor) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() } - -func (p *PostProcessor) Configure(raws ...interface{}) error { - err := config.Decode(&p.config, &config.DecodeOpts{ - PluginType: BuilderId, - Interpolate: true, - InterpolateContext: &p.config.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{}, - }, - }, raws...) - if err != nil { - return err - } - - // Defaults - if p.config.DiskMode == "" { - p.config.DiskMode = "thick" - } - - // Accumulate any errors - errs := new(packersdk.MultiError) - - if runtime.GOOS == "windows" { - ovftool = "ovftool.exe" - } - - if _, err := exec.LookPath(ovftool); err != nil { - errs = packersdk.MultiErrorAppend( - errs, fmt.Errorf("ovftool not found: %s", err)) - } - - // First define all our templatable parameters that are _required_ - templates := map[string]*string{ - "cluster": &p.config.Cluster, - "datacenter": &p.config.Datacenter, - "diskmode": &p.config.DiskMode, - "host": &p.config.Host, - "password": &p.config.Password, - "username": &p.config.Username, - "vm_name": &p.config.VMName, - } - for key, ptr := range templates { - if *ptr == "" { - errs = packersdk.MultiErrorAppend( - errs, fmt.Errorf("%s must be set", key)) - } - } - - if len(errs.Errors) > 0 { - return errs - } - - return nil -} - -func (p *PostProcessor) generateURI() (*url.URL, error) { - // use net/url lib to encode and escape url elements - ovftool_uri := fmt.Sprintf("vi://%s/%s/host/%s", - p.config.Host, - p.config.Datacenter, - p.config.Cluster) - - if p.config.ResourcePool != "" { - ovftool_uri += "/Resources/" + p.config.ResourcePool - } - - u, err := url.Parse(ovftool_uri) - if err != nil { - return nil, fmt.Errorf("Couldn't generate uri for ovftool: %s", err) - } - u.User = url.UserPassword(p.config.Username, p.config.Password) - - if p.config.ESXiHost != "" { - q := u.Query() - if ipv4Regex.MatchString(p.config.ESXiHost) { - q.Add("ip", p.config.ESXiHost) - } else if hostnameRegex.MatchString(p.config.ESXiHost) { - q.Add("dns", p.config.ESXiHost) - } - u.RawQuery = q.Encode() - } - return u, nil -} - -func getEncodedPassword(u *url.URL) (string, bool) { - // filter password from all logging - password, passwordSet := u.User.Password() - if passwordSet && password != "" { - encodedPassword := strings.Split(u.User.String(), ":")[1] - return encodedPassword, true - } - return password, false -} - -func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifact packersdk.Artifact) (packersdk.Artifact, bool, bool, error) { - source := "" - for _, path := range artifact.Files() { - if strings.HasSuffix(path, ".vmx") || strings.HasSuffix(path, ".ovf") || strings.HasSuffix(path, ".ova") { - source = path - break - } - } - - if source == "" { - return nil, false, false, fmt.Errorf("VMX, OVF or OVA file not found") - } - - ovftool_uri, err := p.generateURI() - if err != nil { - return nil, false, false, err - } - encodedPassword, isSet := getEncodedPassword(ovftool_uri) - if isSet { - packersdk.LogSecretFilter.Set(encodedPassword) - } - - args, err := p.BuildArgs(source, ovftool_uri.String()) - if err != nil { - ui.Message(fmt.Sprintf("Failed: %s\n", err)) - } - - ui.Message(fmt.Sprintf("Uploading %s to vSphere", source)) - - log.Printf("Starting ovftool with parameters: %s", strings.Join(args, " ")) - - ui.Message("Validating Username and Password with dry-run") - err = p.ValidateOvfTool(args, ovftool) - if err != nil { - return nil, false, false, err - } - - // Validation has passed, so run for real. - ui.Message("Calling OVFtool to upload vm") - commandAndArgs := []string{ovftool} - commandAndArgs = append(commandAndArgs, args...) - comm := &shelllocal.Communicator{ - ExecuteCommand: commandAndArgs, - } - flattenedCmd := strings.Join(commandAndArgs, " ") - cmd := &packersdk.RemoteCmd{Command: flattenedCmd} - log.Printf("[INFO] (vsphere): starting ovftool command: %s", flattenedCmd) - err = cmd.RunWithUi(ctx, comm, ui) - if err != nil || cmd.ExitStatus() != 0 { - return nil, false, false, fmt.Errorf( - "Error uploading virtual machine: Please see output above for more information.") - } - - artifact = NewArtifact(p.config.Datastore, p.config.VMFolder, p.config.VMName, artifact.Files()) - - return artifact, false, false, nil -} - -func (p *PostProcessor) ValidateOvfTool(args []string, ofvtool string) error { - args = append([]string{"--verifyOnly"}, args...) - var out bytes.Buffer - cmdCtx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - defer cancel() - cmd := exec.CommandContext(cmdCtx, ovftool, args...) - cmd.Stdout = &out - - // Need to manually close stdin or else the ofvtool call will hang - // forever in a situation where the user has provided an invalid - // password or username - stdin, err := cmd.StdinPipe() - if err != nil { - return err - } - defer stdin.Close() - - if err := cmd.Run(); err != nil { - outString := out.String() - if strings.Contains(outString, "Enter login information for") { - err = fmt.Errorf("Error performing OVFtool dry run; the username " + - "or password you provided to ovftool is likely invalid.") - return err - } - return nil - } - return nil -} - -func (p *PostProcessor) BuildArgs(source, ovftool_uri string) ([]string, error) { - args := []string{ - "--acceptAllEulas", - fmt.Sprintf(`--name=%s`, p.config.VMName), - fmt.Sprintf(`--datastore=%s`, p.config.Datastore), - } - - if p.config.Insecure { - args = append(args, fmt.Sprintf(`--noSSLVerify=%t`, p.config.Insecure)) - } - - if p.config.DiskMode != "" { - args = append(args, fmt.Sprintf(`--diskMode=%s`, p.config.DiskMode)) - } - - if p.config.VMFolder != "" { - args = append(args, fmt.Sprintf(`--vmFolder=%s`, p.config.VMFolder)) - } - - if p.config.VMNetwork != "" { - args = append(args, fmt.Sprintf(`--network=%s`, p.config.VMNetwork)) - } - - if p.config.Overwrite == true { - args = append(args, "--overwrite") - } - - if len(p.config.Options) > 0 { - args = append(args, p.config.Options...) - } - - args = append(args, source) - args = append(args, ovftool_uri) - - return args, nil -} diff --git a/post-processor/vsphere/post-processor.hcl2spec.go b/post-processor/vsphere/post-processor.hcl2spec.go deleted file mode 100644 index da4d82973..000000000 --- a/post-processor/vsphere/post-processor.hcl2spec.go +++ /dev/null @@ -1,75 +0,0 @@ -// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT. - -package vsphere - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"` - Datacenter *string `mapstructure:"datacenter" cty:"datacenter" hcl:"datacenter"` - Datastore *string `mapstructure:"datastore" cty:"datastore" hcl:"datastore"` - DiskMode *string `mapstructure:"disk_mode" cty:"disk_mode" hcl:"disk_mode"` - Host *string `mapstructure:"host" cty:"host" hcl:"host"` - ESXiHost *string `mapstructure:"esxi_host" cty:"esxi_host" hcl:"esxi_host"` - Insecure *bool `mapstructure:"insecure" cty:"insecure" hcl:"insecure"` - Options []string `mapstructure:"options" cty:"options" hcl:"options"` - Overwrite *bool `mapstructure:"overwrite" cty:"overwrite" hcl:"overwrite"` - Password *string `mapstructure:"password" cty:"password" hcl:"password"` - ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool" hcl:"resource_pool"` - Username *string `mapstructure:"username" cty:"username" hcl:"username"` - VMFolder *string `mapstructure:"vm_folder" cty:"vm_folder" hcl:"vm_folder"` - VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"` - VMNetwork *string `mapstructure:"vm_network" cty:"vm_network" hcl:"vm_network"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "cluster": &hcldec.AttrSpec{Name: "cluster", Type: cty.String, Required: false}, - "datacenter": &hcldec.AttrSpec{Name: "datacenter", Type: cty.String, Required: false}, - "datastore": &hcldec.AttrSpec{Name: "datastore", Type: cty.String, Required: false}, - "disk_mode": &hcldec.AttrSpec{Name: "disk_mode", Type: cty.String, Required: false}, - "host": &hcldec.AttrSpec{Name: "host", Type: cty.String, Required: false}, - "esxi_host": &hcldec.AttrSpec{Name: "esxi_host", Type: cty.String, Required: false}, - "insecure": &hcldec.AttrSpec{Name: "insecure", Type: cty.Bool, Required: false}, - "options": &hcldec.AttrSpec{Name: "options", Type: cty.List(cty.String), Required: false}, - "overwrite": &hcldec.AttrSpec{Name: "overwrite", Type: cty.Bool, Required: false}, - "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, - "resource_pool": &hcldec.AttrSpec{Name: "resource_pool", Type: cty.String, Required: false}, - "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, - "vm_folder": &hcldec.AttrSpec{Name: "vm_folder", Type: cty.String, Required: false}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "vm_network": &hcldec.AttrSpec{Name: "vm_network", Type: cty.String, Required: false}, - } - return s -} diff --git a/post-processor/vsphere/post-processor_test.go b/post-processor/vsphere/post-processor_test.go deleted file mode 100644 index c666cb625..000000000 --- a/post-processor/vsphere/post-processor_test.go +++ /dev/null @@ -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") - } - -} diff --git a/post-processor/vsphere/version/version.go b/post-processor/vsphere/version/version.go deleted file mode 100644 index 5226fb020..000000000 --- a/post-processor/vsphere/version/version.go +++ /dev/null @@ -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) -} diff --git a/website/content/docs/builders/vmware/index.mdx b/website/content/docs/builders/vmware/index.mdx index 778f03745..58930e194 100644 --- a/website/content/docs/builders/vmware/index.mdx +++ b/website/content/docs/builders/vmware/index.mdx @@ -25,14 +25,3 @@ the following VMware builders: an existing VMware VM you want to use as the source. As an additional benefit, you can feed the artifact of this builder back into Packer to iterate on a machine. - -- [vsphere-iso](/docs/builders/vsphere-iso) - This builder starts from an - ISO file, but utilizes the vSphere API rather than the esxcli to build on a - remote esx instance. This allows you to build vms even if you do not have - SSH access to your vSphere cluster. - -- [vsphere-clone](/docs/builders/vsphere-clone) - This builder clones a - vm from an existing template, then modifies it and saves it as a new - template. It uses the vSphere API rather than the esxcli to build on a - remote esx instance. This allows you to build vms even if you do not have - SSH access to your vSphere cluster. diff --git a/website/content/docs/builders/vmware/vsphere-clone.mdx b/website/content/docs/builders/vmware/vsphere-clone.mdx deleted file mode 100644 index 0c817518c..000000000 --- a/website/content/docs/builders/vmware/vsphere-clone.mdx +++ /dev/null @@ -1,416 +0,0 @@ ---- -modeline: | - vim: set ft=pandoc: -description: > - This VMware Packer builder uses the vSphere API to clone an existing vSphere - template and create a new virtual machine remotely. -page_title: VSphere Clone - Builders ---- - -# VMWare Vsphere Clone Builder - -Type: `vsphere-clone` -Artifact BuilderId: `jetbrains.vsphere` - -This builder clones VMs from existing templates. - -- VMware Player is not required. -- It uses the official vCenter API, and does not require ESXi host [modification](/docs/builders/vmware-iso.html#building-on-a-remote-vsphere-hypervisor) -- This builder is supported for vSphere version 6.5 and greater. Builds on lower - versions may work, but some configuration options may throw errors because they - do not exist in the older versions of the vSphere API. - -## Examples - -See complete Ubuntu, Windows, and macOS templates in the [examples folder](https://github.com/hashicorp/packer/tree/master/builder/vsphere/examples/). - -## VSphere-Clone Configuration Reference - -There are many configuration options available for this builder. In addition to -the items listed here, you will want to look at the general configuration -references for [Hardware](#hardware-configuration), -[Output](#output-configuration), -[Boot](#boot-configuration), -[Run](#run-configuration), -[Shutdown](#shutdown-configuration), -[Communicator](#communicator-configuration), -[Export](#export-configuration), -configuration references, which are -necessary for this build to succeed and can be found further down the page. - -@include 'builder/vsphere/clone/Config-not-required.mdx' - -### Clone Configuration - -@include 'builder/vsphere/clone/CloneConfig-not-required.mdx' - -@include 'builder/vsphere/common/StorageConfig-not-required.mdx' - -### Storage Configuration - -When cloning a VM, the storage configuration can be used to add additional storage and disk controllers. The resulting VM -will contain the origin VM storage and disk controller plus the new configured ones. - -@include 'builder/vsphere/common/DiskConfig.mdx' - -@include 'builder/vsphere/common/DiskConfig-required.mdx' - -#### Optional - -@include 'builder/vsphere/common/DiskConfig-not-required.mdx' - -### vApp Options Configuration - -@include 'builder/vsphere/clone/vAppConfig-not-required.mdx' - -Example of usage: - -<Tabs> -<Tab heading="JSON"> - -```json - "vapp": { - "properties": { - "hostname": "{{ user `hostname`}}", - "user-data": "{{ env `USERDATA`}}" - } - } -``` - -A `user-data` field requires the content of a yaml file to be encoded with base64. This -can be done via environment variable: -`export USERDATA=$(gzip -c9 <userdata.yaml | { base64 -w0 2>/dev/null || base64; })` - -</Tab> -<Tab heading="HCL2"> - -```hcl - vapp { - properties = { - hostname = var.hostname - user-data = base64encode(var.user_data) - } - } -``` - -</Tab> -</Tabs> - -### Extra Configuration Parameters - -@include 'builder/vsphere/common/ConfigParamsConfig-not-required.mdx' - -### Customization - -@include '/builder/vsphere/clone/CustomizeConfig.mdx' - -@include 'builder/vsphere/clone/CustomizeConfig-not-required.mdx' - -#### Network Interface Settings - -@include 'builder/vsphere/clone/NetworkInterface-not-required.mdx' - -#### Global Routing Settings - -@include 'builder/vsphere/clone/GlobalRoutingSettings.mdx' - -@include 'builder/vsphere/clone/GlobalRoutingSettings-not-required.mdx' - -#### Global DNS Settings - -@include 'builder/vsphere/clone/GlobalDnsSettings.mdx' - -@include 'builder/vsphere/clone/GlobalDnsSettings-not-required.mdx' - -#### Linux Customization Settings - -@include 'builder/vsphere/clone/LinuxOptions-not-required.mdx' - -#### Customization Example - -<Tabs> -<Tab heading="JSON"> - -```json - "customize": { - "linux_options": { - "host_name": "packer-test", - "domain": "test.internal" - }, - "network_interface": { - "ipv4_address": "10.0.0.10", - "ipv4_netmask": "24" - }, - "ipv4_gateway": "10.0.0.1", - "dns_server_list": ["10.0.0.18"] - } -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl - customize { - linux_options { - host_name = "packer-test" - domain = "test.internal" - } - - network_interface { - ipv4_address = "10.0.0.10" - ipv4_netmask = "24" - } - - ipv4_gateway = 10.0.0.1 - dns_server_list = ["10.0.0.18"] - } -``` - -</Tab> -</Tabs> - -### Boot configuration - -@include 'packer-plugin-sdk/bootcommand/BootConfig.mdx' - -#### Optional: - -@include 'packer-plugin-sdk/bootcommand/BootConfig-not-required.mdx' - -@include 'builder/vsphere/common/BootConfig-not-required.mdx' - -### Http directory configuration - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig.mdx' - -#### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig-not-required.mdx' - -### Floppy configuration - -@include 'builder/vsphere/common/FloppyConfig-not-required.mdx' - -### Connection Configuration - -@include 'builder/vsphere/common/ConnectConfig-not-required.mdx' - -### Hardware Configuration - -@include 'builder/vsphere/common/HardwareConfig-not-required.mdx' - -### Location Configuration - -@include 'builder/vsphere/common/LocationConfig-not-required.mdx' - -### Run Configuration - -@include 'builder/vsphere/common/RunConfig-not-required.mdx' - -### Shutdown Configuration - -@include 'builder/vsphere/common/ShutdownConfig-not-required.mdx' - -### Wait Configuration - -@include 'builder/vsphere/common/WaitIpConfig-not-required.mdx' - -### CDRom Configuration - -@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig.mdx' - -#### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig-not-required.mdx' - -@include 'builder/vsphere/common/CDRomConfig-not-required.mdx' - -@include 'builder/vsphere/common/RemoveCDRomConfig-not-required.mdx' - -### Communicator configuration - -#### Optional common fields: - -@include 'packer-plugin-sdk/communicator/Config-not-required.mdx' - -#### Optional SSH fields: - -@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSHTemporaryKeyPair-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-Key-Pair-Name-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-Agent-Auth-not-required.mdx' - --> **NOTE:** Packer uses vApp Options to inject ssh public keys to the Virtual Machine. -The [temporary_key_pair_name](/docs/builders/vmware/vsphere-clone#temporary_key_pair_name) will only work -if the template being cloned contains the vApp property `public-keys`. -If using [ssh_private_key_file](/docs/builders/vmware/vsphere-clone#ssh_private_key_file), provide -the public key via [configuration_parameters](/docs/builders/vmware/vsphere-clone#configuration_parameters) or -[vApp Options Configuration](/docs/builders/vmware/vsphere-clone#vapp-options-configuration) whenever the `guestinto.userdata` -is available. See [VMware Guestinfo datasource](https://github.com/vmware/cloud-init-vmware-guestinfo) for more information -about the key. - -#### Optional WinRM fields: - -@include 'packer-plugin-sdk/communicator/WinRM-not-required.mdx' - -### Export Configuration - -@include 'builder/vsphere/common/ExportConfig.mdx' - -#### Optional: - -@include 'builder/vsphere/common/ExportConfig-not-required.mdx' - -#### Output Configuration: - -@include 'builder/vsphere/common/OutputConfig-not-required.mdx' - -### Content Library Import Configuration - -@include 'builder/vsphere/common/ContentLibraryDestinationConfig.mdx' - -@include 'builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx' - -Minimal example of usage: - -<Tabs> -<Tab heading="JSON"> - -```json - "content_library_destination" : { - "library": "Packer Library Test" - } -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl - content_library_destination { - library = "Packer Library Test" - } -``` - -</Tab> -</Tabs> - -## Working With Clusters And Hosts - -#### Standalone Hosts - -Only use the `host` option. Optionally specify a `resource_pool`: - -<Tabs> -<Tab heading="JSON"> - -```json -"host": "esxi-1.vsphere65.test", -"resource_pool": "pool1", -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -host = "esxi-1.vsphere65.test" -resource_pool = "pool1" -``` - -</Tab> -</Tabs> - -#### Clusters Without DRS - -Use the `cluster` and `host`parameters: - -<Tabs> -<Tab heading="JSON"> - -```json -"cluster": "cluster1", -"host": "esxi-2.vsphere65.test", -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -cluster = "cluster1" -host = "esxi-2.vsphere65.test" -``` - -</Tab> -</Tabs> - -#### Clusters With DRS - -Only use the `cluster` option. Optionally specify a `resource_pool`: - -<Tabs> -<Tab heading="JSON"> - -```json -"cluster": "cluster2", -"resource_pool": "pool1", -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -cluster = "cluster2" -resource_pool = "pool1" -``` - -</Tab> -</Tabs> - -## Required vSphere Permissions - -- VM folder (this object and children): - ```text - Virtual machine -> Inventory - Virtual machine -> Configuration - Virtual machine -> Interaction - Virtual machine -> Snapshot management - Virtual machine -> Provisioning - ``` - Individual privileges are listed in https://github.com/jetbrains-infra/packer-builder-vsphere/issues/97#issuecomment-436063235. -- Resource pool, host, or cluster (this object): - ```text - Resource -> Assign virtual machine to resource pool - ``` -- Host in clusters without DRS (this object): - ```text - Read-only - ``` -- Datastore (this object): - ```text - Datastore -> Allocate space - Datastore -> Browse datastore - Datastore -> Low level file operations - ``` -- Network (this object): - ```text - Network -> Assign network - ``` -- Distributed switch (this object): - ```text - Read-only - ``` - -For floppy image upload: - -- Datacenter (this object): - ```text - Datastore -> Low level file operations - ``` -- Host (this object): - ```text - Host -> Configuration -> System Management - ``` diff --git a/website/content/docs/builders/vmware/vsphere-iso.mdx b/website/content/docs/builders/vmware/vsphere-iso.mdx deleted file mode 100644 index c4b794bc2..000000000 --- a/website/content/docs/builders/vmware/vsphere-iso.mdx +++ /dev/null @@ -1,410 +0,0 @@ ---- -modeline: | - vim: set ft=pandoc: -description: | - This VMware Packer builder starts from an ISO and creates a vm using the - vSphere API to build on a remote VMWare machine. -page_title: VSphere ISO - Builders ---- - -# Packer Builder for VMware vSphere - -Type: `vsphere-iso` -Artifact BuilderId: `jetbrains.vsphere` - -This builder uses the vSphere API, and creates virtual machines remotely. It -starts from an ISO file and creates new VMs from scratch. - -- VMware Player is not required. -- It uses the official vCenter API, and does not require ESXi host [modification](/docs/builders/vmware-iso#building-on-a-remote-vsphere-hypervisor) -- This builder is supported for vSphere version 6.5 and greater. Builds on lower - versions may work, but some configuration options may throw errors because they - do not exist in the older versions of the vSphere API. - -## Examples - -See complete Ubuntu, Windows, and macOS templates in the [examples folder](https://github.com/hashicorp/packer/tree/master/builder/vsphere/examples/). - -# Configuration Reference - -There are many configuration options available for this builder. In addition to -the items listed here, you will want to look at the general configuration -references for [HTTP](#http-directory-configuration), -[Floppy](#floppy-configuration), -[Boot](#boot-configuration), -[Hardware](#hardware-configuration), -[Output](#output-configuration), -[Run](#run-configuration), -[Shutdown](#shutdown-configuration), -[Communicator](#communicator-configuration), -[Export](#export-configuration), -configuration references, which are -necessary for this build to succeed and can be found further down the page. - -@include 'builder/vsphere/iso/Config-not-required.mdx' - -### Boot Configuration - -@include 'packer-plugin-sdk/bootcommand/BootConfig.mdx' - -We send each character to the VM with a default delay of 100ms between groups. -The delay alleviates possible issues with latency and CPU -contention. If you notice missing keys, you can tune this delay by specifying -"boot_keygroup_interval" in your Packer template, for example: - -<Tabs> -<Tab heading="JSON"> - -```json -{ - "builders": [ - { - "type": "vsphere-iso", - "boot_keygroup_interval": "500ms" - ... - } - ] -} -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -source "vsphere-iso" "example" { - boot_keygroup_interval = "500ms" - # ... -} -``` - -</Tab> -</Tabs> - -#### Optional: - -@include 'packer-plugin-sdk/bootcommand/BootConfig-not-required.mdx' - -@include 'builder/vsphere/common/BootConfig-not-required.mdx' - -### Http directory configuration - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig.mdx' - -#### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig-not-required.mdx' - -### Floppy configuration - -@include 'builder/vsphere/common/FloppyConfig-not-required.mdx' - -### Connection Configuration - -@include 'builder/vsphere/common/ConnectConfig-not-required.mdx' - -### Hardware Configuration - -@include 'builder/vsphere/common/HardwareConfig-not-required.mdx' - -### Location Configuration - -@include 'builder/vsphere/common/LocationConfig-not-required.mdx' - -### Run Configuration - -@include 'builder/vsphere/common/RunConfig-not-required.mdx' - -### Shutdown Configuration - -@include 'builder/vsphere/common/ShutdownConfig-not-required.mdx' - -### Wait Configuration - -@include 'builder/vsphere/common/WaitIpConfig-not-required.mdx' - -### ISO Configuration - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig.mdx' - -#### Required: - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-required.mdx' - -#### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-not-required.mdx' - -### CDRom Configuration - -Each iso defined in the CDRom Configuration adds a new drive. If the "iso_url" is defined in -addition to the "iso_paths", the "iso_url" is added to the VM first. This keeps the "iso_url" first in -the boot order by default allowing the boot iso being defined by the iso_url and the vmware tools iso added -from the datastore. Example: - -<Tabs> -<Tab heading="JSON"> - -```json -"iso_urls": [ - "win10.iso", - "http://example.org/isos/win10.iso" -], -"iso_paths": [ - "[] /usr/lib/vmware/isoimages/windows.iso" -], -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -iso_urls = [ - "win10.iso", - "http://example.org/isos/win10.iso" -] - -iso_paths = [ - "[] /usr/lib/vmware/isoimages/windows.iso" -] -``` - -</Tab> -</Tabs> - -@include 'builder/vsphere/common/CDRomConfig-not-required.mdx' - -@include 'builder/vsphere/common/RemoveCDRomConfig-not-required.mdx' - -@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig.mdx' - -#### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig-not-required.mdx' - -### Create Configuration - -@include 'builder/vsphere/iso/CreateConfig-not-required.mdx' - -@include 'builder/vsphere/common/StorageConfig-not-required.mdx' - -### Network Adapter Configuration - -@include 'builder/vsphere/iso/NIC.mdx' - -@include 'builder/vsphere/iso/NIC-required.mdx' - -#### Optional - -@include 'builder/vsphere/iso/NIC-not-required.mdx' - -### Storage Configuration - -@include 'builder/vsphere/common/DiskConfig.mdx' - -@include 'builder/vsphere/common/DiskConfig-required.mdx' - -#### Optional - -@include 'builder/vsphere/common/DiskConfig-not-required.mdx' - -### Export Configuration - -@include 'builder/vsphere/common/ExportConfig.mdx' - -#### Optional: - -@include 'builder/vsphere/common/ExportConfig-not-required.mdx' - -#### Output Configuration: - -@include 'builder/vsphere/common/OutputConfig-not-required.mdx' - -### Content Library Import Configuration - -@include 'builder/vsphere/common/ContentLibraryDestinationConfig.mdx' - -@include 'builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx' - -Minimal example of usage to import a VM template: - -<Tabs> -<Tab heading="JSON"> - -```json - "content_library_destination" : { - "library": "Packer Library Test" - } -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl - content_library_destination { - library = "Packer Library Test" - } -``` - -</Tab> -</Tabs> - -Minimal example of usage to import a OVF template: - -<Tabs> -<Tab heading="JSON"> - -```json - "content_library_destination" : { - "library": "Packer Library Test", - "ovf": true - } -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl - content_library_destination { - library = "Packer Library Test" - ovf = true - } -``` - -</Tab> -</Tabs> - -### Extra Configuration Parameters - -@include 'builder/vsphere/common/ConfigParamsConfig-not-required.mdx' - -### Communicator configuration - -#### Optional common fields: - -@include 'packer-plugin-sdk/communicator/Config-not-required.mdx' - -#### Optional SSH fields: - -@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx' - -#### Optional WinRM fields: - -@include 'packer-plugin-sdk/communicator/WinRM-not-required.mdx' - -## Working With Clusters And Hosts - -#### Standalone Hosts - -Only use the `host` option. Optionally specify a `resource_pool`: - -<Tabs> -<Tab heading="JSON"> - -```json -"host": "esxi-1.vsphere65.test", -"resource_pool": "pool1", -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -host = ""esxi-1.vsphere65.test"" -resource_pool = "pool1" -``` - -</Tab> -</Tabs> - -#### Clusters Without DRS - -Use the `cluster` and `host`parameters: - -<Tabs> -<Tab heading="JSON"> - -```json -"cluster": "cluster1", -"host": "esxi-2.vsphere65.test", -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -cluster = "cluster1" -host = "esxi-2.vsphere65.test" -``` - -</Tab> -</Tabs> - -#### Clusters With DRS - -Only use the `cluster` option. Optionally specify a `resource_pool`: - -<Tabs> -<Tab heading="JSON"> - -```json -"cluster": "cluster2", -"resource_pool": "pool1", -``` - -</Tab> -<Tab heading="HCL2"> - -```hcl -cluster = "cluster2" -resource_pool = "pool1" -``` - -</Tab> -</Tabs> - -## Required vSphere Permissions - -- VM folder (this object and children): - ```text - Virtual machine -> Inventory - Virtual machine -> Configuration - Virtual machine -> Interaction - Virtual machine -> Snapshot management - Virtual machine -> Provisioning - ``` - Individual privileges are listed in https://github.com/jetbrains-infra/packer-builder-vsphere/issues/97#issuecomment-436063235. -- Resource pool, host, or cluster (this object): - ```text - Resource -> Assign virtual machine to resource pool - ``` -- Host in clusters without DRS (this object): - ```text - Read-only - ``` -- Datastore (this object): - ```text - Datastore -> Allocate space - Datastore -> Browse datastore - Datastore -> Low level file operations - ``` -- Network (this object): - ```text - Network -> Assign network - ``` -- Distributed switch (this object): - ```text - Read-only - ``` - -For floppy image upload: - -- Datacenter (this object): - ```text - Datastore -> Low level file operations - ``` -- Host (this object): - ```text - Host -> Configuration -> System Management - ``` diff --git a/website/content/docs/post-processors/vsphere-template.mdx b/website/content/docs/post-processors/vsphere-template.mdx deleted file mode 100644 index a401b99b1..000000000 --- a/website/content/docs/post-processors/vsphere-template.mdx +++ /dev/null @@ -1,168 +0,0 @@ ---- -description: > - The Packer vSphere Template post-processor takes an artifact from the - VMware-iso builder, built on ESXi (i.e. remote) or an artifact from the - [vSphere](/docs/post-processors/vsphere) post-processor, marks the VM as a - template, and leaves it in the path of your choice. -page_title: vSphere Template - Post-Processors ---- - -# vSphere Template Post-Processor - -Type: `vsphere-template` -Artifact BuilderId: `packer.post-processor.vsphere` - -The Packer vSphere Template post-processor takes an artifact from the -VMware-iso builder, built on ESXi (i.e. remote) or an artifact from the -[vSphere](/docs/post-processors/vsphere) post-processor, marks the VM as a -template, and leaves it in the path of your choice. - -## Example - -An example is shown below, showing only the post-processor configuration: - -```json -{ - "type": "vsphere-template", - "host": "vcenter.local", - "insecure": true, - "username": "root", - "password": "secret", - "datacenter": "mydatacenter", - "folder": "/packer-templates/os/distro-7" -} -``` - -## Configuration - -There are many configuration options available for the post-processor. They are -segmented below into two categories: required and optional parameters. Within -each category, the available configuration keys are alphabetized. - -Required: - -- `host` (string) - The vSphere host that contains the VM built by the - vmware-iso. - -- `password` (string) - Password to use to authenticate to the vSphere - endpoint. - -- `username` (string) - The username to use to authenticate to the vSphere - endpoint. - -Optional: - -- `datacenter` (string) - If you have more than one, you will need to specify - which one the ESXi used. - -- `folder` (string) - Target path where the template will be created. - -- `insecure` (boolean) - If it's true skip verification of server - certificate. Default is false - -- `keep_input_artifact` (boolean) - Unlike most post-processors, this option - has no effect for vsphere-template. This is because in order for a template - to work, you can't delete the vm that you generate the template from. The - vsphere template post-processor will therefore always preserve the original - vm. - -- `snapshot_enable` (boolean) - Create a snapshot before marking as a - template. Default is false - -- `snapshot_name` (string) - Name for the snapshot. Required when - `snapshot_enable` is `true` - -- `snapshot_description` (string) - Description for the snapshot. Required - when `snapshot_enable` is `true` - -- `reregister_vm` (boolean) - Use the method of unregister VM and reregister - as a template, rather than using the markAsTemplate method in vmWare. - NOTE: If you are getting permission denied errors when trying to mark as a - template, but it works fine in the vSphere UI, try setting this to `false`. - Default is `true`. - -## Using the vSphere Template with local builders - -Once the [vSphere](/docs/post-processors/vsphere) takes an artifact from -the VMware builder and uploads it to a vSphere endpoint, you will likely want -to mark that VM as template. Packer can do this for you automatically using a -sequence definition (a collection of post-processors that are treated as as -single pipeline, see [Post-Processors](/docs/templates/legacy_json_templates/post-processors) -for more information): - -```json -{ - "post-processors": [ - [ - { - "type": "vsphere", - ... - }, - { - "type": "vsphere-template", - ... - } - ], - { - "type": "...", - ... - } - ] -} -``` - -In the example above, the result of each builder is passed through the defined -sequence of post-processors starting with the `vsphere` post-processor which -will upload the artifact to a vSphere endpoint. The resulting artifact is then -passed on to the `vsphere-template` post-processor which handles marking a VM -as a template. Note that the `vsphere` and `vsphere-template` post-processors -are paired together in their own JSON array. - -## Permissions - -The vsphere post processor needs several permissions to be able to mark the -vm as a template. Rather than giving full administrator access, you can create -a role to give the post-processor the permissions necessary to run. Here is an -example role that will work. Please note that this is a user-supplied list so -there may be a few extraneous permissions that are not strictly required. - -For Vsphere 5.5 the role needs the following privileges: - - Datastore.AllocateSpace - Host.Config.AdvancedConfig - Host.Config.NetService - Host.Config.Network - Network.Assign - System.Anonymous - System.Read - System.View - VApp.Import - VirtualMachine.Config.AddNewDisk - VirtualMachine.Config.AdvancedConfig - VirtualMachine.Inventory.Delete - -and either (If reregister_vm is false): - - VirtualMachine.Provisioning.MarkAsTemplate - -or (if reregister_vm is true or unset): - - VirtualMachine.Inventory.Register - VirtualMachine.Inventory.Unregister - -And this role must be authorized on the: - - Cluster of the host - The destination folder (not on Datastore, on the Vsphere logical view) - The network to be assigned - The destination datastore. - -# Troubleshooting - -Some users have reported that vSphere templates created from local VMWare builds -get their boot order reset to cdrom only instead of the original boot order -defined by the template. If this issue affects you, the solution is to set -`"bios.hddOrder": "scsi0:0"` in your builder's `vmx_data`. - -Packer doesn't automatically do this for you because it causes strange upload -behavior in certain versions of `ovftool`. diff --git a/website/content/docs/post-processors/vsphere.mdx b/website/content/docs/post-processors/vsphere.mdx deleted file mode 100644 index dbf8629f0..000000000 --- a/website/content/docs/post-processors/vsphere.mdx +++ /dev/null @@ -1,180 +0,0 @@ ---- -description: > - The Packer vSphere post-processor takes an artifact and uploads it to a - vSphere endpoint. -page_title: vSphere - Post-Processors ---- - -# vSphere Post-Processor - -Type: `vsphere` -Artifact BuilderId: `packer.post-processor.vsphere` - -The Packer vSphere post-processor takes an artifact and uploads it to a vSphere endpoint. -The artifact must have a vmx/ova/ovf image. - -## Configuration - -There are many configuration options available for the post-processor. They are -segmented below into two categories: required and optional parameters. Within -each category, the available configuration keys are alphabetized. - -Required: - -- `cluster` (string) - The cluster or host to upload the VM to. This can be - either the name of the cluster, or the IP address of the esx host that you - want to upload to. - -- `datacenter` (string) - The name of the datacenter within vSphere to add - the VM to. - -- `datastore` (string) - The name of the datastore to store this VM. This is - _not required_ if `resource_pool` is specified. - -- `host` (string) - The vSphere host that will be contacted to perform the VM - upload. - -- `password` (string) - Password to use to authenticate to the vSphere - endpoint. - -- `username` (string) - The username to use to authenticate to the vSphere - endpoint. - -- `vm_name` (string) - The name of the VM once it is uploaded. - -Optional: - -- `esxi_host` (string) - Target vSphere host. Used to assign specific esx - host to upload the resulting VM to, when a vCenter Server is used as - `host`. Can be either a hostname (e.g. "packer-esxi1", requires proper DNS - setup and/or correct DNS search domain setting) or an IPv4 address. - -- `disk_mode` (string) - Target disk format. See `ovftool` manual for - available options. By default, `thick` will be used. - -- `insecure` (boolean) - Whether or not the connection to vSphere can be done - over an insecure connection. By default this is `false`. - -- `keep_input_artifact` (boolean) - When `true`, preserve the local VM files, - even after importing them to vsphere. Defaults to `false`. - -- `resource_pool` (string) - The resource pool to upload the VM to. - -- `vm_folder` (string) - The folder within the datastore to store the VM. - -- `vm_network` (string) - The name of the VM network this VM will be added - to. - -- `overwrite` (boolean) - If it's true force the system to overwrite the - existing files instead create new ones. Default is `false` - -- `options` (array of strings) - Custom options to add in `ovftool`. See - `ovftool --help` to list all the options - -# Example - -The following is an example of the vSphere post-processor being used in -conjunction with the null builder and artifice post-processor to upload a vmx -to a vSphere cluster. - -You can also use this post-processor with the vmx artifact from a vmware build. - -<Tabs> -<Tab heading="HCL2"> - -```hcl -source "null" "example" { - communicator = "none" -} - -build { - sources = [ - "source.null.example" - ] - - post-processors{ - post-processor "artifice"{ - files = ["output-vmware-iso/packer-vmware-iso.vmx"] - } - - post-processor "vsphere"{ - keep_input_artifact = true - vm_name = "packerparty" - vm_network = "VM Network" - cluster = "123.45.678.1" - datacenter = "PackerDatacenter" - datastore = "datastore1" - host = "123.45.678.9" - password = "SuperSecretPassword" - username = "Administrator@vsphere.local" - } - } -} -``` - -</Tab> -<Tab heading="JSON"> - -```json -{ - "builders": [ - { - "type": "null", - "communicator": "none" - } - ], - "post-processors": [ - [ - { - "type": "artifice", - "files": ["output-vmware-iso/packer-vmware-iso.vmx"] - }, - { - "type": "vsphere", - "keep_input_artifact": true, - "vm_name": "packerparty", - "vm_network": "VM Network", - "cluster": "123.45.678.1", - "datacenter": "PackerDatacenter", - "datastore": "datastore1", - "host": "123.45.678.9", - "password": "SuperSecretPassword", - "username": "Administrator@vsphere.local" - } - ] - ] -} -``` - -</Tab> -</Tabs> - -# Permissions - -The vsphere post processor uses `ovftool` and therefore needs the same privileges -as `ovftool`. Rather than giving full administrator access, you can create a role -to give the post-processor the permissions necessary to run. Below is an example -role. Please note that this is a user-supplied list so there may be a few -extraneous permissions that are not strictly required. - -For Vsphere 5.5 the role needs the following privileges: - - Datastore.AllocateSpace - Host.Config.AdvancedConfig - Host.Config.NetService - Host.Config.Network - Network.Assign - System.Anonymous - System.Read - System.View - VApp.Import - VirtualMachine.Config.AddNewDisk - VirtualMachine.Config.AdvancedConfig - VirtualMachine.Inventory.Delete - -And this role must be authorized on the: - - Cluster of the host - The destination folder (not on Datastore, on the Vsphere logical view) - The network to be assigned - The destination datastore. diff --git a/website/content/partials/builder/vsphere/clone/CloneConfig-not-required.mdx b/website/content/partials/builder/vsphere/clone/CloneConfig-not-required.mdx deleted file mode 100644 index d9ffbd790..000000000 --- a/website/content/partials/builder/vsphere/clone/CloneConfig-not-required.mdx +++ /dev/null @@ -1,20 +0,0 @@ -<!-- Code generated from the comments of the CloneConfig struct in builder/vsphere/clone/step_clone.go; DO NOT EDIT MANUALLY --> - -- `template` (string) - Name of source VM. Path is optional. - -- `disk_size` (int64) - The size of the disk in MB. - -- `linked_clone` (bool) - Create VM as a linked clone from latest snapshot. Defaults to `false`. - -- `network` (string) - Set the network in which the VM will be connected to. If no network is - specified, `host` must be specified to allow Packer to look for the - available network. If the network is inside a network folder in vCenter, - you need to provide the full path to the network. - -- `mac_address` (string) - Sets a custom Mac Address to the network adapter. If set, the [network](#network) must be also specified. - -- `notes` (string) - VM notes. - -- `vapp` (vAppConfig) - Set the vApp Options to a virtual machine. - See the [vApp Options Configuration](/docs/builders/vmware/vsphere-clone#vapp-options-configuration) - to know the available options and how to use it. diff --git a/website/content/partials/builder/vsphere/clone/Config-not-required.mdx b/website/content/partials/builder/vsphere/clone/Config-not-required.mdx deleted file mode 100644 index b44beb590..000000000 --- a/website/content/partials/builder/vsphere/clone/Config-not-required.mdx +++ /dev/null @@ -1,15 +0,0 @@ -<!-- Code generated from the comments of the Config struct in builder/vsphere/clone/config.go; DO NOT EDIT MANUALLY --> - -- `create_snapshot` (bool) - Create a snapshot when set to `true`, so the VM can be used as a base - for linked clones. Defaults to `false`. - -- `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`. - -- `export` (\*common.ExportConfig) - Configuration for exporting VM to an ovf file. - The VM will not be exported if no [Export Configuration](#export-configuration) is specified. - -- `content_library_destination` (\*common.ContentLibraryDestinationConfig) - Configuration for importing a VM template or OVF template to a Content Library. - The template will not be imported if no [Content Library Import Configuration](#content-library-import-configuration) is specified. - The import doesn't work if [convert_to_template](#convert_to_template) is set to true. - -- `customize` (\*CustomizeConfig) - Customize the cloned VM to configure host, network, or licensing settings. See the [customization options](#customization). diff --git a/website/content/partials/builder/vsphere/clone/CustomizeConfig-not-required.mdx b/website/content/partials/builder/vsphere/clone/CustomizeConfig-not-required.mdx deleted file mode 100644 index 487975075..000000000 --- a/website/content/partials/builder/vsphere/clone/CustomizeConfig-not-required.mdx +++ /dev/null @@ -1,9 +0,0 @@ -<!-- Code generated from the comments of the CustomizeConfig struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -- `linux_options` (\*LinuxOptions) - Settings to Linux guest OS customization. See [Linux customization settings](#linux-customization-settings). - -- `windows_sysprep_file` (string) - Supply your own sysprep.xml file to allow full control of the customization process out-of-band of vSphere. - -- `network_interface` (NetworkInterfaces) - Configure network interfaces on a per-interface basis that should matched up to the network adapters present in the VM. - To use DHCP, declare an empty network_interface for each adapter being configured. This field is required. - See [Network interface settings](#network-interface-settings). diff --git a/website/content/partials/builder/vsphere/clone/CustomizeConfig.mdx b/website/content/partials/builder/vsphere/clone/CustomizeConfig.mdx deleted file mode 100644 index fca10d1e6..000000000 --- a/website/content/partials/builder/vsphere/clone/CustomizeConfig.mdx +++ /dev/null @@ -1,12 +0,0 @@ -<!-- Code generated from the comments of the CustomizeConfig struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -A cloned virtual machine can be [customized](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-58E346FF-83AE-42B8-BE58-253641D257BC.html) -to configure host, network, or licensing settings. - -To perform virtual machine customization as a part of the clone process, specify the customize block with the -respective customization options. Windows guests are customized using Sysprep, which will result in the machine SID being reset. -Before using customization, check that your source VM meets the [requirements](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-E63B6FAA-8D35-428D-B40C-744769845906.html) -for guest OS customization on vSphere. -See the [customization example](#customization-example) for a usage synopsis. - -The settings for customize are as follows: diff --git a/website/content/partials/builder/vsphere/clone/GlobalDnsSettings-not-required.mdx b/website/content/partials/builder/vsphere/clone/GlobalDnsSettings-not-required.mdx deleted file mode 100644 index 095d11a8a..000000000 --- a/website/content/partials/builder/vsphere/clone/GlobalDnsSettings-not-required.mdx +++ /dev/null @@ -1,5 +0,0 @@ -<!-- Code generated from the comments of the GlobalDnsSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -- `dns_server_list` ([]string) - The list of DNS servers to configure on a virtual machine. - -- `dns_suffix_list` ([]string) - A list of DNS search domains to add to the DNS configuration on the virtual machine. diff --git a/website/content/partials/builder/vsphere/clone/GlobalDnsSettings.mdx b/website/content/partials/builder/vsphere/clone/GlobalDnsSettings.mdx deleted file mode 100644 index adbcafe54..000000000 --- a/website/content/partials/builder/vsphere/clone/GlobalDnsSettings.mdx +++ /dev/null @@ -1,4 +0,0 @@ -<!-- Code generated from the comments of the GlobalDnsSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -The following settings configure DNS globally, generally for Linux systems. For Windows systems, -this is done per-interface, see [network interface](#network_interface) settings. diff --git a/website/content/partials/builder/vsphere/clone/GlobalRoutingSettings-not-required.mdx b/website/content/partials/builder/vsphere/clone/GlobalRoutingSettings-not-required.mdx deleted file mode 100644 index e83ad8150..000000000 --- a/website/content/partials/builder/vsphere/clone/GlobalRoutingSettings-not-required.mdx +++ /dev/null @@ -1,5 +0,0 @@ -<!-- Code generated from the comments of the GlobalRoutingSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -- `ipv4_gateway` (string) - The IPv4 default gateway when using network_interface customization on the virtual machine. - -- `ipv6_gateway` (string) - The IPv6 default gateway when using network_interface customization on the virtual machine. diff --git a/website/content/partials/builder/vsphere/clone/GlobalRoutingSettings.mdx b/website/content/partials/builder/vsphere/clone/GlobalRoutingSettings.mdx deleted file mode 100644 index 55aa29735..000000000 --- a/website/content/partials/builder/vsphere/clone/GlobalRoutingSettings.mdx +++ /dev/null @@ -1,3 +0,0 @@ -<!-- Code generated from the comments of the GlobalRoutingSettings struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -The settings here must match the IP/mask of at least one network_interface supplied to customization. diff --git a/website/content/partials/builder/vsphere/clone/LinuxOptions-not-required.mdx b/website/content/partials/builder/vsphere/clone/LinuxOptions-not-required.mdx deleted file mode 100644 index 462b7bab8..000000000 --- a/website/content/partials/builder/vsphere/clone/LinuxOptions-not-required.mdx +++ /dev/null @@ -1,9 +0,0 @@ -<!-- Code generated from the comments of the LinuxOptions struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -- `domain` (string) - The domain name for this machine. This, along with [host_name](#host_name), make up the FQDN of this virtual machine. - -- `host_name` (string) - The host name for this machine. This, along with [domain](#domain), make up the FQDN of this virtual machine. - -- `hw_clock_utc` (boolean) - Tells the operating system that the hardware clock is set to UTC. Default: true. - -- `time_zone` (string) - Sets the time zone. The default is UTC. diff --git a/website/content/partials/builder/vsphere/clone/NetworkInterface-not-required.mdx b/website/content/partials/builder/vsphere/clone/NetworkInterface-not-required.mdx deleted file mode 100644 index 7f9a33468..000000000 --- a/website/content/partials/builder/vsphere/clone/NetworkInterface-not-required.mdx +++ /dev/null @@ -1,15 +0,0 @@ -<!-- Code generated from the comments of the NetworkInterface struct in builder/vsphere/clone/step_customize.go; DO NOT EDIT MANUALLY --> - -- `dns_server_list` ([]string) - Network interface-specific DNS server settings for Windows operating systems. - Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section. - -- `dns_domain` (string) - Network interface-specific DNS search domain for Windows operating systems. - Ignored on Linux and possibly other operating systems - for those systems, please see the [global DNS settings](#global-dns-settings) section. - -- `ipv4_address` (string) - The IPv4 address assigned to this network adapter. If left blank or not included, DHCP is used. - -- `ipv4_netmask` (int) - The IPv4 subnet mask, in bits (example: 24 for 255.255.255.0). - -- `ipv6_address` (string) - The IPv6 address assigned to this network adapter. If left blank or not included, auto-configuration is used. - -- `ipv6_netmask` (int) - The IPv6 subnet mask, in bits (example: 32). diff --git a/website/content/partials/builder/vsphere/clone/vAppConfig-not-required.mdx b/website/content/partials/builder/vsphere/clone/vAppConfig-not-required.mdx deleted file mode 100644 index daa4b2d4f..000000000 --- a/website/content/partials/builder/vsphere/clone/vAppConfig-not-required.mdx +++ /dev/null @@ -1,9 +0,0 @@ -<!-- Code generated from the comments of the vAppConfig struct in builder/vsphere/clone/step_clone.go; DO NOT EDIT MANUALLY --> - -- `properties` (map[string]string) - Set values for the available vApp Properties to supply configuration parameters to a virtual machine cloned from - a template that came from an imported OVF or OVA file. - - -> **Note:** The only supported usage path for vApp properties is for existing user-configurable keys. - These generally come from an existing template that was created from an imported OVF or OVA file. - You cannot set values for vApp properties on virtual machines created from scratch, - virtual machines lacking a vApp configuration, or on property keys that do not exist. diff --git a/website/content/partials/builder/vsphere/common/BootConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/BootConfig-not-required.mdx deleted file mode 100644 index b3899332d..000000000 --- a/website/content/partials/builder/vsphere/common/BootConfig-not-required.mdx +++ /dev/null @@ -1,4 +0,0 @@ -<!-- Code generated from the comments of the BootConfig struct in builder/vsphere/common/step_boot_command.go; DO NOT EDIT MANUALLY --> - -- `http_ip` (string) - The IP address to use for the HTTP server started to serve the `http_directory`. - If unset, Packer will automatically discover and assign an IP. diff --git a/website/content/partials/builder/vsphere/common/CDRomConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/CDRomConfig-not-required.mdx deleted file mode 100644 index e225b4820..000000000 --- a/website/content/partials/builder/vsphere/common/CDRomConfig-not-required.mdx +++ /dev/null @@ -1,12 +0,0 @@ -<!-- Code generated from the comments of the CDRomConfig struct in builder/vsphere/common/step_add_cdrom.go; DO NOT EDIT MANUALLY --> - -- `cdrom_type` (string) - Which controller to use. Example: `sata`. Defaults to `ide`. - -- `iso_paths` ([]string) - List of Datastore or Content Library paths to ISO files that will be mounted to the VM. - Here's an HCL2 example: - ```hcl - iso_paths = [ - "[datastore1] ISO/ubuntu.iso", - "Packer Library Test/ubuntu-16.04.6-server-amd64/ubuntu-16.04.6-server-amd64.iso" - ] - ``` diff --git a/website/content/partials/builder/vsphere/common/ConfigParamsConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/ConfigParamsConfig-not-required.mdx deleted file mode 100644 index 29b4922d4..000000000 --- a/website/content/partials/builder/vsphere/common/ConfigParamsConfig-not-required.mdx +++ /dev/null @@ -1,9 +0,0 @@ -<!-- Code generated from the comments of the ConfigParamsConfig struct in builder/vsphere/common/step_config_params.go; DO NOT EDIT MANUALLY --> - -- `configuration_parameters` (map[string]string) - configuration_parameters is a direct passthrough to the VSphere API's - ConfigSpec: https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.ConfigSpec.html - -- `tools_sync_time` (bool) - Enables time synchronization with the host. Defaults to false. - -- `tools_upgrade_policy` (bool) - If sets to true, vSphere will automatically check and upgrade VMware Tools upon a system power cycle. - If not set, defaults to manual upgrade. diff --git a/website/content/partials/builder/vsphere/common/ConnectConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/ConnectConfig-not-required.mdx deleted file mode 100644 index 69185294b..000000000 --- a/website/content/partials/builder/vsphere/common/ConnectConfig-not-required.mdx +++ /dev/null @@ -1,11 +0,0 @@ -<!-- Code generated from the comments of the ConnectConfig struct in builder/vsphere/common/step_connect.go; DO NOT EDIT MANUALLY --> - -- `vcenter_server` (string) - vCenter server hostname. - -- `username` (string) - vSphere username. - -- `password` (string) - vSphere password. - -- `insecure_connection` (bool) - Do not validate vCenter server's TLS certificate. Defaults to `false`. - -- `datacenter` (string) - VMware datacenter name. Required if there is more than one datacenter in vCenter. diff --git a/website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx deleted file mode 100644 index 86eefcb6b..000000000 --- a/website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig-not-required.mdx +++ /dev/null @@ -1,46 +0,0 @@ -<!-- Code generated from the comments of the ContentLibraryDestinationConfig struct in builder/vsphere/common/step_import_to_content_library.go; DO NOT EDIT MANUALLY --> - -- `library` (string) - Name of the library in which the new library item containing the template should be created/updated. - The Content Library should be of type Local to allow deploying virtual machines. - -- `name` (string) - Name of the library item that will be created or updated. - For VM templates, the name of the item should be different from [vm_name](#vm_name) and - the default is [vm_name](#vm_name) + timestamp when not set. VM templates will be always imported to a new library item. - For OVF templates, the name defaults to [vm_name](#vm_name) when not set, and if an item with the same name already - exists it will be then updated with the new OVF template, otherwise a new item will be created. - - ~> **Note**: It's not possible to update existing library items with a new VM template. If updating an existing library - item is necessary, use an OVF template instead by setting the [ovf](#ovf) option as `true`. - -- `description` (string) - Description of the library item that will be created. - This option is not used when importing OVF templates. - Defaults to "Packer imported [vm_name](#vm_name) VM template". - -- `cluster` (string) - Cluster onto which the virtual machine template should be placed. - If cluster and resource_pool are both specified, resource_pool must belong to cluster. - If cluster and host are both specified, host must be a member of cluster. - This option is not used when importing OVF templates. - Defaults to [cluster](#cluster). - -- `folder` (string) - Virtual machine folder into which the virtual machine template should be placed. - This option is not used when importing OVF templates. - Defaults to the same folder as the source virtual machine. - -- `host` (string) - Host onto which the virtual machine template should be placed. - If host and resource_pool are both specified, resource_pool must belong to host. - If host and cluster are both specified, host must be a member of cluster. - This option is not used when importing OVF templates. - Defaults to [host](#host). - -- `resource_pool` (string) - Resource pool into which the virtual machine template should be placed. - Defaults to [resource_pool](#resource_pool). if [resource_pool](#resource_pool) is also unset, - the system will attempt to choose a suitable resource pool for the virtual machine template. - -- `datastore` (string) - The datastore for the virtual machine template's configuration and log files. - This option is not used when importing OVF templates. - Defaults to the storage backing associated with the library specified by library. - -- `destroy` (bool) - If set to true, the VM will be destroyed after deploying the template to the Content Library. - Defaults to `false`. - -- `ovf` (bool) - When set to true, Packer will import and OVF template to the content library item. Defaults to `false`. diff --git a/website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig.mdx b/website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig.mdx deleted file mode 100644 index 06a6844ac..000000000 --- a/website/content/partials/builder/vsphere/common/ContentLibraryDestinationConfig.mdx +++ /dev/null @@ -1,5 +0,0 @@ -<!-- Code generated from the comments of the ContentLibraryDestinationConfig struct in builder/vsphere/common/step_import_to_content_library.go; DO NOT EDIT MANUALLY --> - -With this configuration Packer creates a library item in a content library whose content is a VM template -or an OVF template created from the just built VM. -The template is stored in a existing or newly created library item. diff --git a/website/content/partials/builder/vsphere/common/DiskConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/DiskConfig-not-required.mdx deleted file mode 100644 index f7267b405..000000000 --- a/website/content/partials/builder/vsphere/common/DiskConfig-not-required.mdx +++ /dev/null @@ -1,7 +0,0 @@ -<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY --> - -- `disk_thin_provisioned` (bool) - Enable VMDK thin provisioning for VM. Defaults to `false`. - -- `disk_eagerly_scrub` (bool) - Enable VMDK eager scrubbing for VM. Defaults to `false`. - -- `disk_controller_index` (int) - The assigned disk controller. Defaults to the first one (0) diff --git a/website/content/partials/builder/vsphere/common/DiskConfig-required.mdx b/website/content/partials/builder/vsphere/common/DiskConfig-required.mdx deleted file mode 100644 index 29a583222..000000000 --- a/website/content/partials/builder/vsphere/common/DiskConfig-required.mdx +++ /dev/null @@ -1,3 +0,0 @@ -<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY --> - -- `disk_size` (int64) - The size of the disk in MB. diff --git a/website/content/partials/builder/vsphere/common/DiskConfig.mdx b/website/content/partials/builder/vsphere/common/DiskConfig.mdx deleted file mode 100644 index 44040b0f7..000000000 --- a/website/content/partials/builder/vsphere/common/DiskConfig.mdx +++ /dev/null @@ -1,74 +0,0 @@ -<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY --> - -Defines the disk storage for a VM. - -Example that will create a 15GB and a 20GB disk on the VM. The second disk will be thin provisioned: - -In JSON: -```json - "storage": [ - { - "disk_size": 15000 - }, - { - "disk_size": 20000, - "disk_thin_provisioned": true - } - ], -``` -In HCL2: -```hcl - storage { - disk_size = 15000 - } - storage { - disk_size = 20000 - disk_thin_provisioned = true - } -``` - -Example that creates 2 pvscsi controllers and adds 2 disks to each one: - -In JSON: -```json - "disk_controller_type": ["pvscsi", "pvscsi"], - "storage": [ - { - "disk_size": 15000, - "disk_controller_index": 0 - }, - { - "disk_size": 15000, - "disk_controller_index": 0 - }, - { - "disk_size": 15000, - "disk_controller_index": 1 - }, - { - "disk_size": 15000, - "disk_controller_index": 1 - } - ], -``` - -In HCL2: -```hcl - disk_controller_type = ["pvscsi", "pvscsi"] - storage { - disk_size = 15000, - disk_controller_index = 0 - } - storage { - disk_size = 15000 - disk_controller_index = 0 - } - storage { - disk_size = 15000 - disk_controller_index = 1 - } - storage { - disk_size = 15000 - disk_controller_index = 1 - } -``` diff --git a/website/content/partials/builder/vsphere/common/ExportConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/ExportConfig-not-required.mdx deleted file mode 100644 index 8f1a355a4..000000000 --- a/website/content/partials/builder/vsphere/common/ExportConfig-not-required.mdx +++ /dev/null @@ -1,32 +0,0 @@ -<!-- Code generated from the comments of the ExportConfig struct in builder/vsphere/common/step_export.go; DO NOT EDIT MANUALLY --> - -- `name` (string) - name of the ovf. defaults to the name of the VM - -- `force` (bool) - overwrite ovf if it exists - -- `images` (bool) - include iso and img image files that are attached to the VM - -- `manifest` (string) - generate manifest using sha1, sha256, sha512. Defaults to 'sha256'. Use 'none' for no manifest. - -- `options` ([]string) - Advanced ovf export options. Options can include: - * mac - MAC address is exported for all ethernet devices - * uuid - UUID is exported for all virtual machines - * extraconfig - all extra configuration options are exported for a virtual machine - * nodevicesubtypes - resource subtypes for CD/DVD drives, floppy drives, and serial and parallel ports are not exported - - For example, adding the following export config option would output the mac addresses for all Ethernet devices in the ovf file: - - In JSON: - ```json - ... - "export": { - "options": ["mac"] - }, - ``` - In HCL2: - ```hcl - ... - export { - options = ["mac"] - } - ``` diff --git a/website/content/partials/builder/vsphere/common/ExportConfig.mdx b/website/content/partials/builder/vsphere/common/ExportConfig.mdx deleted file mode 100644 index 074c74302..000000000 --- a/website/content/partials/builder/vsphere/common/ExportConfig.mdx +++ /dev/null @@ -1,33 +0,0 @@ -<!-- Code generated from the comments of the ExportConfig struct in builder/vsphere/common/step_export.go; DO NOT EDIT MANUALLY --> - -You may optionally export an ovf from VSphere to the instance running Packer. - -Example usage: - -In JSON: -```json -... - "vm_name": "example-ubuntu", -... - "export": { - "force": true, - "output_directory": "./output_vsphere" - }, -``` -In HCL2: -```hcl - # ... - vm_name = "example-ubuntu" - # ... - export { - force = true - output_directory = "./output_vsphere" - } -``` -The above configuration would create the following files: - -```text -./output_vsphere/example-ubuntu-disk-0.vmdk -./output_vsphere/example-ubuntu.mf -./output_vsphere/example-ubuntu.ovf -``` diff --git a/website/content/partials/builder/vsphere/common/FloppyConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/FloppyConfig-not-required.mdx deleted file mode 100644 index fc41e65e1..000000000 --- a/website/content/partials/builder/vsphere/common/FloppyConfig-not-required.mdx +++ /dev/null @@ -1,14 +0,0 @@ -<!-- Code generated from the comments of the FloppyConfig struct in builder/vsphere/common/step_add_floppy.go; DO NOT EDIT MANUALLY --> - -- `floppy_img_path` (string) - Datastore path to a floppy image that will be mounted to the VM. - Example: `[datastore1] ISO/pvscsi-Windows8.flp`. - -- `floppy_files` ([]string) - List of local files to be mounted to the VM floppy drive. Can be used to - make Debian preseed or RHEL kickstart files available to the VM. - -- `floppy_dirs` ([]string) - List of directories to copy files from. - -- `floppy_label` (string) - The label to use for the floppy disk that - is attached when the VM is booted. This is most useful for cloud-init, - Kickstart or other early initialization tools, which can benefit from labelled floppy disks. - By default, the floppy label will be 'packer'. diff --git a/website/content/partials/builder/vsphere/common/HardwareConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/HardwareConfig-not-required.mdx deleted file mode 100644 index ccc4f5e90..000000000 --- a/website/content/partials/builder/vsphere/common/HardwareConfig-not-required.mdx +++ /dev/null @@ -1,31 +0,0 @@ -<!-- Code generated from the comments of the HardwareConfig struct in builder/vsphere/common/step_hardware.go; DO NOT EDIT MANUALLY --> - -- `CPUs` (int32) - Number of CPU cores. - -- `cpu_cores` (int32) - Number of CPU cores per socket. - -- `CPU_reservation` (int64) - Amount of reserved CPU resources in MHz. - -- `CPU_limit` (int64) - Upper limit of available CPU resources in MHz. - -- `CPU_hot_plug` (bool) - Enable CPU hot plug setting for virtual machine. Defaults to `false`. - -- `RAM` (int64) - Amount of RAM in MB. - -- `RAM_reservation` (int64) - Amount of reserved RAM in MB. - -- `RAM_reserve_all` (bool) - Reserve all available RAM. Defaults to `false`. Cannot be used together - with `RAM_reservation`. - -- `RAM_hot_plug` (bool) - Enable RAM hot plug setting for virtual machine. Defaults to `false`. - -- `video_ram` (int64) - Amount of video memory in KB. - -- `vgpu_profile` (string) - vGPU profile for accelerated graphics. See [NVIDIA GRID vGPU documentation](https://docs.nvidia.com/grid/latest/grid-vgpu-user-guide/index.html#configure-vmware-vsphere-vm-with-vgpu) - for examples of profile names. Defaults to none. - -- `NestedHV` (bool) - Enable nested hardware virtualization for VM. Defaults to `false`. - -- `firmware` (string) - Set the Firmware for virtual machine. Supported values: `bios`, `efi` or `efi-secure`. Defaults to `bios`. - -- `force_bios_setup` (bool) - During the boot, force entry into the BIOS setup screen. Defaults to `false`. diff --git a/website/content/partials/builder/vsphere/common/LocationConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/LocationConfig-not-required.mdx deleted file mode 100644 index 58e2afb38..000000000 --- a/website/content/partials/builder/vsphere/common/LocationConfig-not-required.mdx +++ /dev/null @@ -1,24 +0,0 @@ -<!-- Code generated from the comments of the LocationConfig struct in builder/vsphere/common/config_location.go; DO NOT EDIT MANUALLY --> - -- `vm_name` (string) - Name of the new VM to create. - -- `folder` (string) - VM folder to create the VM in. - -- `cluster` (string) - ESXi cluster where target VM is created. See the - [Working With Clusters And Hosts](#working-with-clusters-and-hosts) - section above for more details. - -- `host` (string) - ESXi host where target VM is created. A full path must be specified if - the host is in a folder. For example `folder/host`. See the - [Working With Clusters And Hosts](#working-with-clusters-and-hosts) - section above for more details. - -- `resource_pool` (string) - VMWare resource pool. If not set, it will look for the root resource - pool of the `host` or `cluster`. If a root resource is not found, it - will then look for a default resource pool. - -- `datastore` (string) - VMWare datastore. Required if `host` is a cluster, or if `host` has - multiple datastores. - -- `set_host_for_datastore_uploads` (bool) - Set this to true if packer should use the host for uploading files - to the datastore. Defaults to false. diff --git a/website/content/partials/builder/vsphere/common/OutputConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/OutputConfig-not-required.mdx deleted file mode 100644 index 6e5476c97..000000000 --- a/website/content/partials/builder/vsphere/common/OutputConfig-not-required.mdx +++ /dev/null @@ -1,16 +0,0 @@ -<!-- Code generated from the comments of the OutputConfig struct in builder/vsphere/common/output_config.go; DO NOT EDIT MANUALLY --> - -- `output_directory` (string) - This setting specifies the directory that - artifacts from the build, such as the virtual machine files and disks, - will be output to. The path to the directory may be relative or - absolute. If relative, the path is relative to the working directory - packer is executed from. This directory must not exist or, if - created, must be empty prior to running the builder. By default this is - "output-BUILDNAME" where "BUILDNAME" is the name of the build. - -- `directory_permission` (os.FileMode) - The permissions to apply to the "output_directory", and to any parent - directories that get created for output_directory. By default this is - "0750". You should express the permission as quoted string with a - leading zero such as "0755" in JSON file, because JSON does not support - octal value. In Unix-like OS, the actual permission may differ from - this value because of umask. diff --git a/website/content/partials/builder/vsphere/common/RemoveCDRomConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/RemoveCDRomConfig-not-required.mdx deleted file mode 100644 index 651bffa6e..000000000 --- a/website/content/partials/builder/vsphere/common/RemoveCDRomConfig-not-required.mdx +++ /dev/null @@ -1,3 +0,0 @@ -<!-- Code generated from the comments of the RemoveCDRomConfig struct in builder/vsphere/common/step_remove_cdrom.go; DO NOT EDIT MANUALLY --> - -- `remove_cdrom` (bool) - Remove CD-ROM devices from template. Defaults to `false`. diff --git a/website/content/partials/builder/vsphere/common/RunConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/RunConfig-not-required.mdx deleted file mode 100644 index b5dedf69d..000000000 --- a/website/content/partials/builder/vsphere/common/RunConfig-not-required.mdx +++ /dev/null @@ -1,3 +0,0 @@ -<!-- Code generated from the comments of the RunConfig struct in builder/vsphere/common/step_run.go; DO NOT EDIT MANUALLY --> - -- `boot_order` (string) - Priority of boot devices. Defaults to `disk,cdrom` diff --git a/website/content/partials/builder/vsphere/common/ShutdownConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/ShutdownConfig-not-required.mdx deleted file mode 100644 index 1b950c176..000000000 --- a/website/content/partials/builder/vsphere/common/ShutdownConfig-not-required.mdx +++ /dev/null @@ -1,16 +0,0 @@ -<!-- Code generated from the comments of the ShutdownConfig struct in builder/vsphere/common/step_shutdown.go; DO NOT EDIT MANUALLY --> - -- `shutdown_command` (string) - Specify a VM guest shutdown command. This command will be executed using - the `communicator`. Otherwise the VMware guest tools are used to gracefully - shutdown the VM guest. - -- `shutdown_timeout` (duration string | ex: "1h5m2s") - Amount of time to wait for graceful VM shutdown. - Defaults to 5m or five minutes. - This will likely need to be modified if the `communicator` is 'none'. - -- `disable_shutdown` (bool) - Packer normally halts the virtual machine after all provisioners have - run when no `shutdown_command` is defined. If this is set to `true`, Packer - *will not* halt the virtual machine but will assume that you will send the stop - signal yourself through a preseed.cfg, a script or the final provisioner. - Packer will wait for a default of five minutes until the virtual machine is shutdown. - The timeout can be changed using `shutdown_timeout` option. diff --git a/website/content/partials/builder/vsphere/common/StorageConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/StorageConfig-not-required.mdx deleted file mode 100644 index 2146f4442..000000000 --- a/website/content/partials/builder/vsphere/common/StorageConfig-not-required.mdx +++ /dev/null @@ -1,8 +0,0 @@ -<!-- Code generated from the comments of the StorageConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY --> - -- `disk_controller_type` ([]string) - Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers. - Defaults to `lsilogic`. See - [SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362) - for additional details. - -- `storage` ([]DiskConfig) - Configures a collection of one or more disks to be provisioned along with the VM. See the [Storage Configuration](#storage-configuration). diff --git a/website/content/partials/builder/vsphere/common/WaitIpConfig-not-required.mdx b/website/content/partials/builder/vsphere/common/WaitIpConfig-not-required.mdx deleted file mode 100644 index 905d44690..000000000 --- a/website/content/partials/builder/vsphere/common/WaitIpConfig-not-required.mdx +++ /dev/null @@ -1,20 +0,0 @@ -<!-- Code generated from the comments of the WaitIpConfig struct in builder/vsphere/common/step_wait_for_ip.go; DO NOT EDIT MANUALLY --> - -- `ip_wait_timeout` (duration string | ex: "1h5m2s") - Amount of time to wait for VM's IP, similar to 'ssh_timeout'. - Defaults to 30m (30 minutes). See the Golang - [ParseDuration](https://golang.org/pkg/time/#ParseDuration) documentation - for full details. - -- `ip_settle_timeout` (duration string | ex: "1h5m2s") - Amount of time to wait for VM's IP to settle down, sometimes VM may - report incorrect IP initially, then its recommended to set that - parameter to apx. 2 minutes. Examples 45s and 10m. Defaults to - 5s(5 seconds). See the Golang - [ParseDuration](https://golang.org/pkg/time/#ParseDuration) documentation - for full details. - -- `ip_wait_address` (\*string) - Set this to a CIDR address to cause the service to wait for an address that is contained in - this network range. Defaults to "0.0.0.0/0" for any ipv4 address. Examples include: - - * empty string ("") - remove all filters - * `0:0:0:0:0:0:0:0/0` - allow only ipv6 addresses - * `192.168.1.0/24` - only allow ipv4 addresses from 192.168.1.1 to 192.168.1.254 diff --git a/website/content/partials/builder/vsphere/iso/Config-not-required.mdx b/website/content/partials/builder/vsphere/iso/Config-not-required.mdx deleted file mode 100644 index 72cc35ecf..000000000 --- a/website/content/partials/builder/vsphere/iso/Config-not-required.mdx +++ /dev/null @@ -1,13 +0,0 @@ -<!-- Code generated from the comments of the Config struct in builder/vsphere/iso/config.go; DO NOT EDIT MANUALLY --> - -- `create_snapshot` (bool) - Create a snapshot when set to `true`, so the VM can be used as a base - for linked clones. Defaults to `false`. - -- `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`. - -- `export` (\*common.ExportConfig) - Configuration for exporting VM to an ovf file. - The VM will not be exported if no [Export Configuration](#export-configuration) is specified. - -- `content_library_destination` (\*common.ContentLibraryDestinationConfig) - Configuration for importing the VM template to a Content Library. - The VM template will not be imported if no [Content Library Import Configuration](#content-library-import-configuration) is specified. - The import doesn't work if [convert_to_template](#convert_to_template) is set to true. diff --git a/website/content/partials/builder/vsphere/iso/CreateConfig-not-required.mdx b/website/content/partials/builder/vsphere/iso/CreateConfig-not-required.mdx deleted file mode 100644 index cd2ddc28d..000000000 --- a/website/content/partials/builder/vsphere/iso/CreateConfig-not-required.mdx +++ /dev/null @@ -1,16 +0,0 @@ -<!-- Code generated from the comments of the CreateConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY --> - -- `vm_version` (uint) - Set VM hardware version. Defaults to the most current VM hardware - version supported by vCenter. See - [VMWare article 1003746](https://kb.vmware.com/s/article/1003746) for - the full list of supported VM hardware versions. - -- `guest_os_type` (string) - Set VM OS type. Defaults to `otherGuest`. See [ - here](https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html) - for a full list of possible values. - -- `network_adapters` ([]NIC) - Network adapters - -- `usb_controller` ([]string) - Create USB controllers for the virtual machine. "usb" for a usb 2.0 controller. "xhci" for a usb 3.0 controller. There can only be at most one of each. - -- `notes` (string) - VM notes. diff --git a/website/content/partials/builder/vsphere/iso/NIC-not-required.mdx b/website/content/partials/builder/vsphere/iso/NIC-not-required.mdx deleted file mode 100644 index fa5f0da5c..000000000 --- a/website/content/partials/builder/vsphere/iso/NIC-not-required.mdx +++ /dev/null @@ -1,10 +0,0 @@ -<!-- Code generated from the comments of the NIC struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY --> - -- `network` (string) - Set the network in which the VM will be connected to. If no network is - specified, `host` must be specified to allow Packer to look for the - available network. If the network is inside a network folder in vCenter, - you need to provide the full path to the network. - -- `mac_address` (string) - Set network card MAC address - -- `passthrough` (\*bool) - Enable DirectPath I/O passthrough diff --git a/website/content/partials/builder/vsphere/iso/NIC-required.mdx b/website/content/partials/builder/vsphere/iso/NIC-required.mdx deleted file mode 100644 index a73b8a26e..000000000 --- a/website/content/partials/builder/vsphere/iso/NIC-required.mdx +++ /dev/null @@ -1,3 +0,0 @@ -<!-- Code generated from the comments of the NIC struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY --> - -- `network_card` (string) - Set VM network card type. Example `vmxnet3`. diff --git a/website/content/partials/builder/vsphere/iso/NIC.mdx b/website/content/partials/builder/vsphere/iso/NIC.mdx deleted file mode 100644 index e891469b0..000000000 --- a/website/content/partials/builder/vsphere/iso/NIC.mdx +++ /dev/null @@ -1,30 +0,0 @@ -<!-- Code generated from the comments of the NIC struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY --> - -Defines a Network Adapter - -Example that creates two network adapters: - -In JSON: -```json - "network_adapters": [ - { - "network": "VM Network", - "network_card": "vmxnet3" - }, - { - "network": "OtherNetwork", - "network_card": "vmxnet3" - } - ], -``` -In HCL2: -```hcl - network_adapters { - network = "VM Network" - network_card = "vmxnet3" - } - network_adapters { - network = "OtherNetwork" - network_card = "vmxnet3" - } -``` diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index f6d0a9419..1198fe8f2 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -912,14 +912,6 @@ { "title": "VMWare VMX", "path": "builders/vmware/vmx" - }, - { - "title": "VSphere ISO", - "path": "builders/vmware/vsphere-iso" - }, - { - "title": "VSphere Clone", - "path": "builders/vmware/vsphere-clone" } ] }, @@ -1082,14 +1074,6 @@ "title": "Vagrant Cloud", "path": "post-processors/vagrant-cloud" }, - { - "title": "vSphere", - "path": "post-processors/vsphere" - }, - { - "title": "vSphere Template", - "path": "post-processors/vsphere-template" - }, { "title": "Yandex.Cloud Compute Export", "path": "post-processors/yandex-export"