From 41c66d69357be5c2bef039cd79e01bd79fc1fee5 Mon Sep 17 00:00:00 2001 From: sylviamoss Date: Fri, 9 Apr 2021 17:58:56 +0200 Subject: [PATCH] vendor vsphere plugin --- command/vendored_plugins.go | 20 +- go.mod | 4 +- go.sum | 8 +- .../hashicorp/packer-plugin-vsphere/LICENSE | 373 ++++++ .../builder/vsphere/clone/builder.go | 175 +++ .../builder/vsphere/clone/config.go | 104 ++ .../builder/vsphere/clone/config.hcl2spec.go | 282 +++++ .../builder/vsphere/clone/step_clone.go | 136 ++ .../vsphere/clone/step_clone.hcl2spec.go | 71 ++ .../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/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_floppy.go | 111 ++ .../common/step_add_floppy.hcl2spec.go | 37 + .../vsphere/common/step_boot_command.go | 152 +++ .../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_export.go | 338 +++++ .../vsphere/common/step_export.hcl2spec.go | 45 + .../builder/vsphere/common/step_hardware.go | 98 ++ .../vsphere/common/step_hardware.hcl2spec.go | 57 + .../vsphere/common/step_http_ip_discover.go | 68 + .../common/step_import_to_content_library.go | 180 +++ ...step_import_to_content_library.hcl2spec.go | 49 + .../vsphere/common/step_remote_upload.go | 117 ++ .../vsphere/common/step_remove_cdrom.go | 46 + .../common/step_remove_cdrom.hcl2spec.go | 31 + .../vsphere/common/step_remove_floppy.go | 49 + .../builder/vsphere/common/step_run.go | 80 ++ .../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 + .../vsphere/common/step_ssh_key_pair.go | 115 ++ .../builder/vsphere/common/step_template.go | 31 + .../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/driver/cluster.go | 19 + .../builder/vsphere/driver/datastore.go | 235 ++++ .../builder/vsphere/driver/datastore_mock.go | 81 ++ .../builder/vsphere/driver/disk.go | 85 ++ .../builder/vsphere/driver/driver.go | 129 ++ .../builder/vsphere/driver/driver_mock.go | 119 ++ .../builder/vsphere/driver/folder.go | 93 ++ .../builder/vsphere/driver/host.go | 45 + .../builder/vsphere/driver/library.go | 113 ++ .../builder/vsphere/driver/network.go | 77 ++ .../builder/vsphere/driver/resource_pool.go | 91 ++ .../builder/vsphere/driver/vm.go | 1102 +++++++++++++++++ .../builder/vsphere/driver/vm_cdrom.go | 89 ++ .../builder/vsphere/driver/vm_keyboard.go | 39 + .../builder/vsphere/driver/vm_mock.go | 235 ++++ .../builder/vsphere/iso/builder.go | 179 +++ .../builder/vsphere/iso/config.go | 107 ++ .../builder/vsphere/iso/config.hcl2spec.go | 286 +++++ .../builder/vsphere/iso/step_create.go | 188 +++ .../vsphere/iso/step_create.hcl2spec.go | 73 ++ .../vsphere-template/post-processor.go | 160 +++ .../post-processor.hcl2spec.go | 65 + .../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 +++ .../post-processor/vsphere/artifact.go | 47 + .../post-processor/vsphere/post-processor.go | 280 +++++ .../vsphere/post-processor.hcl2spec.go | 75 ++ .../github.com/vmware/govmomi/.goreleaser.yml | 2 + vendor/github.com/vmware/govmomi/.mailmap | 3 + vendor/github.com/vmware/govmomi/.travis.yml | 11 +- vendor/github.com/vmware/govmomi/CHANGELOG.md | 14 + vendor/github.com/vmware/govmomi/CONTRIBUTORS | 32 +- vendor/github.com/vmware/govmomi/README.md | 2 + .../github.com/vmware/govmomi/find/finder.go | 35 +- .../vmware/govmomi/internal/helpers.go | 38 + .../vmware/govmomi/internal/methods.go | 123 ++ .../vmware/govmomi/internal/types.go | 270 ++++ .../govmomi/object/authorization_manager.go | 47 + .../vmware/govmomi/object/virtual_app.go | 16 + .../govmomi/object/virtual_device_list.go | 8 +- .../vmware/govmomi/object/virtual_machine.go | 136 +- vendor/github.com/vmware/govmomi/ovf/cim.go | 128 ++ vendor/github.com/vmware/govmomi/ovf/doc.go | 25 + vendor/github.com/vmware/govmomi/ovf/env.go | 99 ++ .../github.com/vmware/govmomi/ovf/envelope.go | 208 ++++ .../github.com/vmware/govmomi/ovf/manager.go | 103 ++ vendor/github.com/vmware/govmomi/ovf/ovf.go | 35 + .../vmware/govmomi/session/manager.go | 11 + .../vmware/govmomi/vapi/library/library.go | 308 +++++ .../govmomi/vapi/library/library_file.go | 56 + .../govmomi/vapi/library/library_item.go | 180 +++ .../library_item_downloadsession_file.go | 71 ++ .../library/library_item_updatesession.go | 165 +++ .../library_item_updatesession_file.go | 149 +++ .../vmware/govmomi/vapi/rest/client.go | 23 +- .../vmware/govmomi/vapi/rest/resource.go | 9 +- .../govmomi/vapi/vcenter/vcenter_ovf.go | 304 +++++ .../govmomi/vapi/vcenter/vcenter_vmtx.go | 285 +++++ .../vmware/govmomi/vim25/methods/methods.go | 40 + .../github.com/vmware/govmomi/vim25/retry.go | 72 +- .../vmware/govmomi/vim25/soap/client.go | 23 +- .../vmware/govmomi/vim25/soap/error.go | 10 + .../vmware/govmomi/vim25/types/enum.go | 388 +++--- .../vmware/govmomi/vim25/types/helpers.go | 6 + .../vmware/govmomi/vim25/types/if.go | 20 +- .../vmware/govmomi/vim25/types/types.go | 281 ++++- .../vmware/govmomi/vim25/xml/marshal.go | 18 +- .../vmware/govmomi/vim25/xml/read.go | 18 +- .../vmware/govmomi/vim25/xml/typeinfo.go | 24 +- .../vmware/govmomi/vim25/xml/xml.go | 9 +- vendor/modules.txt | 16 +- 123 files changed, 12354 insertions(+), 344 deletions(-) create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/LICENSE create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/builder.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/artifact.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/cleanup_vm.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_ssh.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_boot_command.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_download.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_http_ip_discover.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remote_upload.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_floppy.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_snapshot.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_ssh_key_pair.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_template.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/cluster.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore_mock.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/disk.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver_mock.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/folder.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/host.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/library.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/network.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/resource_pool.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_cdrom.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_keyboard.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_mock.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/builder.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.hcl2spec.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_choose_datacenter.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_folder.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_snapshot.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_mark_as_template.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/artifact.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.go create mode 100644 vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.hcl2spec.go create mode 100644 vendor/github.com/vmware/govmomi/internal/helpers.go create mode 100644 vendor/github.com/vmware/govmomi/internal/methods.go create mode 100644 vendor/github.com/vmware/govmomi/internal/types.go create mode 100644 vendor/github.com/vmware/govmomi/ovf/cim.go create mode 100644 vendor/github.com/vmware/govmomi/ovf/doc.go create mode 100644 vendor/github.com/vmware/govmomi/ovf/env.go create mode 100644 vendor/github.com/vmware/govmomi/ovf/envelope.go create mode 100644 vendor/github.com/vmware/govmomi/ovf/manager.go create mode 100644 vendor/github.com/vmware/govmomi/ovf/ovf.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/library/library.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/library/library_file.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/library/library_item.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/library/library_item_downloadsession_file.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession_file.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go create mode 100644 vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_vmtx.go diff --git a/command/vendored_plugins.go b/command/vendored_plugins.go index eea52e9d5..092bd4b90 100644 --- a/command/vendored_plugins.go +++ b/command/vendored_plugins.go @@ -20,6 +20,10 @@ import ( dockerpushpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-push" dockersavepostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-save" dockertagpostprocessor "github.com/hashicorp/packer-plugin-docker/post-processor/docker-tag" + vsphereclonebuilder "github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone" + vsphereisobuilder "github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso" + vspherepostprocessor "github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere" + vspheretemplatepostprocessor "github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template" ) // VendoredDatasources are datasource components that were once bundled with the @@ -38,6 +42,8 @@ var VendoredBuilders = map[string]packersdk.Builder{ "amazon-ebssurrogate": new(amazonebssurrogatebuilder.Builder), "amazon-ebsvolume": new(amazonebsvolumebuilder.Builder), "amazon-instance": new(amazoninstancebuilder.Builder), + "vsphere-clone": new(vsphereclonebuilder.Builder), + "vsphere-iso": new(vsphereisobuilder.Builder), } // VendoredProvisioners are provisioner components that were once bundled with the @@ -47,12 +53,14 @@ var VendoredProvisioners = map[string]packersdk.Provisioner{} // VendoredPostProcessors are post-processor components that were once bundled with the // Packer core, but are now being imported from their counterpart plugin repos var VendoredPostProcessors = map[string]packersdk.PostProcessor{ - "docker-import": new(dockerimportpostprocessor.PostProcessor), - "docker-push": new(dockerpushpostprocessor.PostProcessor), - "docker-save": new(dockersavepostprocessor.PostProcessor), - "docker-tag": new(dockertagpostprocessor.PostProcessor), - "exoscale-import": new(exoscaleimportpostprocessor.PostProcessor), - "amazon-import": new(anazibimportpostprocessor.PostProcessor), + "docker-import": new(dockerimportpostprocessor.PostProcessor), + "docker-push": new(dockerpushpostprocessor.PostProcessor), + "docker-save": new(dockersavepostprocessor.PostProcessor), + "docker-tag": new(dockertagpostprocessor.PostProcessor), + "exoscale-import": new(exoscaleimportpostprocessor.PostProcessor), + "amazon-import": new(anazibimportpostprocessor.PostProcessor), + "vsphere": new(vspherepostprocessor.PostProcessor), + "vsphere-template": new(vspheretemplatepostprocessor.PostProcessor), } // Upon init lets load up any plugins that were vendored manually into the default diff --git a/go.mod b/go.mod index 797690093..d59a5cfe8 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,7 @@ require ( github.com/hashicorp/packer-plugin-amazon v0.0.1 github.com/hashicorp/packer-plugin-docker v0.0.7 github.com/hashicorp/packer-plugin-sdk v0.1.3-0.20210407132324-af39c7839daf + github.com/hashicorp/packer-plugin-vsphere v0.0.0-20210409154313-881202ca3ffe github.com/hashicorp/vault/api v1.0.4 github.com/hetznercloud/hcloud-go v1.15.1 github.com/hyperonecom/h1-client-go v0.0.0-20191203060043-b46280e4c4a4 @@ -83,7 +84,8 @@ require ( github.com/ucloud/ucloud-sdk-go v0.16.3 github.com/ufilesdk-dev/ufile-gosdk v0.0.0-20190830075812-b4dbc4ef43a6 github.com/ulikunitz/xz v0.5.6 - github.com/vmware/govmomi v0.23.1 + github.com/ulikunitz/xz v0.5.5 + github.com/vmware/govmomi v0.24.1 github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0 github.com/yandex-cloud/go-genproto v0.0.0-20200915125933-33de72a328bd github.com/yandex-cloud/go-sdk v0.0.0-20200921111412-ef15ded2014c diff --git a/go.sum b/go.sum index e1e5eed6e..df88fba60 100644 --- a/go.sum +++ b/go.sum @@ -450,6 +450,8 @@ github.com/hashicorp/packer-plugin-sdk v0.1.1/go.mod h1:1d3nqB9LUsXMQaNUiL67Q+WY github.com/hashicorp/packer-plugin-sdk v0.1.2/go.mod h1:KRjczE1/c9NV5Re+PXt3myJsVTI/FxEHpZjRjOH0Fug= github.com/hashicorp/packer-plugin-sdk v0.1.3-0.20210407132324-af39c7839daf h1:0DBlIExTDefzbfkOl213QtgJsVJXWdgW/aIQIvYUMzs= github.com/hashicorp/packer-plugin-sdk v0.1.3-0.20210407132324-af39c7839daf/go.mod h1:xePpgQgQYv/bamiypx3hH9ukidxDdcN8q0R0wLi8IEQ= +github.com/hashicorp/packer-plugin-vsphere v0.0.0-20210409154313-881202ca3ffe h1:qUU0ctLV5Pjq+RqxaKlVmKhE1BQtWZvqV4a05cF93PY= +github.com/hashicorp/packer-plugin-vsphere v0.0.0-20210409154313-881202ca3ffe/go.mod h1:ZmA5O2CDiIOGW/hvHbhxNzq2hEXDYyUVj+knuoxyWu0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.2 h1:yJoyfZXo4Pk2p/M/viW+YLibBFiIbKoP79gu7kDAFP0= github.com/hashicorp/serf v0.9.2/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= @@ -695,8 +697,9 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/vmware/govmomi v0.23.1 h1:vU09hxnNR/I7e+4zCJvW+5vHu5dO64Aoe2Lw7Yi/KRg= github.com/vmware/govmomi v0.23.1/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc= +github.com/vmware/govmomi v0.24.1 h1:ecVvrxF28/5g738gLTiYgc62fpGfIPRKheQ1Dj1p35w= +github.com/vmware/govmomi v0.24.1/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc= github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk= github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0 h1:NJrcIkdzq0C3I8ypAZwFE9RHtGbfp+mJvqIcoFATZuk= github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0/go.mod h1:sBh287mCRwCz6zyXHMmw7sSZGPohVpnx+o+OY4M+i3A= @@ -773,8 +776,9 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20191130191448-5c0e7e404af8/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ= -golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2 h1:3HADozU50HyrJ2jklLtr3xr0itFkz9u4LxCJhqKVdjI= golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= +golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 h1:h+GZ3ubjuWaQjGe8owMGcmMVCqs0xYJtRG5y2bpHaqU= +golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= diff --git a/vendor/github.com/hashicorp/packer-plugin-vsphere/LICENSE b/vendor/github.com/hashicorp/packer-plugin-vsphere/LICENSE new file mode 100644 index 000000000..a612ad981 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/builder.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/builder.go new file mode 100644 index 000000000..f7e4e8063 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/builder.go @@ -0,0 +1,175 @@ +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-plugin-vsphere/builder/vsphere/common" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.go new file mode 100644 index 000000000..900e901f7 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.go @@ -0,0 +1,104 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.hcl2spec.go new file mode 100644 index 000000000..4ca2c4fb9 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/config.hcl2spec.go @@ -0,0 +1,282 @@ +// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT. + +package clone + +import ( + "github.com/hashicorp/hcl/v2/hcldec" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.go new file mode 100644 index 000000000..3d6021f83 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.go @@ -0,0 +1,136 @@ +//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-plugin-vsphere/builder/vsphere/common" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.hcl2spec.go new file mode 100644 index 000000000..e02a3c174 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_clone.hcl2spec.go @@ -0,0 +1,71 @@ +// 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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.go new file mode 100644 index 000000000..86714317a --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.go @@ -0,0 +1,276 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.hcl2spec.go new file mode 100644 index 000000000..0634474a3 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone/step_customize.hcl2spec.go @@ -0,0 +1,155 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/artifact.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/artifact.go new file mode 100644 index 000000000..208e6b526 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/artifact.go @@ -0,0 +1,50 @@ +package common + +import ( + "os" + + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/cleanup_vm.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/cleanup_vm.go new file mode 100644 index 000000000..6e6636d03 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/cleanup_vm.go @@ -0,0 +1,30 @@ +package common + +import ( + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.go new file mode 100644 index 000000000..06c651a10 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.go @@ -0,0 +1,53 @@ +//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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.hcl2spec.go new file mode 100644 index 000000000..c55712475 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_location.hcl2spec.go @@ -0,0 +1,43 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_ssh.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_ssh.go new file mode 100644 index 000000000..bb967a45f --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/config_ssh.go @@ -0,0 +1,15 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.go new file mode 100644 index 000000000..1aef6cc30 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.go @@ -0,0 +1,59 @@ +//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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.hcl2spec.go new file mode 100644 index 000000000..0cec88325 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/output_config.hcl2spec.go @@ -0,0 +1,35 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.go new file mode 100644 index 000000000..fe1dfd2fb --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.go @@ -0,0 +1,81 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.hcl2spec.go new file mode 100644 index 000000000..205232829 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_cdrom.hcl2spec.go @@ -0,0 +1,33 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.go new file mode 100644 index 000000000..41b3b09ee --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.go @@ -0,0 +1,111 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.hcl2spec.go new file mode 100644 index 000000000..a42511314 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_add_floppy.hcl2spec.go @@ -0,0 +1,37 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_boot_command.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_boot_command.go new file mode 100644 index 000000000..7de930748 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_boot_command.go @@ -0,0 +1,152 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.go new file mode 100644 index 000000000..fc86d9816 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.go @@ -0,0 +1,65 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.hcl2spec.go new file mode 100644 index 000000000..a68cb3ad2 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_config_params.hcl2spec.go @@ -0,0 +1,35 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.go new file mode 100644 index 000000000..0398c6997 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.go @@ -0,0 +1,64 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.hcl2spec.go new file mode 100644 index 000000000..fa5782e33 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_connect.hcl2spec.go @@ -0,0 +1,39 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_download.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_download.go new file mode 100644 index 000000000..978e21a63 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_download.go @@ -0,0 +1,68 @@ +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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.go new file mode 100644 index 000000000..4aafda86f --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.go @@ -0,0 +1,338 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.hcl2spec.go new file mode 100644 index 000000000..21824d5d5 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_export.hcl2spec.go @@ -0,0 +1,45 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.go new file mode 100644 index 000000000..edf0314eb --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.go @@ -0,0 +1,98 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.hcl2spec.go new file mode 100644 index 000000000..334e6a644 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_hardware.hcl2spec.go @@ -0,0 +1,57 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_http_ip_discover.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_http_ip_discover.go new file mode 100644 index 000000000..933cdbfe7 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_http_ip_discover.go @@ -0,0 +1,68 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.go new file mode 100644 index 000000000..2e2350f6a --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.go @@ -0,0 +1,180 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.hcl2spec.go new file mode 100644 index 000000000..2c42538fb --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_import_to_content_library.hcl2spec.go @@ -0,0 +1,49 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remote_upload.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remote_upload.go new file mode 100644 index 000000000..2d44235fb --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remote_upload.go @@ -0,0 +1,117 @@ +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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.go new file mode 100644 index 000000000..f3a104ddf --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.go @@ -0,0 +1,46 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.hcl2spec.go new file mode 100644 index 000000000..826cacdf4 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_cdrom.hcl2spec.go @@ -0,0 +1,31 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_floppy.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_floppy.go new file mode 100644 index 000000000..01966953c --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_remove_floppy.go @@ -0,0 +1,49 @@ +package common + +import ( + "context" + + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.go new file mode 100644 index 000000000..dff47eda4 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.go @@ -0,0 +1,80 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.hcl2spec.go new file mode 100644 index 000000000..5ecc99cae --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_run.hcl2spec.go @@ -0,0 +1,31 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.go new file mode 100644 index 000000000..6d99929c5 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.go @@ -0,0 +1,109 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.hcl2spec.go new file mode 100644 index 000000000..323e771c8 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_shutdown.hcl2spec.go @@ -0,0 +1,35 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_snapshot.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_snapshot.go new file mode 100644 index 000000000..8d30543d1 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_snapshot.go @@ -0,0 +1,32 @@ +package common + +import ( + "context" + + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_ssh_key_pair.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_ssh_key_pair.go new file mode 100644 index 000000000..01dfe20b3 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_ssh_key_pair.go @@ -0,0 +1,115 @@ +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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_template.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_template.go new file mode 100644 index 000000000..12ca50047 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_template.go @@ -0,0 +1,31 @@ +package common + +import ( + "context" + + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.go new file mode 100644 index 000000000..2fb183bde --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.go @@ -0,0 +1,182 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.hcl2spec.go new file mode 100644 index 000000000..c65302f31 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/step_wait_for_ip.hcl2spec.go @@ -0,0 +1,35 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.go new file mode 100644 index 000000000..6650616d5 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.go @@ -0,0 +1,118 @@ +//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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.hcl2spec.go new file mode 100644 index 000000000..1d8fbd8c5 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common/storage_config.hcl2spec.go @@ -0,0 +1,62 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/cluster.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/cluster.go new file mode 100644 index 000000000..d17031b82 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/cluster.go @@ -0,0 +1,19 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore.go new file mode 100644 index 000000000..ae371b79f --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore.go @@ -0,0 +1,235 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore_mock.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore_mock.go new file mode 100644 index 000000000..9330d9227 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/datastore_mock.go @@ -0,0 +1,81 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/disk.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/disk.go new file mode 100644 index 000000000..a51201992 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/disk.go @@ -0,0 +1,85 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver.go new file mode 100644 index 000000000..8fbab96e5 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver.go @@ -0,0 +1,129 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver_mock.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver_mock.go new file mode 100644 index 000000000..03fa736fb --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/driver_mock.go @@ -0,0 +1,119 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/folder.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/folder.go new file mode 100644 index 000000000..75e07e594 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/folder.go @@ -0,0 +1,93 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/host.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/host.go new file mode 100644 index 000000000..31c193589 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/host.go @@ -0,0 +1,45 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/library.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/library.go new file mode 100644 index 000000000..25d7d6880 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/library.go @@ -0,0 +1,113 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/network.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/network.go new file mode 100644 index 000000000..f2d90d187 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/network.go @@ -0,0 +1,77 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/resource_pool.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/resource_pool.go new file mode 100644 index 000000000..c982078b0 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/resource_pool.go @@ -0,0 +1,91 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm.go new file mode 100644 index 000000000..0c739d108 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm.go @@ -0,0 +1,1102 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_cdrom.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_cdrom.go new file mode 100644 index 000000000..0eab0d196 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_cdrom.go @@ -0,0 +1,89 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_keyboard.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_keyboard.go new file mode 100644 index 000000000..d50e66e07 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_keyboard.go @@ -0,0 +1,39 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_mock.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_mock.go new file mode 100644 index 000000000..daf62b3c9 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver/vm_mock.go @@ -0,0 +1,235 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/builder.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/builder.go new file mode 100644 index 000000000..4255aebb7 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/builder.go @@ -0,0 +1,179 @@ +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-plugin-vsphere/builder/vsphere/common" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.go new file mode 100644 index 000000000..94a2d850c --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.go @@ -0,0 +1,107 @@ +//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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.hcl2spec.go new file mode 100644 index 000000000..c502743b7 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/config.hcl2spec.go @@ -0,0 +1,286 @@ +// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT. + +package iso + +import ( + "github.com/hashicorp/hcl/v2/hcldec" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.go new file mode 100644 index 000000000..10ff39336 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.go @@ -0,0 +1,188 @@ +//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-plugin-vsphere/builder/vsphere/common" + "github.com/hashicorp/packer-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.hcl2spec.go new file mode 100644 index 000000000..130cd6a1c --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso/step_create.hcl2spec.go @@ -0,0 +1,73 @@ +// 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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.go new file mode 100644 index 000000000..b7f885133 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.go @@ -0,0 +1,160 @@ +//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" + vsphere "github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common" + vspherepost "github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere" + "github.com/vmware/govmomi" +) + +const ( + // BuilderId for the local artifacts + BuilderIdESX = "mitchellh.vmware-esx" + + ArtifactConfFormat = "artifact.conf.format" + ArtifactConfKeepRegistered = "artifact.conf.keep_registered" + ArtifactConfSkipExport = "artifact.conf.skip_export" +) + +var builtins = map[string]string{ + vspherepost.BuilderId: "vmware", + BuilderIdESX: "vmware", + vsphere.BuilderId: "vsphere", + "packer.post-processor.artifice": "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(ArtifactConfFormat) + k := artifact.State(ArtifactConfKeepRegistered) + s := artifact.State(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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.hcl2spec.go new file mode 100644 index 000000000..214568087 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/post-processor.hcl2spec.go @@ -0,0 +1,65 @@ +// 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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_choose_datacenter.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_choose_datacenter.go new file mode 100644 index 000000000..6645c4dc5 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_choose_datacenter.go @@ -0,0 +1,35 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_folder.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_folder.go new file mode 100644 index 000000000..282848434 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_folder.go @@ -0,0 +1,86 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_snapshot.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_snapshot.go new file mode 100644 index 000000000..0fd5eaedf --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_create_snapshot.go @@ -0,0 +1,76 @@ +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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_mark_as_template.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_mark_as_template.go new file mode 100644 index 000000000..730fc3600 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template/step_mark_as_template.go @@ -0,0 +1,186 @@ +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-plugin-vsphere/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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/artifact.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/artifact.go new file mode 100644 index 000000000..90e475a28 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/artifact.go @@ -0,0 +1,47 @@ +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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.go new file mode 100644 index 000000000..827ad7273 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.go @@ -0,0 +1,280 @@ +//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/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.hcl2spec.go b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.hcl2spec.go new file mode 100644 index 000000000..da4d82973 --- /dev/null +++ b/vendor/github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere/post-processor.hcl2spec.go @@ -0,0 +1,75 @@ +// 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/vendor/github.com/vmware/govmomi/.goreleaser.yml b/vendor/github.com/vmware/govmomi/.goreleaser.yml index 6a374cd9b..9e7edeb3c 100644 --- a/vendor/github.com/vmware/govmomi/.goreleaser.yml +++ b/vendor/github.com/vmware/govmomi/.goreleaser.yml @@ -11,6 +11,7 @@ builds: - amd64 - 386 - arm64 + - mips64le env: - CGO_ENABLED=0 main: ./govc/main.go @@ -27,6 +28,7 @@ builds: - amd64 - 386 - arm64 + - mips64le env: - CGO_ENABLED=0 main: ./vcsim/main.go diff --git a/vendor/github.com/vmware/govmomi/.mailmap b/vendor/github.com/vmware/govmomi/.mailmap index 9368b7a9d..057bc427c 100644 --- a/vendor/github.com/vmware/govmomi/.mailmap +++ b/vendor/github.com/vmware/govmomi/.mailmap @@ -33,3 +33,6 @@ Uwe Bessle Uwe Bessle Vadim Egorov Zach Tucker Zee Yang +Ian Eyberg +Parveen Chahal +Yun Zhou <41678287+gh05tn0va@users.noreply.github.com> diff --git a/vendor/github.com/vmware/govmomi/.travis.yml b/vendor/github.com/vmware/govmomi/.travis.yml index 1c55bc987..fc7006ae8 100644 --- a/vendor/github.com/vmware/govmomi/.travis.yml +++ b/vendor/github.com/vmware/govmomi/.travis.yml @@ -12,7 +12,7 @@ services: false # Set the version of Go. language: go -go: 1.14 +go: 1.15 # Always set the project's Go import path to ensure that forked # builds get cloned to the correct location. @@ -44,23 +44,14 @@ jobs: install: true script: make install - - <<: *build-stage - env: GOOS=linux GOARCH=386 - - <<: *build-stage env: GOOS=darwin GOARCH=amd64 - - <<: *build-stage - env: GOOS=darwin GOARCH=386 - <<: *build-stage env: GOOS=freebsd GOARCH=amd64 - - <<: *build-stage - env: GOOS=freebsd GOARCH=386 - <<: *build-stage env: GOOS=windows GOARCH=amd64 - - <<: *build-stage - env: GOOS=windows GOARCH=386 # The test stage executes the test target. - stage: test diff --git a/vendor/github.com/vmware/govmomi/CHANGELOG.md b/vendor/github.com/vmware/govmomi/CHANGELOG.md index 5bc962871..bdc547462 100644 --- a/vendor/github.com/vmware/govmomi/CHANGELOG.md +++ b/vendor/github.com/vmware/govmomi/CHANGELOG.md @@ -1,5 +1,19 @@ # changelog +### 0.24.0 (2020-12-20) + +* Update generated API bindings to vSphere 7.0U1 release + +* Add vSAN 7.0 API bindings + +* Add AuthorizationManager.HasUserPrivilegeOnEntities wrapper + +* Add sms generated types and methods + +* Add ExtendDisk and InflateDisk wrappers to vlsm.ObjectManager + +* Add vSAN Performance Data Collection API + ### 0.23.0 (2020-06-11) * Finder: support DistributedVirtualSwitch traversal diff --git a/vendor/github.com/vmware/govmomi/CONTRIBUTORS b/vendor/github.com/vmware/govmomi/CONTRIBUTORS index 4d4819fea..bf849d644 100644 --- a/vendor/github.com/vmware/govmomi/CONTRIBUTORS +++ b/vendor/github.com/vmware/govmomi/CONTRIBUTORS @@ -8,9 +8,9 @@ abrarshivani Adam Shannon Al Biheiri Alessandro Cortiana +Alex Alex Bozhenko Alex Ellis (VMware) -Alex Alvaro Miranda Amanda H. L. de Andrade Amit Bathla @@ -31,27 +31,30 @@ Austin Parker Balu Dontu bastienbc Ben Corrie +Ben Vickers Benjamin Davini Benjamin Peterson +Bhavya Choudhary Bob Killen Brad Fitzpatrick +brian57860 Bruce Downs -Cédric Blomart Cheng Cheng Chethan Venkatesh Chris Marchesi Christian Höltje Clint Greenwood CuiHaozhi -Daniel Mueller +Cédric Blomart Dan Ilan +Daniel Mueller Danny Lockard Dave Gress Dave Smith-Uchida Dave Tucker -Davide Agnello David Gress David Stark +Davide Agnello Davinder Kumar demarey dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> @@ -82,6 +85,7 @@ Hasan Mahmood Henrik Hodne hkumar hui luo +Ian Eyberg Isaac Rodman Ivan Mikushin Ivan Porto Carrero @@ -91,16 +95,18 @@ Jeremy Canady jeremy-clerc Jiatong Wang jingyizPensando -João Pereira Jonas Ausevicius Jorge Sevilla +João Pereira kayrus Kevin George +Leslie Wang leslie-qiwa Lintong Jiang Liping Xue Louie Jiang Luther Monson +Madanagopal Arunachalam maplain Marc Carmier Marcus Tan @@ -109,15 +115,17 @@ Marin Atanasov Nikolov Mario Trangoni Mark Peek Matt Clay -Matthew Cosgrove Matt Moore Matt Moriarity +Matthew Cosgrove Mevan Samaratunga +Michael Gasch Michal Jankowski mingwei Nicolas Lamirault Omar Kohl Parham Alvani +Parveen Chahal Pierre Gronlier Pieter Noordhuis prydin @@ -125,11 +133,12 @@ rHermes Rowan Jacobs rsikdar runner.mei -Sandeep Pissay Srinivasa Rao S.Çağlar Onur +Sandeep Pissay Srinivasa Rao Sergey Ignatov serokles Shalini Bhaskara +Shaozhen Ding Shawn Neal shylasrinivas sky-joker @@ -157,12 +166,17 @@ Waldek Maleska William Lam Witold Krecicki xing-yang -yangxi Yang Yang +yangxi Yann Hodique +Yash Nitin Desai +Yassine TIJANI +yiyingy ykakarap +Yogesh Sobale <6104071+ysobale@users.noreply.github.com> +Yun Zhou Yuya Kusakabe -Zacharias Taubert Zach Tucker +Zacharias Taubert Zee Yang zyuxin diff --git a/vendor/github.com/vmware/govmomi/README.md b/vendor/github.com/vmware/govmomi/README.md index db17cc664..2bc127e2b 100644 --- a/vendor/github.com/vmware/govmomi/README.md +++ b/vendor/github.com/vmware/govmomi/README.md @@ -89,6 +89,8 @@ Refer to the [CHANGELOG](CHANGELOG.md) for version to version changes. * [OPS](https://github.com/nanovms/ops) +* [VMware Event Broker Appliance](https://github.com/vmware-samples/vcenter-event-broker-appliance/tree/development/vmware-event-router) + ## Related projects * [rbvmomi](https://github.com/vmware/rbvmomi) diff --git a/vendor/github.com/vmware/govmomi/find/finder.go b/vendor/github.com/vmware/govmomi/find/finder.go index a46c70bf5..cd71d183b 100644 --- a/vendor/github.com/vmware/govmomi/find/finder.go +++ b/vendor/github.com/vmware/govmomi/find/finder.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2014-2020 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import ( "path" "strings" + "github.com/vmware/govmomi/internal" "github.com/vmware/govmomi/list" "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/property" @@ -67,6 +68,18 @@ func (f *Finder) SetDatacenter(dc *object.Datacenter) *Finder { return f } +// InventoryPath composes the given object's inventory path. +// There is no vSphere property or method that provides an inventory path directly. +// This method uses the ManagedEntity.Parent field to determine the ancestry tree of the object and +// the ManagedEntity.Name field for each ancestor to compose the path. +func InventoryPath(ctx context.Context, client *vim25.Client, obj types.ManagedObjectReference) (string, error) { + entities, err := mo.Ancestors(ctx, client, client.ServiceContent.PropertyCollector, obj) + if err != nil { + return "", err + } + return internal.InventoryPath(entities), nil +} + // findRoot makes it possible to use "find" mode with a different root path. // Example: ResourcePoolList("/dc1/host/cluster1/...") func (f *Finder) findRoot(ctx context.Context, root *list.Element, parts []string) bool { @@ -103,8 +116,8 @@ func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, isPath := strings.Contains(arg, "/") root := list.Element{ - Path: "/", Object: object.NewRootFolder(f.client), + Path: "/", } parts := list.ToParts(arg) @@ -119,19 +132,10 @@ func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, return nil, err } - mes, err := mo.Ancestors(ctx, f.client, f.client.ServiceContent.PropertyCollector, pivot.Reference()) + root.Path, err = InventoryPath(ctx, f.client, pivot.Reference()) if err != nil { return nil, err } - - for _, me := range mes { - // Skip root entity in building inventory path. - if me.Parent == nil { - continue - } - root.Path = path.Join(root.Path, me.Name) - } - root.Object = pivot parts = parts[1:] } @@ -281,8 +285,7 @@ func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool, in return f.find(ctx, path, s) } -// Element returns an Element for the given ManagedObjectReference -// This method is only useful for looking up the InventoryPath of a ManagedObjectReference. +// Element is deprecated, use InventoryPath() instead. func (f *Finder) Element(ctx context.Context, ref types.ManagedObjectReference) (*list.Element, error) { rl := func(_ context.Context) (object.Reference, error) { return ref, nil @@ -311,7 +314,7 @@ func (f *Finder) Element(ctx context.Context, ref types.ManagedObjectReference) // ObjectReference converts the given ManagedObjectReference to a type from the object package via object.NewReference // with the object.Common.InventoryPath field set. func (f *Finder) ObjectReference(ctx context.Context, ref types.ManagedObjectReference) (object.Reference, error) { - e, err := f.Element(ctx, ref) + path, err := InventoryPath(ctx, f.client, ref) if err != nil { return nil, err } @@ -322,7 +325,7 @@ func (f *Finder) ObjectReference(ctx context.Context, ref types.ManagedObjectRef SetInventoryPath(string) } - r.(common).SetInventoryPath(e.Path) + r.(common).SetInventoryPath(path) if f.dc != nil { if ds, ok := r.(*object.Datastore); ok { diff --git a/vendor/github.com/vmware/govmomi/internal/helpers.go b/vendor/github.com/vmware/govmomi/internal/helpers.go new file mode 100644 index 000000000..945f1d474 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/internal/helpers.go @@ -0,0 +1,38 @@ +/* +Copyright (c) 2020 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "path" + + "github.com/vmware/govmomi/vim25/mo" +) + +// InventoryPath composed of entities by Name +func InventoryPath(entities []mo.ManagedEntity) string { + val := "/" + + for _, entity := range entities { + // Skip root folder in building inventory path. + if entity.Parent == nil { + continue + } + val = path.Join(val, entity.Name) + } + + return val +} diff --git a/vendor/github.com/vmware/govmomi/internal/methods.go b/vendor/github.com/vmware/govmomi/internal/methods.go new file mode 100644 index 000000000..95ccee8d2 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/internal/methods.go @@ -0,0 +1,123 @@ +/* +Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "context" + + "github.com/vmware/govmomi/vim25/soap" +) + +type RetrieveDynamicTypeManagerBody struct { + Req *RetrieveDynamicTypeManagerRequest `xml:"urn:vim25 RetrieveDynamicTypeManager"` + Res *RetrieveDynamicTypeManagerResponse `xml:"urn:vim25 RetrieveDynamicTypeManagerResponse"` + Fault_ *soap.Fault +} + +func (b *RetrieveDynamicTypeManagerBody) Fault() *soap.Fault { return b.Fault_ } + +func RetrieveDynamicTypeManager(ctx context.Context, r soap.RoundTripper, req *RetrieveDynamicTypeManagerRequest) (*RetrieveDynamicTypeManagerResponse, error) { + var reqBody, resBody RetrieveDynamicTypeManagerBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type RetrieveManagedMethodExecuterBody struct { + Req *RetrieveManagedMethodExecuterRequest `xml:"urn:vim25 RetrieveManagedMethodExecuter"` + Res *RetrieveManagedMethodExecuterResponse `xml:"urn:vim25 RetrieveManagedMethodExecuterResponse"` + Fault_ *soap.Fault +} + +func (b *RetrieveManagedMethodExecuterBody) Fault() *soap.Fault { return b.Fault_ } + +func RetrieveManagedMethodExecuter(ctx context.Context, r soap.RoundTripper, req *RetrieveManagedMethodExecuterRequest) (*RetrieveManagedMethodExecuterResponse, error) { + var reqBody, resBody RetrieveManagedMethodExecuterBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type DynamicTypeMgrQueryMoInstancesBody struct { + Req *DynamicTypeMgrQueryMoInstancesRequest `xml:"urn:vim25 DynamicTypeMgrQueryMoInstances"` + Res *DynamicTypeMgrQueryMoInstancesResponse `xml:"urn:vim25 DynamicTypeMgrQueryMoInstancesResponse"` + Fault_ *soap.Fault +} + +func (b *DynamicTypeMgrQueryMoInstancesBody) Fault() *soap.Fault { return b.Fault_ } + +func DynamicTypeMgrQueryMoInstances(ctx context.Context, r soap.RoundTripper, req *DynamicTypeMgrQueryMoInstancesRequest) (*DynamicTypeMgrQueryMoInstancesResponse, error) { + var reqBody, resBody DynamicTypeMgrQueryMoInstancesBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type DynamicTypeMgrQueryTypeInfoBody struct { + Req *DynamicTypeMgrQueryTypeInfoRequest `xml:"urn:vim25 DynamicTypeMgrQueryTypeInfo"` + Res *DynamicTypeMgrQueryTypeInfoResponse `xml:"urn:vim25 DynamicTypeMgrQueryTypeInfoResponse"` + Fault_ *soap.Fault +} + +func (b *DynamicTypeMgrQueryTypeInfoBody) Fault() *soap.Fault { return b.Fault_ } + +func DynamicTypeMgrQueryTypeInfo(ctx context.Context, r soap.RoundTripper, req *DynamicTypeMgrQueryTypeInfoRequest) (*DynamicTypeMgrQueryTypeInfoResponse, error) { + var reqBody, resBody DynamicTypeMgrQueryTypeInfoBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type ExecuteSoapBody struct { + Req *ExecuteSoapRequest `xml:"urn:vim25 ExecuteSoap"` + Res *ExecuteSoapResponse `xml:"urn:vim25 ExecuteSoapResponse"` + Fault_ *soap.Fault +} + +func (b *ExecuteSoapBody) Fault() *soap.Fault { return b.Fault_ } + +func ExecuteSoap(ctx context.Context, r soap.RoundTripper, req *ExecuteSoapRequest) (*ExecuteSoapResponse, error) { + var reqBody, resBody ExecuteSoapBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} diff --git a/vendor/github.com/vmware/govmomi/internal/types.go b/vendor/github.com/vmware/govmomi/internal/types.go new file mode 100644 index 000000000..b84103b89 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/internal/types.go @@ -0,0 +1,270 @@ +/* +Copyright (c) 2014 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "reflect" + + "github.com/vmware/govmomi/vim25/types" +) + +type DynamicTypeMgrQueryMoInstancesRequest struct { + This types.ManagedObjectReference `xml:"_this"` + FilterSpec BaseDynamicTypeMgrFilterSpec `xml:"filterSpec,omitempty,typeattr"` +} + +type DynamicTypeMgrQueryMoInstancesResponse struct { + Returnval []DynamicTypeMgrMoInstance `xml:"urn:vim25 returnval"` +} + +type DynamicTypeEnumTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + Value []string `xml:"value,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeEnumTypeInfo", reflect.TypeOf((*DynamicTypeEnumTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrAllTypeInfoRequest struct { + types.DynamicData + + ManagedTypeInfo []DynamicTypeMgrManagedTypeInfo `xml:"managedTypeInfo,omitempty"` + EnumTypeInfo []DynamicTypeEnumTypeInfo `xml:"enumTypeInfo,omitempty"` + DataTypeInfo []DynamicTypeMgrDataTypeInfo `xml:"dataTypeInfo,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrAllTypeInfo", reflect.TypeOf((*DynamicTypeMgrAllTypeInfoRequest)(nil)).Elem()) +} + +type DynamicTypeMgrAnnotation struct { + types.DynamicData + + Name string `xml:"name"` + Parameter []string `xml:"parameter,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrAnnotation", reflect.TypeOf((*DynamicTypeMgrAnnotation)(nil)).Elem()) +} + +type DynamicTypeMgrDataTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + Base []string `xml:"base,omitempty"` + Property []DynamicTypeMgrPropertyTypeInfo `xml:"property,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrDataTypeInfo", reflect.TypeOf((*DynamicTypeMgrDataTypeInfo)(nil)).Elem()) +} + +func (b *DynamicTypeMgrFilterSpec) GetDynamicTypeMgrFilterSpec() *DynamicTypeMgrFilterSpec { return b } + +type BaseDynamicTypeMgrFilterSpec interface { + GetDynamicTypeMgrFilterSpec() *DynamicTypeMgrFilterSpec +} + +type DynamicTypeMgrFilterSpec struct { + types.DynamicData +} + +func init() { + types.Add("DynamicTypeMgrFilterSpec", reflect.TypeOf((*DynamicTypeMgrFilterSpec)(nil)).Elem()) +} + +type DynamicTypeMgrManagedTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + Base []string `xml:"base,omitempty"` + Property []DynamicTypeMgrPropertyTypeInfo `xml:"property,omitempty"` + Method []DynamicTypeMgrMethodTypeInfo `xml:"method,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrManagedTypeInfo", reflect.TypeOf((*DynamicTypeMgrManagedTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrMethodTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + WsdlName string `xml:"wsdlName"` + Version string `xml:"version"` + ParamTypeInfo []DynamicTypeMgrParamTypeInfo `xml:"paramTypeInfo,omitempty"` + ReturnTypeInfo *DynamicTypeMgrParamTypeInfo `xml:"returnTypeInfo,omitempty"` + Fault []string `xml:"fault,omitempty"` + PrivId string `xml:"privId,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrMethodTypeInfo", reflect.TypeOf((*DynamicTypeMgrMethodTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrMoFilterSpec struct { + DynamicTypeMgrFilterSpec + + Id string `xml:"id,omitempty"` + TypeSubstr string `xml:"typeSubstr,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrMoFilterSpec", reflect.TypeOf((*DynamicTypeMgrMoFilterSpec)(nil)).Elem()) +} + +type DynamicTypeMgrMoInstance struct { + types.DynamicData + + Id string `xml:"id"` + MoType string `xml:"moType"` +} + +func init() { + types.Add("DynamicTypeMgrMoInstance", reflect.TypeOf((*DynamicTypeMgrMoInstance)(nil)).Elem()) +} + +type DynamicTypeMgrParamTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + Version string `xml:"version"` + Type string `xml:"type"` + PrivId string `xml:"privId,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrParamTypeInfo", reflect.TypeOf((*DynamicTypeMgrParamTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrPropertyTypeInfo struct { + types.DynamicData + + Name string `xml:"name"` + Version string `xml:"version"` + Type string `xml:"type"` + PrivId string `xml:"privId,omitempty"` + MsgIdFormat string `xml:"msgIdFormat,omitempty"` + Annotation []DynamicTypeMgrAnnotation `xml:"annotation,omitempty"` +} + +type DynamicTypeMgrQueryTypeInfoRequest struct { + This types.ManagedObjectReference `xml:"_this"` + FilterSpec BaseDynamicTypeMgrFilterSpec `xml:"filterSpec,omitempty,typeattr"` +} + +type DynamicTypeMgrQueryTypeInfoResponse struct { + Returnval DynamicTypeMgrAllTypeInfoRequest `xml:"urn:vim25 returnval"` +} + +func init() { + types.Add("DynamicTypeMgrPropertyTypeInfo", reflect.TypeOf((*DynamicTypeMgrPropertyTypeInfo)(nil)).Elem()) +} + +type DynamicTypeMgrTypeFilterSpec struct { + DynamicTypeMgrFilterSpec + + TypeSubstr string `xml:"typeSubstr,omitempty"` +} + +func init() { + types.Add("DynamicTypeMgrTypeFilterSpec", reflect.TypeOf((*DynamicTypeMgrTypeFilterSpec)(nil)).Elem()) +} + +type ReflectManagedMethodExecuterSoapArgument struct { + types.DynamicData + + Name string `xml:"name"` + Val string `xml:"val"` +} + +func init() { + types.Add("ReflectManagedMethodExecuterSoapArgument", reflect.TypeOf((*ReflectManagedMethodExecuterSoapArgument)(nil)).Elem()) +} + +type ReflectManagedMethodExecuterSoapFault struct { + types.DynamicData + + FaultMsg string `xml:"faultMsg"` + FaultDetail string `xml:"faultDetail,omitempty"` +} + +func init() { + types.Add("ReflectManagedMethodExecuterSoapFault", reflect.TypeOf((*ReflectManagedMethodExecuterSoapFault)(nil)).Elem()) +} + +type ReflectManagedMethodExecuterSoapResult struct { + types.DynamicData + + Response string `xml:"response,omitempty"` + Fault *ReflectManagedMethodExecuterSoapFault `xml:"fault,omitempty"` +} + +type RetrieveDynamicTypeManagerRequest struct { + This types.ManagedObjectReference `xml:"_this"` +} + +type RetrieveDynamicTypeManagerResponse struct { + Returnval *InternalDynamicTypeManager `xml:"urn:vim25 returnval"` +} + +type RetrieveManagedMethodExecuterRequest struct { + This types.ManagedObjectReference `xml:"_this"` +} + +func init() { + types.Add("RetrieveManagedMethodExecuter", reflect.TypeOf((*RetrieveManagedMethodExecuterRequest)(nil)).Elem()) +} + +type RetrieveManagedMethodExecuterResponse struct { + Returnval *ReflectManagedMethodExecuter `xml:"urn:vim25 returnval"` +} + +type InternalDynamicTypeManager struct { + types.ManagedObjectReference +} + +type ReflectManagedMethodExecuter struct { + types.ManagedObjectReference +} + +type ExecuteSoapRequest struct { + This types.ManagedObjectReference `xml:"_this"` + Moid string `xml:"moid"` + Version string `xml:"version"` + Method string `xml:"method"` + Argument []ReflectManagedMethodExecuterSoapArgument `xml:"argument,omitempty"` +} + +type ExecuteSoapResponse struct { + Returnval *ReflectManagedMethodExecuterSoapResult `xml:"urn:vim25 returnval"` +} diff --git a/vendor/github.com/vmware/govmomi/object/authorization_manager.go b/vendor/github.com/vmware/govmomi/object/authorization_manager.go index b703258fe..5cd6851a8 100644 --- a/vendor/github.com/vmware/govmomi/object/authorization_manager.go +++ b/vendor/github.com/vmware/govmomi/object/authorization_manager.go @@ -172,3 +172,50 @@ func (m AuthorizationManager) UpdateRole(ctx context.Context, id int32, name str _, err := methods.UpdateAuthorizationRole(ctx, m.Client(), &req) return err } + +func (m AuthorizationManager) HasUserPrivilegeOnEntities(ctx context.Context, entities []types.ManagedObjectReference, userName string, privID []string) ([]types.EntityPrivilege, error) { + req := types.HasUserPrivilegeOnEntities{ + This: m.Reference(), + Entities: entities, + UserName: userName, + PrivId: privID, + } + + res, err := methods.HasUserPrivilegeOnEntities(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) HasPrivilegeOnEntity(ctx context.Context, entity types.ManagedObjectReference, sessionID string, privID []string) ([]bool, error) { + req := types.HasPrivilegeOnEntity{ + This: m.Reference(), + Entity: entity, + SessionId: sessionID, + PrivId: privID, + } + + res, err := methods.HasPrivilegeOnEntity(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (m AuthorizationManager) FetchUserPrivilegeOnEntities(ctx context.Context, entities []types.ManagedObjectReference, userName string) ([]types.UserPrivilegeResult, error) { + req := types.FetchUserPrivilegeOnEntities{ + This: m.Reference(), + Entities: entities, + UserName: userName, + } + + res, err := methods.FetchUserPrivilegeOnEntities(ctx, m.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_app.go b/vendor/github.com/vmware/govmomi/object/virtual_app.go index 4811178f1..b7311b3e3 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_app.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_app.go @@ -103,3 +103,19 @@ func (p VirtualApp) Suspend(ctx context.Context) (*Task, error) { return NewTask(p.c, res.Returnval), nil } + +func (p VirtualApp) Clone(ctx context.Context, name string, target types.ManagedObjectReference, spec types.VAppCloneSpec) (*Task, error) { + req := types.CloneVApp_Task{ + This: p.Reference(), + Name: name, + Target: target, + Spec: spec, + } + + res, err := methods.CloneVApp_Task(ctx, p.c, &req) + if err != nil { + return nil, err + } + + return NewTask(p.c, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/object/virtual_device_list.go b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go index 58b61f5d5..f25f6f2c1 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_device_list.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go @@ -19,6 +19,7 @@ package object import ( "errors" "fmt" + "math/rand" "path/filepath" "reflect" "regexp" @@ -67,7 +68,7 @@ func EthernetCardTypes() VirtualDeviceList { &types.VirtualSriovEthernetCard{}, }).Select(func(device types.BaseVirtualDevice) bool { c := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() - c.GetVirtualDevice().Key = -1 + c.GetVirtualDevice().Key = int32(rand.Uint32()) * -1 return true }) } @@ -134,6 +135,9 @@ func (l VirtualDeviceList) SelectByBackingInfo(backing types.BaseVirtualDeviceBa b := backing.(*types.VirtualEthernetCardDistributedVirtualPortBackingInfo) return a.Port.SwitchUuid == b.Port.SwitchUuid && a.Port.PortgroupKey == b.Port.PortgroupKey + case *types.VirtualEthernetCardOpaqueNetworkBackingInfo: + b := backing.(*types.VirtualEthernetCardOpaqueNetworkBackingInfo) + return a.OpaqueNetworkId == b.OpaqueNetworkId case *types.VirtualDiskFlatVer2BackingInfo: b := backing.(*types.VirtualDiskFlatVer2BackingInfo) if a.Parent != nil && b.Parent != nil { @@ -433,7 +437,7 @@ func (l VirtualDeviceList) AssignController(device types.BaseVirtualDevice, c ty d.UnitNumber = new(int32) *d.UnitNumber = l.newUnitNumber(c) if d.Key == 0 { - d.Key = -1 + d.Key = int32(rand.Uint32()) * -1 } } diff --git a/vendor/github.com/vmware/govmomi/object/virtual_machine.go b/vendor/github.com/vmware/govmomi/object/virtual_machine.go index ed86a3922..1d85047fc 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_machine.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_machine.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2021 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,6 +40,34 @@ type VirtualMachine struct { Common } +// extractDiskLayoutFiles is a helper function used to extract file keys for +// all disk files attached to the virtual machine at the current point of +// running. +func extractDiskLayoutFiles(diskLayoutList []types.VirtualMachineFileLayoutExDiskLayout) []int { + var result []int + + for _, layoutExDisk := range diskLayoutList { + for _, link := range layoutExDisk.Chain { + for i := range link.FileKey { // diskDescriptor, diskExtent pairs + result = append(result, int(link.FileKey[i])) + } + } + } + + return result +} + +// removeKey is a helper function for removing a specific file key from a list +// of keys associated with disks attached to a virtual machine. +func removeKey(l *[]int, key int) { + for i, k := range *l { + if k == key { + *l = append((*l)[:i], (*l)[i+1:]...) + break + } + } +} + func NewVirtualMachine(c *vim25.Client, ref types.ManagedObjectReference) *VirtualMachine { return &VirtualMachine{ Common: NewCommon(c, ref), @@ -181,6 +209,20 @@ func (v VirtualMachine) Clone(ctx context.Context, folder *Folder, name string, return NewTask(v.c, res.Returnval), nil } +func (v VirtualMachine) InstantClone(ctx context.Context, config types.VirtualMachineInstantCloneSpec) (*Task, error) { + req := types.InstantClone_Task{ + This: v.Reference(), + Spec: config, + } + + res, err := methods.InstantClone_Task(ctx, v.c, &req) + if err != nil { + return nil, err + } + + return NewTask(v.c, res.Returnval), nil +} + func (v VirtualMachine) Customize(ctx context.Context, spec types.CustomizationSpec) (*Task, error) { req := types.CustomizeVM_Task{ This: v.Reference(), @@ -469,6 +511,41 @@ func (v VirtualMachine) RemoveDevice(ctx context.Context, keepFiles bool, device return v.configureDevice(ctx, types.VirtualDeviceConfigSpecOperationRemove, fop, device...) } +// AttachDisk attaches the given disk to the VirtualMachine +func (v VirtualMachine) AttachDisk(ctx context.Context, id string, datastore *Datastore, controllerKey int32, unitNumber int32) error { + req := types.AttachDisk_Task{ + This: v.Reference(), + DiskId: types.ID{Id: id}, + Datastore: datastore.Reference(), + ControllerKey: controllerKey, + UnitNumber: &unitNumber, + } + + res, err := methods.AttachDisk_Task(ctx, v.c, &req) + if err != nil { + return err + } + + task := NewTask(v.c, res.Returnval) + return task.Wait(ctx) +} + +// DetachDisk detaches the given disk from the VirtualMachine +func (v VirtualMachine) DetachDisk(ctx context.Context, id string) error { + req := types.DetachDisk_Task{ + This: v.Reference(), + DiskId: types.ID{Id: id}, + } + + res, err := methods.DetachDisk_Task(ctx, v.c, &req) + if err != nil { + return err + } + + task := NewTask(v.c, res.Returnval) + return task.Wait(ctx) +} + // BootOptions returns the VirtualMachine's config.bootOptions property. func (v VirtualMachine) BootOptions(ctx context.Context) (*types.VirtualMachineBootOptions, error) { var o mo.VirtualMachine @@ -579,6 +656,63 @@ func (m snapshotMap) add(parent string, tree []types.VirtualMachineSnapshotTree) } } +// SnapshotSize calculates the size of a given snapshot in bytes. If the +// snapshot is current, disk files not associated with any parent snapshot are +// included in size calculations. This allows for measuring and including the +// growth from the last fixed snapshot to the present state. +func SnapshotSize(info types.ManagedObjectReference, parent *types.ManagedObjectReference, vmlayout *types.VirtualMachineFileLayoutEx, isCurrent bool) int { + var fileKeyList []int + var parentFiles []int + var allSnapshotFiles []int + + diskFiles := extractDiskLayoutFiles(vmlayout.Disk) + + for _, layout := range vmlayout.Snapshot { + diskLayout := extractDiskLayoutFiles(layout.Disk) + allSnapshotFiles = append(allSnapshotFiles, diskLayout...) + + if layout.Key.Value == info.Value { + fileKeyList = append(fileKeyList, int(layout.DataKey)) // The .vmsn file + fileKeyList = append(fileKeyList, diskLayout...) // The .vmdk files + } else if parent != nil && layout.Key.Value == parent.Value { + parentFiles = append(parentFiles, diskLayout...) + } + } + + for _, parentFile := range parentFiles { + removeKey(&fileKeyList, parentFile) + } + + for _, file := range allSnapshotFiles { + removeKey(&diskFiles, file) + } + + fileKeyMap := make(map[int]types.VirtualMachineFileLayoutExFileInfo) + for _, file := range vmlayout.File { + fileKeyMap[int(file.Key)] = file + } + + size := 0 + + for _, fileKey := range fileKeyList { + file := fileKeyMap[fileKey] + if parent != nil || + (file.Type != string(types.VirtualMachineFileLayoutExFileTypeDiskDescriptor) && + file.Type != string(types.VirtualMachineFileLayoutExFileTypeDiskExtent)) { + size += int(file.Size) + } + } + + if isCurrent { + for _, diskFile := range diskFiles { + file := fileKeyMap[diskFile] + size += int(file.Size) + } + } + + return size +} + // FindSnapshot supports snapshot lookup by name, where name can be: // 1) snapshot ManagedObjectReference.Value (unique) // 2) snapshot name (may not be unique) diff --git a/vendor/github.com/vmware/govmomi/ovf/cim.go b/vendor/github.com/vmware/govmomi/ovf/cim.go new file mode 100644 index 000000000..427699954 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/cim.go @@ -0,0 +1,128 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ovf + +import ( + "github.com/vmware/govmomi/vim25/types" +) + +/* +Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_VirtualSystemSettingData.xsd +*/ + +type CIMVirtualSystemSettingData struct { + ElementName string `xml:"ElementName"` + InstanceID string `xml:"InstanceID"` + + AutomaticRecoveryAction *uint8 `xml:"AutomaticRecoveryAction"` + AutomaticShutdownAction *uint8 `xml:"AutomaticShutdownAction"` + AutomaticStartupAction *uint8 `xml:"AutomaticStartupAction"` + AutomaticStartupActionDelay *string `xml:"AutomaticStartupActionDelay>Interval"` + AutomaticStartupActionSequenceNumber *uint16 `xml:"AutomaticStartupActionSequenceNumber"` + Caption *string `xml:"Caption"` + ConfigurationDataRoot *string `xml:"ConfigurationDataRoot"` + ConfigurationFile *string `xml:"ConfigurationFile"` + ConfigurationID *string `xml:"ConfigurationID"` + CreationTime *string `xml:"CreationTime"` + Description *string `xml:"Description"` + LogDataRoot *string `xml:"LogDataRoot"` + Notes []string `xml:"Notes"` + RecoveryFile *string `xml:"RecoveryFile"` + SnapshotDataRoot *string `xml:"SnapshotDataRoot"` + SuspendDataRoot *string `xml:"SuspendDataRoot"` + SwapFileDataRoot *string `xml:"SwapFileDataRoot"` + VirtualSystemIdentifier *string `xml:"VirtualSystemIdentifier"` + VirtualSystemType *string `xml:"VirtualSystemType"` +} + +/* +Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_ResourceAllocationSettingData.xsd +*/ + +type CIMResourceAllocationSettingData struct { + ElementName string `xml:"ElementName"` + InstanceID string `xml:"InstanceID"` + + ResourceType *uint16 `xml:"ResourceType"` + OtherResourceType *string `xml:"OtherResourceType"` + ResourceSubType *string `xml:"ResourceSubType"` + + AddressOnParent *string `xml:"AddressOnParent"` + Address *string `xml:"Address"` + AllocationUnits *string `xml:"AllocationUnits"` + AutomaticAllocation *bool `xml:"AutomaticAllocation"` + AutomaticDeallocation *bool `xml:"AutomaticDeallocation"` + Caption *string `xml:"Caption"` + Connection []string `xml:"Connection"` + ConsumerVisibility *uint16 `xml:"ConsumerVisibility"` + Description *string `xml:"Description"` + HostResource []string `xml:"HostResource"` + Limit *uint64 `xml:"Limit"` + MappingBehavior *uint `xml:"MappingBehavior"` + Parent *string `xml:"Parent"` + PoolID *string `xml:"PoolID"` + Reservation *uint64 `xml:"Reservation"` + VirtualQuantity *uint `xml:"VirtualQuantity"` + VirtualQuantityUnits *string `xml:"VirtualQuantityUnits"` + Weight *uint `xml:"Weight"` +} + +/* +Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_StorageAllocationSettingData.xsd +*/ +type CIMStorageAllocationSettingData struct { + ElementName string `xml:"ElementName"` + InstanceID string `xml:"InstanceID"` + + ResourceType *uint16 `xml:"ResourceType"` + OtherResourceType *string `xml:"OtherResourceType"` + ResourceSubType *string `xml:"ResourceSubType"` + + Access *uint16 `xml:"Access"` + Address *string `xml:"Address"` + AddressOnParent *string `xml:"AddressOnParent"` + AllocationUnits *string `xml:"AllocationUnits"` + AutomaticAllocation *bool `xml:"AutomaticAllocation"` + AutomaticDeallocation *bool `xml:"AutomaticDeallocation"` + Caption *string `xml:"Caption"` + ChangeableType *uint16 `xml:"ChangeableType"` + ComponentSetting []types.AnyType `xml:"ComponentSetting"` + ConfigurationName *string `xml:"ConfigurationName"` + Connection []string `xml:"Connection"` + ConsumerVisibility *uint16 `xml:"ConsumerVisibility"` + Description *string `xml:"Description"` + Generation *uint64 `xml:"Generation"` + HostExtentName *string `xml:"HostExtentName"` + HostExtentNameFormat *uint16 `xml:"HostExtentNameFormat"` + HostExtentNameNamespace *uint16 `xml:"HostExtentNameNamespace"` + HostExtentStartingAddress *uint64 `xml:"HostExtentStartingAddress"` + HostResource []string `xml:"HostResource"` + HostResourceBlockSize *uint64 `xml:"HostResourceBlockSize"` + Limit *uint64 `xml:"Limit"` + MappingBehavior *uint `xml:"MappingBehavior"` + OtherHostExtentNameFormat *string `xml:"OtherHostExtentNameFormat"` + OtherHostExtentNameNamespace *string `xml:"OtherHostExtentNameNamespace"` + Parent *string `xml:"Parent"` + PoolID *string `xml:"PoolID"` + Reservation *uint64 `xml:"Reservation"` + SoID *string `xml:"SoID"` + SoOrgID *string `xml:"SoOrgID"` + VirtualQuantity *uint `xml:"VirtualQuantity"` + VirtualQuantityUnits *string `xml:"VirtualQuantityUnits"` + VirtualResourceBlockSize *uint64 `xml:"VirtualResourceBlockSize"` + Weight *uint `xml:"Weight"` +} diff --git a/vendor/github.com/vmware/govmomi/ovf/doc.go b/vendor/github.com/vmware/govmomi/ovf/doc.go new file mode 100644 index 000000000..6284b1ac5 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/doc.go @@ -0,0 +1,25 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Package ovf provides functionality to unmarshal and inspect the structure +of an OVF file. It is not a complete implementation of the specification and +is intended to be used to import virtual infrastructure into vSphere. + +For a complete specification of the OVF standard, refer to: +https://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.0.pdf +*/ +package ovf diff --git a/vendor/github.com/vmware/govmomi/ovf/env.go b/vendor/github.com/vmware/govmomi/ovf/env.go new file mode 100644 index 000000000..3ec1b99d0 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/env.go @@ -0,0 +1,99 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ovf + +import ( + "bytes" + "fmt" + + "github.com/vmware/govmomi/vim25/xml" +) + +const ( + ovfEnvHeader = `` + ovfEnvPlatformSection = ` + %s + %s + %s + %s + ` + ovfEnvPropertyHeader = `` + ovfEnvPropertyEntry = `` + ovfEnvPropertyFooter = `` + ovfEnvFooter = `` +) + +type Env struct { + XMLName xml.Name `xml:"http://schemas.dmtf.org/ovf/environment/1 Environment"` + ID string `xml:"id,attr"` + EsxID string `xml:"http://www.vmware.com/schema/ovfenv esxId,attr"` + + Platform *PlatformSection `xml:"PlatformSection"` + Property *PropertySection `xml:"PropertySection"` +} + +type PlatformSection struct { + Kind string `xml:"Kind"` + Version string `xml:"Version"` + Vendor string `xml:"Vendor"` + Locale string `xml:"Locale"` +} + +type PropertySection struct { + Properties []EnvProperty `xml:"Property"` +} + +type EnvProperty struct { + Key string `xml:"key,attr"` + Value string `xml:"value,attr"` +} + +// Marshal marshals Env to xml by using xml.Marshal. +func (e Env) Marshal() (string, error) { + x, err := xml.Marshal(e) + if err != nil { + return "", err + } + + return fmt.Sprintf("%s%s", xml.Header, x), nil +} + +// MarshalManual manually marshals Env to xml suitable for a vApp guest. +// It exists to overcome the lack of expressiveness in Go's XML namespaces. +func (e Env) MarshalManual() string { + var buffer bytes.Buffer + + buffer.WriteString(xml.Header) + buffer.WriteString(fmt.Sprintf(ovfEnvHeader, e.EsxID)) + buffer.WriteString(fmt.Sprintf(ovfEnvPlatformSection, e.Platform.Kind, e.Platform.Version, e.Platform.Vendor, e.Platform.Locale)) + + buffer.WriteString(fmt.Sprint(ovfEnvPropertyHeader)) + for _, p := range e.Property.Properties { + buffer.WriteString(fmt.Sprintf(ovfEnvPropertyEntry, p.Key, p.Value)) + } + buffer.WriteString(fmt.Sprint(ovfEnvPropertyFooter)) + + buffer.WriteString(fmt.Sprint(ovfEnvFooter)) + + return buffer.String() +} diff --git a/vendor/github.com/vmware/govmomi/ovf/envelope.go b/vendor/github.com/vmware/govmomi/ovf/envelope.go new file mode 100644 index 000000000..274adb9df --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/envelope.go @@ -0,0 +1,208 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ovf + +type Envelope struct { + References []File `xml:"References>File"` + + // Package level meta-data + Annotation *AnnotationSection `xml:"AnnotationSection"` + Product *ProductSection `xml:"ProductSection"` + Network *NetworkSection `xml:"NetworkSection"` + Disk *DiskSection `xml:"DiskSection"` + OperatingSystem *OperatingSystemSection `xml:"OperatingSystemSection"` + Eula *EulaSection `xml:"EulaSection"` + VirtualHardware *VirtualHardwareSection `xml:"VirtualHardwareSection"` + ResourceAllocation *ResourceAllocationSection `xml:"ResourceAllocationSection"` + DeploymentOption *DeploymentOptionSection `xml:"DeploymentOptionSection"` + + // Content: A VirtualSystem or a VirtualSystemCollection + VirtualSystem *VirtualSystem `xml:"VirtualSystem"` +} + +type VirtualSystem struct { + Content + + Annotation []AnnotationSection `xml:"AnnotationSection"` + Product []ProductSection `xml:"ProductSection"` + OperatingSystem []OperatingSystemSection `xml:"OperatingSystemSection"` + Eula []EulaSection `xml:"EulaSection"` + VirtualHardware []VirtualHardwareSection `xml:"VirtualHardwareSection"` +} + +type File struct { + ID string `xml:"id,attr"` + Href string `xml:"href,attr"` + Size uint `xml:"size,attr"` + Compression *string `xml:"compression,attr"` + ChunkSize *int `xml:"chunkSize,attr"` +} + +type Content struct { + ID string `xml:"id,attr"` + Info string `xml:"Info"` + Name *string `xml:"Name"` +} + +type Section struct { + Required *bool `xml:"required,attr"` + Info string `xml:"Info"` +} + +type AnnotationSection struct { + Section + + Annotation string `xml:"Annotation"` +} + +type ProductSection struct { + Section + + Class *string `xml:"class,attr"` + Instance *string `xml:"instance,attr"` + + Product string `xml:"Product"` + Vendor string `xml:"Vendor"` + Version string `xml:"Version"` + FullVersion string `xml:"FullVersion"` + ProductURL string `xml:"ProductUrl"` + VendorURL string `xml:"VendorUrl"` + AppURL string `xml:"AppUrl"` + Property []Property `xml:"Property"` +} + +type Property struct { + Key string `xml:"key,attr"` + Type string `xml:"type,attr"` + Qualifiers *string `xml:"qualifiers,attr"` + UserConfigurable *bool `xml:"userConfigurable,attr"` + Default *string `xml:"value,attr"` + Password *bool `xml:"password,attr"` + + Label *string `xml:"Label"` + Description *string `xml:"Description"` + + Values []PropertyConfigurationValue `xml:"Value"` +} + +type PropertyConfigurationValue struct { + Value string `xml:"value,attr"` + Configuration *string `xml:"configuration,attr"` +} + +type NetworkSection struct { + Section + + Networks []Network `xml:"Network"` +} + +type Network struct { + Name string `xml:"name,attr"` + + Description string `xml:"Description"` +} + +type DiskSection struct { + Section + + Disks []VirtualDiskDesc `xml:"Disk"` +} + +type VirtualDiskDesc struct { + DiskID string `xml:"diskId,attr"` + FileRef *string `xml:"fileRef,attr"` + Capacity string `xml:"capacity,attr"` + CapacityAllocationUnits *string `xml:"capacityAllocationUnits,attr"` + Format *string `xml:"format,attr"` + PopulatedSize *int `xml:"populatedSize,attr"` + ParentRef *string `xml:"parentRef,attr"` +} + +type OperatingSystemSection struct { + Section + + ID int16 `xml:"id,attr"` + Version *string `xml:"version,attr"` + OSType *string `xml:"osType,attr"` + + Description *string `xml:"Description"` +} + +type EulaSection struct { + Section + + License string `xml:"License"` +} + +type Config struct { + Required *bool `xml:"required,attr"` + Key string `xml:"key,attr"` + Value string `xml:"value,attr"` +} + +type VirtualHardwareSection struct { + Section + + ID *string `xml:"id,attr"` + Transport *string `xml:"transport,attr"` + + System *VirtualSystemSettingData `xml:"System"` + Item []ResourceAllocationSettingData `xml:"Item"` + StorageItem []StorageAllocationSettingData `xml:"StorageItem"` + Config []Config `xml:"Config"` + ExtraConfig []Config `xml:"ExtraConfig"` +} + +type VirtualSystemSettingData struct { + CIMVirtualSystemSettingData +} + +type ResourceAllocationSettingData struct { + CIMResourceAllocationSettingData + + Required *bool `xml:"required,attr"` + Configuration *string `xml:"configuration,attr"` + Bound *string `xml:"bound,attr"` +} + +type StorageAllocationSettingData struct { + CIMStorageAllocationSettingData + + Required *bool `xml:"required,attr"` + Configuration *string `xml:"configuration,attr"` + Bound *string `xml:"bound,attr"` +} + +type ResourceAllocationSection struct { + Section + + Item []ResourceAllocationSettingData `xml:"Item"` +} + +type DeploymentOptionSection struct { + Section + + Configuration []DeploymentOptionConfiguration `xml:"Configuration"` +} + +type DeploymentOptionConfiguration struct { + ID string `xml:"id,attr"` + Default *bool `xml:"default,attr"` + + Label string `xml:"Label"` + Description string `xml:"Description"` +} diff --git a/vendor/github.com/vmware/govmomi/ovf/manager.go b/vendor/github.com/vmware/govmomi/ovf/manager.go new file mode 100644 index 000000000..3ee2afdd4 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/manager.go @@ -0,0 +1,103 @@ +/* +Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ovf + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type Manager struct { + types.ManagedObjectReference + + c *vim25.Client +} + +func NewManager(c *vim25.Client) *Manager { + return &Manager{*c.ServiceContent.OvfManager, c} +} + +// CreateDescriptor wraps methods.CreateDescriptor +func (m *Manager) CreateDescriptor(ctx context.Context, obj mo.Reference, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) { + req := types.CreateDescriptor{ + This: m.Reference(), + Obj: obj.Reference(), + Cdp: cdp, + } + + res, err := methods.CreateDescriptor(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +// CreateImportSpec wraps methods.CreateImportSpec +func (m *Manager) CreateImportSpec(ctx context.Context, ovfDescriptor string, resourcePool mo.Reference, datastore mo.Reference, cisp types.OvfCreateImportSpecParams) (*types.OvfCreateImportSpecResult, error) { + req := types.CreateImportSpec{ + This: m.Reference(), + OvfDescriptor: ovfDescriptor, + ResourcePool: resourcePool.Reference(), + Datastore: datastore.Reference(), + Cisp: cisp, + } + + res, err := methods.CreateImportSpec(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +// ParseDescriptor wraps methods.ParseDescriptor +func (m *Manager) ParseDescriptor(ctx context.Context, ovfDescriptor string, pdp types.OvfParseDescriptorParams) (*types.OvfParseDescriptorResult, error) { + req := types.ParseDescriptor{ + This: m.Reference(), + OvfDescriptor: ovfDescriptor, + Pdp: pdp, + } + + res, err := methods.ParseDescriptor(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} + +// ValidateHost wraps methods.ValidateHost +func (m *Manager) ValidateHost(ctx context.Context, ovfDescriptor string, host mo.Reference, vhp types.OvfValidateHostParams) (*types.OvfValidateHostResult, error) { + req := types.ValidateHost{ + This: m.Reference(), + OvfDescriptor: ovfDescriptor, + Host: host.Reference(), + Vhp: vhp, + } + + res, err := methods.ValidateHost(ctx, m.c, &req) + if err != nil { + return nil, err + } + + return &res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/ovf/ovf.go b/vendor/github.com/vmware/govmomi/ovf/ovf.go new file mode 100644 index 000000000..bd279e757 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/ovf.go @@ -0,0 +1,35 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ovf + +import ( + "io" + + "github.com/vmware/govmomi/vim25/xml" +) + +func Unmarshal(r io.Reader) (*Envelope, error) { + var e Envelope + + dec := xml.NewDecoder(r) + err := dec.Decode(&e) + if err != nil { + return nil, err + } + + return &e, nil +} diff --git a/vendor/github.com/vmware/govmomi/session/manager.go b/vendor/github.com/vmware/govmomi/session/manager.go index 24c6a2dbe..8689acd50 100644 --- a/vendor/github.com/vmware/govmomi/session/manager.go +++ b/vendor/github.com/vmware/govmomi/session/manager.go @@ -281,3 +281,14 @@ func (sm *Manager) CloneSession(ctx context.Context, ticket string) error { sm.userSession = &res.Returnval return nil } + +func (sm *Manager) UpdateServiceMessage(ctx context.Context, message string) error { + req := types.UpdateServiceMessage{ + This: sm.Reference(), + Message: message, + } + + _, err := methods.UpdateServiceMessage(ctx, sm.client, &req) + + return err +} diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library.go b/vendor/github.com/vmware/govmomi/vapi/library/library.go new file mode 100644 index 000000000..7611af27a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/library.go @@ -0,0 +1,308 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package library + +import ( + "context" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vapi/internal" + "github.com/vmware/govmomi/vapi/rest" +) + +// StorageBackings for Content Libraries +type StorageBackings struct { + DatastoreID string `json:"datastore_id,omitempty"` + Type string `json:"type,omitempty"` +} + +// Library provides methods to create, read, update, delete, and enumerate libraries. +type Library struct { + CreationTime *time.Time `json:"creation_time,omitempty"` + Description string `json:"description,omitempty"` + ID string `json:"id,omitempty"` + LastModifiedTime *time.Time `json:"last_modified_time,omitempty"` + LastSyncTime *time.Time `json:"last_sync_time,omitempty"` + Name string `json:"name,omitempty"` + Storage []StorageBackings `json:"storage_backings,omitempty"` + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + Subscription *Subscription `json:"subscription_info,omitempty"` + Publication *Publication `json:"publish_info,omitempty"` +} + +// Subscription info +type Subscription struct { + AuthenticationMethod string `json:"authentication_method"` + AutomaticSyncEnabled *bool `json:"automatic_sync_enabled,omitempty"` + OnDemand *bool `json:"on_demand,omitempty"` + Password string `json:"password,omitempty"` + SslThumbprint string `json:"ssl_thumbprint,omitempty"` + SubscriptionURL string `json:"subscription_url,omitempty"` + UserName string `json:"user_name,omitempty"` +} + +// Publication info +type Publication struct { + AuthenticationMethod string `json:"authentication_method"` + UserName string `json:"user_name,omitempty"` + Password string `json:"password,omitempty"` + CurrentPassword string `json:"current_password,omitempty"` + PersistJSON *bool `json:"persist_json_enabled,omitempty"` + Published *bool `json:"published,omitempty"` + PublishURL string `json:"publish_url,omitempty"` +} + +// SubscriberSummary as returned by ListSubscribers +type SubscriberSummary struct { + LibraryID string `json:"subscribed_library"` + LibraryName string `json:"subscribed_library_name"` + SubscriptionID string `json:"subscription"` + LibraryVcenterHostname string `json:"subscribed_library_vcenter_hostname,omitempty"` +} + +// Placement information used to place a virtual machine template +type Placement struct { + ResourcePool string `json:"resource_pool,omitempty"` + Host string `json:"host,omitempty"` + Folder string `json:"folder,omitempty"` + Cluster string `json:"cluster,omitempty"` + Network string `json:"network,omitempty"` +} + +// Vcenter contains information about the vCenter Server instance where a subscribed library associated with a subscription exists. +type Vcenter struct { + Hostname string `json:"hostname"` + Port int `json:"https_port,omitempty"` + ServerGUID string `json:"server_guid"` +} + +// Subscriber contains the detailed info for a library subscriber. +type Subscriber struct { + LibraryID string `json:"subscribed_library"` + LibraryName string `json:"subscribed_library_name"` + LibraryLocation string `json:"subscribed_library_location"` + Placement *Placement `json:"subscribed_library_placement,omitempty"` + Vcenter *Vcenter `json:"subscribed_library_vcenter,omitempty"` +} + +// SubscriberLibrary is the specification for a subscribed library to be associated with a subscription. +type SubscriberLibrary struct { + Target string `json:"target"` + LibraryID string `json:"subscribed_library,omitempty"` + Location string `json:"location"` + Vcenter *Vcenter `json:"vcenter,omitempty"` + Placement *Placement `json:"placement,omitempty"` +} + +// Patch merges updates from the given src. +func (l *Library) Patch(src *Library) { + if src.Name != "" { + l.Name = src.Name + } + if src.Description != "" { + l.Description = src.Description + } + if src.Version != "" { + l.Version = src.Version + } +} + +// Manager extends rest.Client, adding content library related methods. +type Manager struct { + *rest.Client +} + +// NewManager creates a new Manager instance with the given client. +func NewManager(client *rest.Client) *Manager { + return &Manager{ + Client: client, + } +} + +// Find is the search criteria for finding libraries. +type Find struct { + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` +} + +// FindLibrary returns one or more libraries that match the provided search +// criteria. +// +// The provided name is case-insensitive. +// +// Either the name or type of library may be set to empty values in order +// to search for all libraries, all libraries with a specific name, regardless +// of type, or all libraries of a specified type. +func (c *Manager) FindLibrary(ctx context.Context, search Find) ([]string, error) { + url := c.Resource(internal.LibraryPath).WithAction("find") + spec := struct { + Spec Find `json:"spec"` + }{search} + var res []string + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// CreateLibrary creates a new library with the given Type, Name, +// Description, and CategoryID. +func (c *Manager) CreateLibrary(ctx context.Context, library Library) (string, error) { + spec := struct { + Library Library `json:"create_spec"` + }{library} + path := internal.LocalLibraryPath + if library.Type == "SUBSCRIBED" { + path = internal.SubscribedLibraryPath + sub := library.Subscription + u, err := url.Parse(sub.SubscriptionURL) + if err != nil { + return "", err + } + if u.Scheme == "https" && sub.SslThumbprint == "" { + thumbprint := c.Thumbprint(u.Host) + if thumbprint == "" { + t := c.DefaultTransport() + if t.TLSClientConfig.InsecureSkipVerify { + var info object.HostCertificateInfo + _ = info.FromURL(u, t.TLSClientConfig) + thumbprint = info.ThumbprintSHA1 + } + sub.SslThumbprint = thumbprint + } + } + } + url := c.Resource(path) + var res string + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// SyncLibrary syncs a subscribed library. +func (c *Manager) SyncLibrary(ctx context.Context, library *Library) error { + path := internal.SubscribedLibraryPath + url := c.Resource(path).WithID(library.ID).WithAction("sync") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} + +// PublishLibrary publishes the library to specified subscriptions. +// If no subscriptions are specified, then publishes the library to all subscriptions. +func (c *Manager) PublishLibrary(ctx context.Context, library *Library, subscriptions []string) error { + path := internal.LocalLibraryPath + var spec internal.SubscriptionDestinationSpec + for i := range subscriptions { + spec.Subscriptions = append(spec.Subscriptions, internal.SubscriptionDestination{ID: subscriptions[i]}) + } + url := c.Resource(path).WithID(library.ID).WithAction("publish") + return c.Do(ctx, url.Request(http.MethodPost, spec), nil) +} + +// DeleteLibrary deletes an existing library. +func (c *Manager) DeleteLibrary(ctx context.Context, library *Library) error { + path := internal.LocalLibraryPath + if library.Type == "SUBSCRIBED" { + path = internal.SubscribedLibraryPath + } + url := c.Resource(path).WithID(library.ID) + return c.Do(ctx, url.Request(http.MethodDelete), nil) +} + +// ListLibraries returns a list of all content library IDs in the system. +func (c *Manager) ListLibraries(ctx context.Context) ([]string, error) { + url := c.Resource(internal.LibraryPath) + var res []string + return res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// GetLibraryByID returns information on a library for the given ID. +func (c *Manager) GetLibraryByID(ctx context.Context, id string) (*Library, error) { + url := c.Resource(internal.LibraryPath).WithID(id) + var res Library + return &res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// GetLibraryByName returns information on a library for the given name. +func (c *Manager) GetLibraryByName(ctx context.Context, name string) (*Library, error) { + // Lookup by name + libraries, err := c.GetLibraries(ctx) + if err != nil { + return nil, err + } + for i := range libraries { + if libraries[i].Name == name { + return &libraries[i], nil + } + } + return nil, fmt.Errorf("library name (%s) not found", name) +} + +// GetLibraries returns a list of all content library details in the system. +func (c *Manager) GetLibraries(ctx context.Context) ([]Library, error) { + ids, err := c.ListLibraries(ctx) + if err != nil { + return nil, fmt.Errorf("get libraries failed for: %s", err) + } + + var libraries []Library + for _, id := range ids { + library, err := c.GetLibraryByID(ctx, id) + if err != nil { + return nil, fmt.Errorf("get library %s failed for %s", id, err) + } + + libraries = append(libraries, *library) + + } + return libraries, nil +} + +// ListSubscribers lists the subscriptions of the published library. +func (c *Manager) ListSubscribers(ctx context.Context, library *Library) ([]SubscriberSummary, error) { + url := c.Resource(internal.Subscriptions).WithParam("library", library.ID) + var res []SubscriberSummary + return res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// CreateSubscriber creates a subscription of the published library. +func (c *Manager) CreateSubscriber(ctx context.Context, library *Library, s SubscriberLibrary) (string, error) { + var spec struct { + Sub struct { + SubscriberLibrary SubscriberLibrary `json:"subscribed_library"` + } `json:"spec"` + } + spec.Sub.SubscriberLibrary = s + url := c.Resource(internal.Subscriptions).WithID(library.ID) + var res string + return res, c.Do(ctx, url.Request(http.MethodPost, &spec), &res) +} + +// GetSubscriber returns information about the specified subscriber of the published library. +func (c *Manager) GetSubscriber(ctx context.Context, library *Library, subscriber string) (*Subscriber, error) { + id := internal.SubscriptionDestination{ID: subscriber} + url := c.Resource(internal.Subscriptions).WithID(library.ID).WithAction("get") + var res Subscriber + return &res, c.Do(ctx, url.Request(http.MethodPost, &id), &res) +} + +// DeleteSubscriber deletes the specified subscription of the published library. +// The subscribed library associated with the subscription will not be deleted. +func (c *Manager) DeleteSubscriber(ctx context.Context, library *Library, subscriber string) error { + id := internal.SubscriptionDestination{ID: subscriber} + url := c.Resource(internal.Subscriptions).WithID(library.ID).WithAction("delete") + return c.Do(ctx, url.Request(http.MethodPost, &id), nil) +} diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library_file.go b/vendor/github.com/vmware/govmomi/vapi/library/library_file.go new file mode 100644 index 000000000..ba71d72d2 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/library_file.go @@ -0,0 +1,56 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package library + +import ( + "context" + "net/http" + + "github.com/vmware/govmomi/vapi/internal" +) + +// Checksum provides checksum information on library item files. +type Checksum struct { + Algorithm string `json:"algorithm,omitempty"` + Checksum string `json:"checksum"` +} + +// File provides methods to get information on library item files. +type File struct { + Cached *bool `json:"cached,omitempty"` + Checksum *Checksum `json:"checksum_info,omitempty"` + Name string `json:"name,omitempty"` + Size *int64 `json:"size,omitempty"` + Version string `json:"version,omitempty"` +} + +// ListLibraryItemFiles returns a list of all the files for a library item. +func (c *Manager) ListLibraryItemFiles(ctx context.Context, id string) ([]File, error) { + url := c.Resource(internal.LibraryItemFilePath).WithParam("library_item_id", id) + var res []File + return res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// GetLibraryItemFile returns a file with the provided name for a library item. +func (c *Manager) GetLibraryItemFile(ctx context.Context, id, fileName string) (*File, error) { + url := c.Resource(internal.LibraryItemFilePath).WithID(id).WithAction("get") + spec := struct { + Name string `json:"name"` + }{fileName} + var res File + return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library_item.go b/vendor/github.com/vmware/govmomi/vapi/library/library_item.go new file mode 100644 index 000000000..57914ad6c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/library_item.go @@ -0,0 +1,180 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package library + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/vmware/govmomi/vapi/internal" +) + +const ( + ItemTypeISO = "iso" + ItemTypeOVF = "ovf" + ItemTypeVMTX = "vm-template" +) + +// Item provides methods to create, read, update, delete, and enumerate library items. +type Item struct { + Cached bool `json:"cached,omitempty"` + ContentVersion string `json:"content_version,omitempty"` + CreationTime *time.Time `json:"creation_time,omitempty"` + Description string `json:"description,omitempty"` + ID string `json:"id,omitempty"` + LastModifiedTime *time.Time `json:"last_modified_time,omitempty"` + LastSyncTime *time.Time `json:"last_sync_time,omitempty"` + LibraryID string `json:"library_id,omitempty"` + MetadataVersion string `json:"metadata_version,omitempty"` + Name string `json:"name,omitempty"` + Size int64 `json:"size,omitempty"` + SourceID string `json:"source_id,omitempty"` + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` +} + +// Patch merges updates from the given src. +func (i *Item) Patch(src *Item) { + if src.Name != "" { + i.Name = src.Name + } + if src.Description != "" { + i.Description = src.Description + } + if src.Type != "" { + i.Type = src.Type + } + if src.Version != "" { + i.Version = src.Version + } +} + +// CreateLibraryItem creates a new library item +func (c *Manager) CreateLibraryItem(ctx context.Context, item Item) (string, error) { + type createItemSpec struct { + Name string `json:"name"` + Description string `json:"description"` + LibraryID string `json:"library_id,omitempty"` + Type string `json:"type"` + } + spec := struct { + Item createItemSpec `json:"create_spec"` + }{ + Item: createItemSpec{ + Name: item.Name, + Description: item.Description, + LibraryID: item.LibraryID, + Type: item.Type, + }, + } + url := c.Resource(internal.LibraryItemPath) + var res string + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// CopyLibraryItem copies a library item +func (c *Manager) CopyLibraryItem(ctx context.Context, src *Item, dst Item) (string, error) { + body := struct { + Item `json:"destination_create_spec"` + }{dst} + url := c.Resource(internal.LibraryItemPath).WithID(src.ID).WithAction("copy") + var res string + return res, c.Do(ctx, url.Request(http.MethodPost, body), &res) +} + +// SyncLibraryItem syncs a subscribed library item +func (c *Manager) SyncLibraryItem(ctx context.Context, item *Item, force bool) error { + body := struct { + Force bool `json:"force_sync_content"` + }{force} + url := c.Resource(internal.SubscribedLibraryItem).WithID(item.ID).WithAction("sync") + return c.Do(ctx, url.Request(http.MethodPost, body), nil) +} + +// PublishLibraryItem publishes a library item to specified subscriptions. +// If no subscriptions are specified, then publishes the library item to all subscriptions. +func (c *Manager) PublishLibraryItem(ctx context.Context, item *Item, force bool, subscriptions []string) error { + body := internal.SubscriptionItemDestinationSpec{ + Force: force, + } + for i := range subscriptions { + body.Subscriptions = append(body.Subscriptions, internal.SubscriptionDestination{ID: subscriptions[i]}) + } + url := c.Resource(internal.LibraryItemPath).WithID(item.ID).WithAction("publish") + return c.Do(ctx, url.Request(http.MethodPost, body), nil) +} + +// DeleteLibraryItem deletes an existing library item. +func (c *Manager) DeleteLibraryItem(ctx context.Context, item *Item) error { + url := c.Resource(internal.LibraryItemPath).WithID(item.ID) + return c.Do(ctx, url.Request(http.MethodDelete), nil) +} + +// ListLibraryItems returns a list of all items in a content library. +func (c *Manager) ListLibraryItems(ctx context.Context, id string) ([]string, error) { + url := c.Resource(internal.LibraryItemPath).WithParam("library_id", id) + var res []string + return res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// GetLibraryItem returns information on a library item for the given ID. +func (c *Manager) GetLibraryItem(ctx context.Context, id string) (*Item, error) { + url := c.Resource(internal.LibraryItemPath).WithID(id) + var res Item + return &res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// GetLibraryItems returns a list of all the library items for the specified library. +func (c *Manager) GetLibraryItems(ctx context.Context, libraryID string) ([]Item, error) { + ids, err := c.ListLibraryItems(ctx, libraryID) + if err != nil { + return nil, fmt.Errorf("get library items failed for: %s", err) + } + var items []Item + for _, id := range ids { + item, err := c.GetLibraryItem(ctx, id) + if err != nil { + return nil, fmt.Errorf("get library item for %s failed for %s", id, err) + } + items = append(items, *item) + } + return items, nil +} + +// FindItem is the search criteria for finding library items. +type FindItem struct { + Cached *bool `json:"cached,omitempty"` + LibraryID string `json:"library_id,omitempty"` + Name string `json:"name,omitempty"` + SourceID string `json:"source_id,omitempty"` + Type string `json:"type,omitempty"` +} + +// FindLibraryItems returns the IDs of all the library items that match the +// search criteria. +func (c *Manager) FindLibraryItems( + ctx context.Context, search FindItem) ([]string, error) { + + url := c.Resource(internal.LibraryItemPath).WithAction("find") + spec := struct { + Spec FindItem `json:"spec"` + }{search} + var res []string + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library_item_downloadsession_file.go b/vendor/github.com/vmware/govmomi/vapi/library/library_item_downloadsession_file.go new file mode 100644 index 000000000..6f432f727 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/library_item_downloadsession_file.go @@ -0,0 +1,71 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package library + +import ( + "context" + "net/http" + + "github.com/vmware/govmomi/vapi/internal" + "github.com/vmware/govmomi/vapi/rest" +) + +// DownloadFile is the specification for the downloadsession +// operations file:add, file:get, and file:list. +type DownloadFile struct { + BytesTransferred int64 `json:"bytes_transferred"` + Checksum *Checksum `json:"checksum_info,omitempty"` + DownloadEndpoint *TransferEndpoint `json:"download_endpoint,omitempty"` + ErrorMessage *rest.LocalizableMessage `json:"error_message,omitempty"` + Name string `json:"name"` + Size int64 `json:"size,omitempty"` + Status string `json:"status"` +} + +// GetLibraryItemDownloadSessionFile retrieves information about a specific file that is a part of an download session. +func (c *Manager) GetLibraryItemDownloadSessionFile(ctx context.Context, sessionID string, name string) (*DownloadFile, error) { + url := c.Resource(internal.LibraryItemDownloadSessionFile).WithID(sessionID).WithAction("get") + spec := struct { + Name string `json:"file_name"` + }{name} + var res DownloadFile + err := c.Do(ctx, url.Request(http.MethodPost, spec), &res) + if err != nil { + return nil, err + } + if res.Status == "ERROR" { + return nil, res.ErrorMessage + } + return &res, nil +} + +// ListLibraryItemDownloadSessionFile retrieves information about a specific file that is a part of an download session. +func (c *Manager) ListLibraryItemDownloadSessionFile(ctx context.Context, sessionID string) ([]DownloadFile, error) { + url := c.Resource(internal.LibraryItemDownloadSessionFile).WithParam("download_session_id", sessionID) + var res []DownloadFile + return res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// PrepareLibraryItemDownloadSessionFile retrieves information about a specific file that is a part of an download session. +func (c *Manager) PrepareLibraryItemDownloadSessionFile(ctx context.Context, sessionID string, name string) (*DownloadFile, error) { + url := c.Resource(internal.LibraryItemDownloadSessionFile).WithID(sessionID).WithAction("prepare") + spec := struct { + Name string `json:"file_name"` + }{name} + var res DownloadFile + return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession.go b/vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession.go new file mode 100644 index 000000000..df66a87b3 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession.go @@ -0,0 +1,165 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package library + +import ( + "context" + "net/http" + "time" + + "github.com/vmware/govmomi/vapi/internal" + "github.com/vmware/govmomi/vapi/rest" +) + +// Session is used to create an initial update or download session +type Session struct { + ClientProgress int64 `json:"client_progress,omitempty"` + ErrorMessage *rest.LocalizableMessage `json:"error_message,omitempty"` + ExpirationTime *time.Time `json:"expiration_time,omitempty"` + ID string `json:"id,omitempty"` + LibraryItemContentVersion string `json:"library_item_content_version,omitempty"` + LibraryItemID string `json:"library_item_id,omitempty"` + State string `json:"state,omitempty"` +} + +// CreateLibraryItemUpdateSession creates a new library item +func (c *Manager) CreateLibraryItemUpdateSession(ctx context.Context, session Session) (string, error) { + url := c.Resource(internal.LibraryItemUpdateSession) + spec := struct { + CreateSpec Session `json:"create_spec"` + }{session} + var res string + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// GetLibraryItemUpdateSession gets the update session information with status +func (c *Manager) GetLibraryItemUpdateSession(ctx context.Context, id string) (*Session, error) { + url := c.Resource(internal.LibraryItemUpdateSession).WithID(id) + var res Session + return &res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// ListLibraryItemUpdateSession gets the list of update sessions +func (c *Manager) ListLibraryItemUpdateSession(ctx context.Context) ([]string, error) { + url := c.Resource(internal.LibraryItemUpdateSession) + var res []string + return res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// CancelLibraryItemUpdateSession cancels an update session +func (c *Manager) CancelLibraryItemUpdateSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("cancel") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} + +// CompleteLibraryItemUpdateSession completes an update session +func (c *Manager) CompleteLibraryItemUpdateSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("complete") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} + +// DeleteLibraryItemUpdateSession deletes an update session +func (c *Manager) DeleteLibraryItemUpdateSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemUpdateSession).WithID(id) + return c.Do(ctx, url.Request(http.MethodDelete), nil) +} + +// FailLibraryItemUpdateSession fails an update session +func (c *Manager) FailLibraryItemUpdateSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("fail") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} + +// KeepAliveLibraryItemUpdateSession keeps an inactive update session alive. +func (c *Manager) KeepAliveLibraryItemUpdateSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemUpdateSession).WithID(id).WithAction("keep-alive") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} + +// WaitOnLibraryItemUpdateSession blocks until the update session is no longer +// in the ACTIVE state. +func (c *Manager) WaitOnLibraryItemUpdateSession( + ctx context.Context, sessionID string, + interval time.Duration, intervalCallback func()) error { + + // Wait until the upload operation is complete to return. + for { + session, err := c.GetLibraryItemUpdateSession(ctx, sessionID) + if err != nil { + return err + } + + if session.State != "ACTIVE" { + if session.State == "ERROR" { + return session.ErrorMessage + } + return nil + } + time.Sleep(interval) + if intervalCallback != nil { + intervalCallback() + } + } +} + +// CreateLibraryItemDownloadSession creates a new library item +func (c *Manager) CreateLibraryItemDownloadSession(ctx context.Context, session Session) (string, error) { + url := c.Resource(internal.LibraryItemDownloadSession) + spec := struct { + CreateSpec Session `json:"create_spec"` + }{session} + var res string + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// GetLibraryItemDownloadSession gets the download session information with status +func (c *Manager) GetLibraryItemDownloadSession(ctx context.Context, id string) (*Session, error) { + url := c.Resource(internal.LibraryItemDownloadSession).WithID(id) + var res Session + return &res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// ListLibraryItemDownloadSession gets the list of download sessions +func (c *Manager) ListLibraryItemDownloadSession(ctx context.Context) ([]string, error) { + url := c.Resource(internal.LibraryItemDownloadSession) + var res []string + return res, c.Do(ctx, url.Request(http.MethodGet), &res) +} + +// CancelLibraryItemDownloadSession cancels an download session +func (c *Manager) CancelLibraryItemDownloadSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemDownloadSession).WithID(id).WithAction("cancel") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} + +// DeleteLibraryItemDownloadSession deletes an download session +func (c *Manager) DeleteLibraryItemDownloadSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemDownloadSession).WithID(id) + return c.Do(ctx, url.Request(http.MethodDelete), nil) +} + +// FailLibraryItemDownloadSession fails an download session +func (c *Manager) FailLibraryItemDownloadSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemDownloadSession).WithID(id).WithAction("fail") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} + +// KeepAliveLibraryItemDownloadSession keeps an inactive download session alive. +func (c *Manager) KeepAliveLibraryItemDownloadSession(ctx context.Context, id string) error { + url := c.Resource(internal.LibraryItemDownloadSession).WithID(id).WithAction("keep-alive") + return c.Do(ctx, url.Request(http.MethodPost), nil) +} diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession_file.go b/vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession_file.go new file mode 100644 index 000000000..e34331cfa --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/library_item_updatesession_file.go @@ -0,0 +1,149 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package library + +import ( + "bufio" + "context" + "io" + "net/http" + "strings" + + "github.com/vmware/govmomi/vapi/internal" + "github.com/vmware/govmomi/vapi/rest" + "github.com/vmware/govmomi/vim25/soap" +) + +// TransferEndpoint provides information on the source of a library item file. +type TransferEndpoint struct { + URI string `json:"uri,omitempty"` + SSLCertificateThumbprint string `json:"ssl_certificate_thumbprint,omitempty"` +} + +// UpdateFile is the specification for the updatesession +// operations file:add, file:get, and file:list. +type UpdateFile struct { + BytesTransferred int64 `json:"bytes_transferred,omitempty"` + Checksum *Checksum `json:"checksum_info,omitempty"` + ErrorMessage *rest.LocalizableMessage `json:"error_message,omitempty"` + Name string `json:"name"` + Size int64 `json:"size,omitempty"` + SourceEndpoint *TransferEndpoint `json:"source_endpoint,omitempty"` + SourceType string `json:"source_type"` + Status string `json:"status,omitempty"` + UploadEndpoint *TransferEndpoint `json:"upload_endpoint,omitempty"` +} + +// AddLibraryItemFile adds a file +func (c *Manager) AddLibraryItemFile(ctx context.Context, sessionID string, updateFile UpdateFile) (*UpdateFile, error) { + url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("add") + spec := struct { + FileSpec UpdateFile `json:"file_spec"` + }{updateFile} + var res UpdateFile + err := c.Do(ctx, url.Request(http.MethodPost, spec), &res) + if err != nil { + return nil, err + } + if res.Status == "ERROR" { + return nil, res.ErrorMessage + } + return &res, nil +} + +// AddLibraryItemFileFromURI adds a file from a remote URI. +func (c *Manager) AddLibraryItemFileFromURI( + ctx context.Context, + sessionID, fileName, uri string) (*UpdateFile, error) { + + n, fingerprint, err := c.getContentLengthAndFingerprint(ctx, uri) + if err != nil { + return nil, err + } + + info, err := c.AddLibraryItemFile(ctx, sessionID, UpdateFile{ + Name: fileName, + SourceType: "PULL", + Size: n, + SourceEndpoint: &TransferEndpoint{ + URI: uri, + SSLCertificateThumbprint: fingerprint, + }, + }) + if err != nil { + return nil, err + } + + return info, c.CompleteLibraryItemUpdateSession(ctx, sessionID) +} + +// GetLibraryItemUpdateSessionFile retrieves information about a specific file +// that is a part of an update session. +func (c *Manager) GetLibraryItemUpdateSessionFile(ctx context.Context, sessionID string, fileName string) (*UpdateFile, error) { + url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("get") + spec := struct { + Name string `json:"file_name"` + }{fileName} + var res UpdateFile + return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// getContentLengthAndFingerprint gets the number of bytes returned +// by the URI as well as the SHA1 fingerprint of the peer certificate +// if the URI's scheme is https. +func (c *Manager) getContentLengthAndFingerprint( + ctx context.Context, uri string) (int64, string, error) { + resp, err := c.Head(uri) + if err != nil { + return 0, "", err + } + if resp.TLS == nil || len(resp.TLS.PeerCertificates) == 0 { + return resp.ContentLength, "", nil + } + fingerprint := c.Thumbprint(resp.Request.URL.Host) + if fingerprint == "" { + if c.DefaultTransport().TLSClientConfig.InsecureSkipVerify { + fingerprint = soap.ThumbprintSHA1(resp.TLS.PeerCertificates[0]) + } + } + return resp.ContentLength, fingerprint, nil +} + +// ReadManifest converts an ovf manifest to a map of file name -> Checksum. +func ReadManifest(m io.Reader) (map[string]*Checksum, error) { + // expected format: openssl sha1 *.{ovf,vmdk} + c := make(map[string]*Checksum) + + scanner := bufio.NewScanner(m) + for scanner.Scan() { + line := strings.SplitN(scanner.Text(), ")=", 2) + if len(line) != 2 { + continue + } + name := strings.SplitN(line[0], "(", 2) + if len(name) != 2 { + continue + } + sum := &Checksum{ + Algorithm: strings.TrimSpace(name[0]), + Checksum: strings.TrimSpace(line[1]), + } + c[name[1]] = sum + } + + return c, scanner.Err() +} diff --git a/vendor/github.com/vmware/govmomi/vapi/rest/client.go b/vendor/github.com/vmware/govmomi/vapi/rest/client.go index 0cad1fb13..6b69c0947 100644 --- a/vendor/github.com/vmware/govmomi/vapi/rest/client.go +++ b/vendor/github.com/vmware/govmomi/vapi/rest/client.go @@ -25,6 +25,7 @@ import ( "io/ioutil" "net/http" "net/url" + "strings" "sync" "time" @@ -106,10 +107,21 @@ func (c *Client) UnmarshalJSON(b []byte) error { return nil } +// isAPI returns true if path starts with "/api" +// This hack allows helpers to support both endpoints: +// "/rest" - value wrapped responses and structured error responses +// "/api" - raw responses and no structured error responses +func isAPI(path string) bool { + return strings.HasPrefix(path, "/api") +} + // Resource helper for the given path. func (c *Client) Resource(path string) *Resource { r := &Resource{u: c.URL()} - r.u.Path = Path + path + if !isAPI(path) { + path = Path + path + } + r.u.Path = path return r } @@ -153,6 +165,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) return c.Client.Do(ctx, req, func(res *http.Response) error { switch res.StatusCode { case http.StatusOK: + case http.StatusCreated: case http.StatusNoContent: case http.StatusBadRequest: // TODO: structured error types @@ -174,12 +187,18 @@ func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) _, err := io.Copy(b, res.Body) return err default: + d := json.NewDecoder(res.Body) + if isAPI(req.URL.Path) { + // Responses from the /api endpoint are not wrapped + return d.Decode(resBody) + } + // Responses from the /rest endpoint are wrapped in this structure val := struct { Value interface{} `json:"value,omitempty"` }{ resBody, } - return json.NewDecoder(res.Body).Decode(&val) + return d.Decode(&val) } }) } diff --git a/vendor/github.com/vmware/govmomi/vapi/rest/resource.go b/vendor/github.com/vmware/govmomi/vapi/rest/resource.go index 243789632..060a1c84f 100644 --- a/vendor/github.com/vmware/govmomi/vapi/rest/resource.go +++ b/vendor/github.com/vmware/govmomi/vapi/rest/resource.go @@ -48,11 +48,12 @@ func (r *Resource) WithAction(action string) *Resource { return r.WithParam("~action", action) } -// WithParam sets adds a parameter to the URL.RawQuery +// WithParam adds one parameter on the URL.RawQuery func (r *Resource) WithParam(name string, value string) *Resource { - r.u.RawQuery = url.Values{ - name: []string{value}, - }.Encode() + // ParseQuery handles empty case, and we control access to query string so shouldn't encounter an error case + params, _ := url.ParseQuery(r.u.RawQuery) + params[name] = []string{value} + r.u.RawQuery = params.Encode() return r } diff --git a/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go b/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go new file mode 100644 index 000000000..3eaaa6431 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go @@ -0,0 +1,304 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vcenter + +import ( + "context" + "fmt" + "net/http" + + "github.com/vmware/govmomi/vapi/internal" + "github.com/vmware/govmomi/vapi/rest" + "github.com/vmware/govmomi/vim25/types" +) + +// AdditionalParams are additional OVF parameters which can be specified for a deployment target. +// This structure is a union where based on Type, only one of each commented section will be set. +type AdditionalParams struct { + Class string `json:"@class"` + Type string `json:"type"` + + // DeploymentOptionParams + SelectedKey string `json:"selected_key,omitempty"` + DeploymentOptions []DeploymentOption `json:"deployment_options,omitempty"` + + // ExtraConfigs + ExtraConfig []ExtraConfig `json:"extra_configs,omitempty"` + + // PropertyParams + Properties []Property `json:"properties,omitempty"` + + // SizeParams + ApproximateSparseDeploymentSize int64 `json:"approximate_sparse_deployment_size,omitempty"` + VariableDiskSize bool `json:"variable_disk_size,omitempty"` + ApproximateDownloadSize int64 `json:"approximate_download_size,omitempty"` + ApproximateFlatDeploymentSize int64 `json:"approximate_flat_deployment_size,omitempty"` + + // IpAllocationParams + SupportedAllocationScheme []string `json:"supported_allocation_scheme,omitempty"` + SupportedIPProtocol []string `json:"supported_ip_protocol,omitempty"` + SupportedIPAllocationPolicy []string `json:"supported_ip_allocation_policy,omitempty"` + IPAllocationPolicy string `json:"ip_allocation_policy,omitempty"` + IPProtocol string `json:"ip_protocol,omitempty"` + + // UnknownSections + UnknownSections []UnknownSection `json:"unknown_sections,omitempty"` +} + +const ( + ClassDeploymentOptionParams = "com.vmware.vcenter.ovf.deployment_option_params" + ClassPropertyParams = "com.vmware.vcenter.ovf.property_params" + TypeDeploymentOptionParams = "DeploymentOptionParams" + TypeExtraConfigParams = "ExtraConfigParams" + TypeIPAllocationParams = "IpAllocationParams" + TypePropertyParams = "PropertyParams" + TypeSizeParams = "SizeParams" +) + +// DeploymentOption contains the information about a deployment option as defined in the OVF specification +type DeploymentOption struct { + Key string `json:"key,omitempty"` + Label string `json:"label,omitempty"` + Description string `json:"description,omitempty"` + DefaultChoice bool `json:"default_choice,omitempty"` +} + +// ExtraConfig contains information about a vmw:ExtraConfig OVF element +type ExtraConfig struct { + Key string `json:"key,omitempty"` + Value string `json:"value,omitempty"` + VirtualSystemID string `json:"virtual_system_id,omitempty"` +} + +// Property contains information about a property in an OVF package +type Property struct { + Category string `json:"category,omitempty"` + ClassID string `json:"class_id,omitempty"` + Description string `json:"description,omitempty"` + ID string `json:"id,omitempty"` + InstanceID string `json:"instance_id,omitempty"` + Label string `json:"label,omitempty"` + Type string `json:"type,omitempty"` + UIOptional bool `json:"ui_optional,omitempty"` + Value string `json:"value,omitempty"` +} + +// UnknownSection contains information about an unknown section in an OVF package +type UnknownSection struct { + Tag string `json:"tag,omitempty"` + Info string `json:"info,omitempty"` +} + +// NetworkMapping specifies the target network to use for sections of type ovf:NetworkSection in the OVF descriptor +type NetworkMapping struct { + Key string `json:"key"` + Value string `json:"value"` +} + +// StorageGroupMapping defines the storage deployment target and storage provisioning type for a section of type vmw:StorageGroupSection in the OVF descriptor +type StorageGroupMapping struct { + Type string `json:"type"` + StorageProfileID string `json:"storage_profile_id,omitempty"` + DatastoreID string `json:"datastore_id,omitempty"` + Provisioning string `json:"provisioning,omitempty"` +} + +// StorageMapping specifies the target storage to use for sections of type vmw:StorageGroupSection in the OVF descriptor +type StorageMapping struct { + Key string `json:"key"` + Value StorageGroupMapping `json:"value"` +} + +// DeploymentSpec is the deployment specification for the deployment +type DeploymentSpec struct { + Name string `json:"name,omitempty"` + Annotation string `json:"annotation,omitempty"` + AcceptAllEULA bool `json:"accept_all_EULA,omitempty"` + NetworkMappings []NetworkMapping `json:"network_mappings,omitempty"` + StorageMappings []StorageMapping `json:"storage_mappings,omitempty"` + StorageProvisioning string `json:"storage_provisioning,omitempty"` + StorageProfileID string `json:"storage_profile_id,omitempty"` + Locale string `json:"locale,omitempty"` + Flags []string `json:"flags,omitempty"` + AdditionalParams []AdditionalParams `json:"additional_parameters,omitempty"` + DefaultDatastoreID string `json:"default_datastore_id,omitempty"` +} + +// Target is the target for the deployment +type Target struct { + ResourcePoolID string `json:"resource_pool_id,omitempty"` + HostID string `json:"host_id,omitempty"` + FolderID string `json:"folder_id,omitempty"` +} + +// Deploy contains the information to start the deployment of a library OVF +type Deploy struct { + DeploymentSpec `json:"deployment_spec,omitempty"` + Target `json:"target,omitempty"` +} + +// Error is a SERVER error +type Error struct { + Class string `json:"@class,omitempty"` + Messages []rest.LocalizableMessage `json:"messages,omitempty"` +} + +// ParseIssue is a parse issue struct +type ParseIssue struct { + Category string `json:"@classcategory,omitempty"` + File string `json:"file,omitempty"` + LineNumber int64 `json:"line_number,omitempty"` + ColumnNumber int64 `json:"column_number,omitempty"` + Message rest.LocalizableMessage `json:"message,omitempty"` +} + +// OVFError is a list of errors from create or deploy +type OVFError struct { + Category string `json:"category,omitempty"` + Error *Error `json:"error,omitempty"` + Issues []ParseIssue `json:"issues,omitempty"` + Message *rest.LocalizableMessage `json:"message,omitempty"` +} + +// ResourceID is a managed object reference for a deployed resource. +type ResourceID struct { + Type string `json:"type,omitempty"` + Value string `json:"id,omitempty"` +} + +// DeploymentError is an error that occurs when deploying and OVF from +// a library item. +type DeploymentError struct { + Errors []OVFError `json:"errors,omitempty"` +} + +// Error implements the error interface +func (e *DeploymentError) Error() string { + msg := "" + if len(e.Errors) != 0 { + err := e.Errors[0] + if err.Message != nil { + msg = err.Message.DefaultMessage + } else if err.Error != nil && len(err.Error.Messages) != 0 { + msg = err.Error.Messages[0].DefaultMessage + } + } + if msg == "" { + msg = fmt.Sprintf("%#v", e) + } + return "deploy error: " + msg +} + +// LibraryTarget specifies a Library or Library item +type LibraryTarget struct { + LibraryID string `json:"library_id,omitempty"` + LibraryItemID string `json:"library_item_id,omitempty"` +} + +// CreateSpec info used to create an OVF package from a VM +type CreateSpec struct { + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + Flags []string `json:"flags,omitempty"` +} + +// OVF data used by CreateOVF +type OVF struct { + Spec CreateSpec `json:"create_spec"` + Source ResourceID `json:"source"` + Target LibraryTarget `json:"target"` +} + +// CreateResult used for decoded a CreateOVF response +type CreateResult struct { + Succeeded bool `json:"succeeded,omitempty"` + ID string `json:"ovf_library_item_id,omitempty"` + Error *DeploymentError `json:"error,omitempty"` +} + +// Deployment is the results from issuing a library OVF deployment +type Deployment struct { + Succeeded bool `json:"succeeded,omitempty"` + ResourceID *ResourceID `json:"resource_id,omitempty"` + Error *DeploymentError `json:"error,omitempty"` +} + +// FilterRequest contains the information to start a vcenter filter call +type FilterRequest struct { + Target `json:"target,omitempty"` +} + +// FilterResponse returns information from the vcenter filter call +type FilterResponse struct { + EULAs []string `json:"EULAs,omitempty"` + AdditionalParams []AdditionalParams `json:"additional_params,omitempty"` + Annotation string `json:"Annotation,omitempty"` + Name string `json:"name,omitempty"` + Networks []string `json:"Networks,omitempty"` + StorageGroups []string `json:"storage_groups,omitempty"` +} + +// Manager extends rest.Client, adding content library related methods. +type Manager struct { + *rest.Client +} + +// NewManager creates a new Manager instance with the given client. +func NewManager(client *rest.Client) *Manager { + return &Manager{ + Client: client, + } +} + +// CreateOVF creates a library OVF item in content library from an existing VM +func (c *Manager) CreateOVF(ctx context.Context, ovf OVF) (string, error) { + if ovf.Source.Type == "" { + ovf.Source.Type = "VirtualMachine" + } + url := c.Resource(internal.VCenterOVFLibraryItem) + var res CreateResult + err := c.Do(ctx, url.Request(http.MethodPost, ovf), &res) + if err != nil { + return "", err + } + if res.Succeeded { + return res.ID, nil + } + return "", res.Error +} + +// DeployLibraryItem deploys a library OVF +func (c *Manager) DeployLibraryItem(ctx context.Context, libraryItemID string, deploy Deploy) (*types.ManagedObjectReference, error) { + url := c.Resource(internal.VCenterOVFLibraryItem).WithID(libraryItemID).WithAction("deploy") + var res Deployment + err := c.Do(ctx, url.Request(http.MethodPost, deploy), &res) + if err != nil { + return nil, err + } + if res.Succeeded { + ref := types.ManagedObjectReference(*res.ResourceID) + return &ref, nil + } + return nil, res.Error +} + +// FilterLibraryItem deploys a library OVF +func (c *Manager) FilterLibraryItem(ctx context.Context, libraryItemID string, filter FilterRequest) (FilterResponse, error) { + url := c.Resource(internal.VCenterOVFLibraryItem).WithID(libraryItemID).WithAction("filter") + var res FilterResponse + return res, c.Do(ctx, url.Request(http.MethodPost, filter), &res) +} diff --git a/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_vmtx.go b/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_vmtx.go new file mode 100644 index 000000000..a71d4a061 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_vmtx.go @@ -0,0 +1,285 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vcenter + +import ( + "context" + "crypto/sha1" + "fmt" + "log" + "net/http" + "path" + + "github.com/vmware/govmomi/vapi/internal" + "github.com/vmware/govmomi/vapi/library" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +// vcenter vm template +// The vcenter.vm_template API provides structures and services that will let its client manage VMTX template in Content Library. +// http://vmware.github.io/vsphere-automation-sdk-rest/6.7.1/index.html#SVC_com.vmware.vcenter.vm_template.library_items + +// Template create spec +type Template struct { + Description string `json:"description,omitempty"` + DiskStorage *DiskStorage `json:"disk_storage,omitempty"` + DiskStorageOverrides []DiskStorageOverride `json:"disk_storage_overrides,omitempty"` + Library string `json:"library,omitempty"` + Name string `json:"name,omitempty"` + Placement *Placement `json:"placement,omitempty"` + SourceVM string `json:"source_vm,omitempty"` + VMHomeStorage *DiskStorage `json:"vm_home_storage,omitempty"` +} + +// TemplateInfo for a VM template contained in an existing library item +type TemplateInfo struct { + GuestOS string `json:"guest_OS,omitempty"` + // TODO... +} + +// Placement information used to place the virtual machine template +type Placement = library.Placement + +// StoragePolicy for DiskStorage +type StoragePolicy struct { + Policy string `json:"policy,omitempty"` + Type string `json:"type"` +} + +// DiskStorage defines the storage specification for VM files +type DiskStorage struct { + Datastore string `json:"datastore,omitempty"` + StoragePolicy *StoragePolicy `json:"storage_policy,omitempty"` +} + +// DiskStorageOverride storage specification for individual disks in the virtual machine template +type DiskStorageOverride struct { + Key string `json:"key"` + Value DiskStorage `json:"value"` +} + +// GuestCustomization spec to apply to the deployed VM +type GuestCustomization struct { + Name string `json:"name,omitempty"` +} + +// HardwareCustomization spec which specifies updates to the deployed VM +type HardwareCustomization struct { + // TODO +} + +// DeployTemplate specification of how a library VM template clone should be deployed. +type DeployTemplate struct { + Description string `json:"description,omitempty"` + DiskStorage *DiskStorage `json:"disk_storage,omitempty"` + DiskStorageOverrides []DiskStorageOverride `json:"disk_storage_overrides,omitempty"` + GuestCustomization *GuestCustomization `json:"guest_customization,omitempty"` + HardwareCustomization *HardwareCustomization `json:"hardware_customization,omitempty"` + Name string `json:"name,omitempty"` + Placement *Placement `json:"placement,omitempty"` + PoweredOn bool `json:"powered_on"` + VMHomeStorage *DiskStorage `json:"vm_home_storage,omitempty"` +} + +// CheckOut specification +type CheckOut struct { + Name string `json:"name,omitempty"` + Placement *Placement `json:"placement,omitempty"` + PoweredOn bool `json:"powered_on,omitempty"` +} + +// CheckIn specification +type CheckIn struct { + Message string `json:"message"` +} + +// CreateTemplate creates a library VMTX item in content library from an existing VM +func (c *Manager) CreateTemplate(ctx context.Context, vmtx Template) (string, error) { + url := c.Resource(internal.VCenterVMTXLibraryItem) + var res string + spec := struct { + Template `json:"spec"` + }{vmtx} + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// DeployTemplateLibraryItem deploys a VM as a copy of the source VM template contained in the given library item +func (c *Manager) DeployTemplateLibraryItem(ctx context.Context, libraryItemID string, deploy DeployTemplate) (*types.ManagedObjectReference, error) { + url := c.Resource(path.Join(internal.VCenterVMTXLibraryItem, libraryItemID)).WithParam("action", "deploy") + var res string + spec := struct { + DeployTemplate `json:"spec"` + }{deploy} + err := c.Do(ctx, url.Request(http.MethodPost, spec), &res) + if err != nil { + return nil, err + } + return &types.ManagedObjectReference{Type: "VirtualMachine", Value: res}, nil +} + +// CheckOut a library item containing a VM template. +func (c *Manager) CheckOut(ctx context.Context, libraryItemID string, checkout *CheckOut) (*types.ManagedObjectReference, error) { + url := c.Resource(path.Join(internal.VCenterVMTXLibraryItem, libraryItemID, "check-outs")).WithParam("action", "check-out") + var res string + spec := struct { + *CheckOut `json:"spec"` + }{checkout} + err := c.Do(ctx, url.Request(http.MethodPost, spec), &res) + if err != nil { + return nil, err + } + return &types.ManagedObjectReference{Type: "VirtualMachine", Value: res}, nil +} + +// CheckIn a VM into the library item. +func (c *Manager) CheckIn(ctx context.Context, libraryItemID string, vm mo.Reference, checkin *CheckIn) (string, error) { + p := path.Join(internal.VCenterVMTXLibraryItem, libraryItemID, "check-outs", vm.Reference().Value) + url := c.Resource(p).WithParam("action", "check-in") + var res string + spec := struct { + *CheckIn `json:"spec"` + }{checkin} + return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) +} + +// TemplateLibrary params for synchronizing subscription library OVF items to VM Template items +type TemplateLibrary struct { + Source library.Library + Destination library.Library + Placement Target + Include func(library.Item, *library.Item) bool + SyncItem func(context.Context, library.Item, *Deploy, *Template) error +} + +func (c *Manager) includeTemplateLibraryItem(src library.Item, dst *library.Item) bool { + return dst == nil +} + +// SyncTemplateLibraryItem deploys an Library OVF item from which a VM template (vmtx) Library item is created. +// The deployed VM is deleted after being converted to a Library vmtx item. +func (c *Manager) SyncTemplateLibraryItem(ctx context.Context, item library.Item, deploy *Deploy, spec *Template) error { + destroy := false + if spec.SourceVM == "" { + ref, err := c.DeployLibraryItem(ctx, item.ID, *deploy) + if err != nil { + return err + } + + destroy = true + spec.SourceVM = ref.Value + } + + _, err := c.CreateTemplate(ctx, *spec) + + if destroy { + // Delete source VM regardless of CreateTemplate result + url := c.Resource("/vcenter/vm/" + spec.SourceVM) + derr := c.Do(ctx, url.Request(http.MethodDelete), nil) + if derr != nil { + if err == nil { + // Return Delete error if CreateTemplate was successful + return derr + } + // Return CreateTemplate error and just log Delete error + log.Printf("destroy %s: %s", spec.SourceVM, derr) + } + } + + return err +} + +func vmtxSourceName(l library.Library, item library.Item) string { + sum := sha1.Sum([]byte(path.Join(l.Name, item.Name))) + return fmt.Sprintf("vmtx-src-%x", sum) +} + +// SyncTemplateLibrary converts TemplateLibrary.Source OVF items to VM Template items within TemplateLibrary.Destination +// The optional TemplateLibrary.Include func can be used to filter which items are synced. +// By default all items that don't exist in the Destination library are synced. +// The optional TemplateLibrary.SyncItem func can be used to change how the item is synced, by default SyncTemplateLibraryItem is used. +func (c *Manager) SyncTemplateLibrary(ctx context.Context, l TemplateLibrary, items ...library.Item) error { + m := library.NewManager(c.Client) + var err error + if len(items) == 0 { + items, err = m.GetLibraryItems(ctx, l.Source.ID) + if err != nil { + return err + } + } + + templates, err := m.GetLibraryItems(ctx, l.Destination.ID) + if err != nil { + return err + } + + existing := make(map[string]*library.Item) + for i := range templates { + existing[templates[i].Name] = &templates[i] + } + + include := l.Include + if include == nil { + include = c.includeTemplateLibraryItem + } + + sync := l.SyncItem + if sync == nil { + sync = c.SyncTemplateLibraryItem + } + + for _, item := range items { + if item.Type != library.ItemTypeOVF { + continue + } + + // Deploy source VM from library ovf item + deploy := Deploy{ + DeploymentSpec: DeploymentSpec{ + Name: vmtxSourceName(l.Destination, item), + DefaultDatastoreID: l.Destination.Storage[0].DatastoreID, + AcceptAllEULA: true, + }, + Target: l.Placement, + } + + // Create library vmtx item from source VM + storage := &DiskStorage{ + Datastore: deploy.DeploymentSpec.DefaultDatastoreID, + } + spec := Template{ + Name: item.Name, + Library: l.Destination.ID, + DiskStorage: storage, + VMHomeStorage: storage, + Placement: &Placement{ + Folder: deploy.Target.FolderID, + ResourcePool: deploy.Target.ResourcePoolID, + }, + } + + if !l.Include(item, existing[item.Name]) { + continue + } + + if err = sync(ctx, item, &deploy, &spec); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/vmware/govmomi/vim25/methods/methods.go b/vendor/github.com/vmware/govmomi/vim25/methods/methods.go index 8c209e604..eb2be0d00 100644 --- a/vendor/github.com/vmware/govmomi/vim25/methods/methods.go +++ b/vendor/github.com/vmware/govmomi/vim25/methods/methods.go @@ -4843,6 +4843,26 @@ func DownloadDescriptionTree(ctx context.Context, r soap.RoundTripper, req *type return resBody.Res, nil } +type DropConnectionsBody struct { + Req *types.DropConnections `xml:"urn:vim25 DropConnections,omitempty"` + Res *types.DropConnectionsResponse `xml:"DropConnectionsResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *DropConnectionsBody) Fault() *soap.Fault { return b.Fault_ } + +func DropConnections(ctx context.Context, r soap.RoundTripper, req *types.DropConnections) (*types.DropConnectionsResponse, error) { + var reqBody, resBody DropConnectionsBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + type DuplicateCustomizationSpecBody struct { Req *types.DuplicateCustomizationSpec `xml:"urn:vim25 DuplicateCustomizationSpec,omitempty"` Res *types.DuplicateCustomizationSpecResponse `xml:"DuplicateCustomizationSpecResponse,omitempty"` @@ -9523,6 +9543,26 @@ func QueryConnectionInfoViaSpec(ctx context.Context, r soap.RoundTripper, req *t return resBody.Res, nil } +type QueryConnectionsBody struct { + Req *types.QueryConnections `xml:"urn:vim25 QueryConnections,omitempty"` + Res *types.QueryConnectionsResponse `xml:"QueryConnectionsResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *QueryConnectionsBody) Fault() *soap.Fault { return b.Fault_ } + +func QueryConnections(ctx context.Context, r soap.RoundTripper, req *types.QueryConnections) (*types.QueryConnectionsResponse, error) { + var reqBody, resBody QueryConnectionsBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + type QueryCryptoKeyStatusBody struct { Req *types.QueryCryptoKeyStatus `xml:"urn:vim25 QueryCryptoKeyStatus,omitempty"` Res *types.QueryCryptoKeyStatusResponse `xml:"QueryCryptoKeyStatusResponse,omitempty"` diff --git a/vendor/github.com/vmware/govmomi/vim25/retry.go b/vendor/github.com/vmware/govmomi/vim25/retry.go index f10e2cb6c..bf663a101 100644 --- a/vendor/github.com/vmware/govmomi/vim25/retry.go +++ b/vendor/github.com/vmware/govmomi/vim25/retry.go @@ -25,42 +25,50 @@ import ( type RetryFunc func(err error) (retry bool, delay time.Duration) -// TemporaryNetworkError returns a RetryFunc that retries up to a maximum of n -// times, only if the error returned by the RoundTrip function is a temporary -// network error (for example: a connect timeout). +// TemporaryNetworkError is deprecated. Use Retry() with RetryTemporaryNetworkError and retryAttempts instead. func TemporaryNetworkError(n int) RetryFunc { - return func(err error) (retry bool, delay time.Duration) { - var ok bool - - t, ok := err.(interface { - // Temporary is implemented by url.Error and net.Error - Temporary() bool - }) - if !ok { - // Never retry if this is not a Temporary error. - return false, 0 + return func(err error) (bool, time.Duration) { + if IsTemporaryNetworkError(err) { + // Don't retry if we're out of tries. + if n--; n <= 0 { + return false, 0 + } + return true, 0 } - - if !t.Temporary() { - return false, 0 - } - - // Don't retry if we're out of tries. - if n--; n <= 0 { - return false, 0 - } - - return true, 0 + return false, 0 } } +// RetryTemporaryNetworkError returns a RetryFunc that returns IsTemporaryNetworkError(err) +func RetryTemporaryNetworkError(err error) (bool, time.Duration) { + return IsTemporaryNetworkError(err), 0 +} + +// IsTemporaryNetworkError returns false unless the error implements +// a Temporary() bool method such as url.Error and net.Error. +// Otherwise, returns the value of the Temporary() method. +func IsTemporaryNetworkError(err error) bool { + t, ok := err.(interface { + // Temporary is implemented by url.Error and net.Error + Temporary() bool + }) + + if !ok { + // Not a Temporary error. + return false + } + + return t.Temporary() +} + type retry struct { roundTripper soap.RoundTripper // fn is a custom function that is called when an error occurs. // It returns whether or not to retry, and if so, how long to // delay before retrying. - fn RetryFunc + fn RetryFunc + maxRetryAttempts int } // Retry wraps the specified soap.RoundTripper and invokes the @@ -68,10 +76,16 @@ type retry struct { // retry the call, and if so, how long to wait before retrying. If // the result of this function is to not retry, the original error // is returned from the RoundTrip function. -func Retry(roundTripper soap.RoundTripper, fn RetryFunc) soap.RoundTripper { +// The soap.RoundTripper will return the original error if retryAttempts is specified and reached. +func Retry(roundTripper soap.RoundTripper, fn RetryFunc, retryAttempts ...int) soap.RoundTripper { r := &retry{ - roundTripper: roundTripper, - fn: fn, + roundTripper: roundTripper, + fn: fn, + maxRetryAttempts: 1, + } + + if len(retryAttempts) == 1 { + r.maxRetryAttempts = retryAttempts[0] } return r @@ -80,7 +94,7 @@ func Retry(roundTripper soap.RoundTripper, fn RetryFunc) soap.RoundTripper { func (r *retry) RoundTrip(ctx context.Context, req, res soap.HasFault) error { var err error - for { + for attempt := 0; attempt < r.maxRetryAttempts; attempt++ { err = r.roundTripper.RoundTrip(ctx, req, res) if err == nil { break diff --git a/vendor/github.com/vmware/govmomi/vim25/soap/client.go b/vendor/github.com/vmware/govmomi/vim25/soap/client.go index 04e26f059..637330462 100644 --- a/vendor/github.com/vmware/govmomi/vim25/soap/client.go +++ b/vendor/github.com/vmware/govmomi/vim25/soap/client.go @@ -74,7 +74,8 @@ type Client struct { Types types.Func UserAgent string - cookie string + cookie string + insecureCookies bool } var schemeMatch = regexp.MustCompile(`^\w+://`) @@ -156,6 +157,10 @@ func NewClient(u *url.URL, insecure bool) *Client { c.u = c.URL() c.u.User = nil + if c.u.Scheme == "http" { + c.insecureCookies = os.Getenv("GOVMOMI_INSECURE_COOKIES") == "true" + } + return &c } @@ -476,6 +481,16 @@ func (c *Client) UnmarshalJSON(b []byte) error { type kindContext struct{} +func (c *Client) setInsecureCookies(res *http.Response) { + cookies := res.Cookies() + if len(cookies) != 0 { + for _, cookie := range cookies { + cookie.Secure = false + } + c.Jar.SetCookies(c.u, cookies) + } +} + func (c *Client) Do(ctx context.Context, req *http.Request, f func(*http.Response) error) error { if ctx == nil { ctx = context.Background() @@ -519,6 +534,10 @@ func (c *Client) Do(ctx context.Context, req *http.Request, f func(*http.Respons d.debugResponse(res, ext) } + if c.insecureCookies { + c.setInsecureCookies(res) + } + return f(res) } @@ -541,7 +560,7 @@ type statusError struct { } // Temporary returns true for HTTP response codes that can be retried -// See vim25.TemporaryNetworkError +// See vim25.IsTemporaryNetworkError func (e *statusError) Temporary() bool { switch e.res.StatusCode { case http.StatusBadGateway: diff --git a/vendor/github.com/vmware/govmomi/vim25/soap/error.go b/vendor/github.com/vmware/govmomi/vim25/soap/error.go index 46111556c..1e1508733 100644 --- a/vendor/github.com/vmware/govmomi/vim25/soap/error.go +++ b/vendor/github.com/vmware/govmomi/vim25/soap/error.go @@ -17,6 +17,7 @@ limitations under the License. package soap import ( + "encoding/json" "fmt" "reflect" @@ -49,6 +50,15 @@ func (s soapFaultError) Error() string { return fmt.Sprintf("%s: %s", s.fault.Code, msg) } +func (s soapFaultError) MarshalJSON() ([]byte, error) { + out := struct { + Fault *Fault + }{ + Fault: s.fault, + } + return json.Marshal(out) +} + type vimFaultError struct { fault types.BaseMethodFault } diff --git a/vendor/github.com/vmware/govmomi/vim25/types/enum.go b/vendor/github.com/vmware/govmomi/vim25/types/enum.go index a356fff4f..834cdcb79 100644 --- a/vendor/github.com/vmware/govmomi/vim25/types/enum.go +++ b/vendor/github.com/vmware/govmomi/vim25/types/enum.go @@ -272,6 +272,18 @@ func init() { t["ClusterComputeResourceHCIWorkflowState"] = reflect.TypeOf((*ClusterComputeResourceHCIWorkflowState)(nil)).Elem() } +type ClusterComputeResourceVcsHealthStatus string + +const ( + ClusterComputeResourceVcsHealthStatusHealthy = ClusterComputeResourceVcsHealthStatus("healthy") + ClusterComputeResourceVcsHealthStatusDegraded = ClusterComputeResourceVcsHealthStatus("degraded") + ClusterComputeResourceVcsHealthStatusNonhealthy = ClusterComputeResourceVcsHealthStatus("nonhealthy") +) + +func init() { + t["ClusterComputeResourceVcsHealthStatus"] = reflect.TypeOf((*ClusterComputeResourceVcsHealthStatus)(nil)).Elem() +} + type ClusterCryptoConfigInfoCryptoMode string const ( @@ -537,6 +549,7 @@ type CustomizationFailedReasonCode string const ( CustomizationFailedReasonCodeUserDefinedScriptDisabled = CustomizationFailedReasonCode("userDefinedScriptDisabled") + CustomizationFailedReasonCodeCustomizationDisabled = CustomizationFailedReasonCode("customizationDisabled") ) func init() { @@ -801,6 +814,7 @@ const ( DistributedVirtualSwitchHostInfrastructureTrafficClassHbr = DistributedVirtualSwitchHostInfrastructureTrafficClass("hbr") DistributedVirtualSwitchHostInfrastructureTrafficClassVsan = DistributedVirtualSwitchHostInfrastructureTrafficClass("vsan") DistributedVirtualSwitchHostInfrastructureTrafficClassVdp = DistributedVirtualSwitchHostInfrastructureTrafficClass("vdp") + DistributedVirtualSwitchHostInfrastructureTrafficClassBackupNfc = DistributedVirtualSwitchHostInfrastructureTrafficClass("backupNfc") ) func init() { @@ -1440,6 +1454,7 @@ const ( HostFileSystemVolumeFileSystemTypeVFFS = HostFileSystemVolumeFileSystemType("VFFS") HostFileSystemVolumeFileSystemTypeVVOL = HostFileSystemVolumeFileSystemType("VVOL") HostFileSystemVolumeFileSystemTypePMEM = HostFileSystemVolumeFileSystemType("PMEM") + HostFileSystemVolumeFileSystemTypeVsanD = HostFileSystemVolumeFileSystemType("vsanD") HostFileSystemVolumeFileSystemTypeOTHER = HostFileSystemVolumeFileSystemType("OTHER") ) @@ -2098,6 +2113,18 @@ func init() { t["HostServicePolicy"] = reflect.TypeOf((*HostServicePolicy)(nil)).Elem() } +type HostSevInfoSevState string + +const ( + HostSevInfoSevStateUninitialized = HostSevInfoSevState("uninitialized") + HostSevInfoSevStateInitialized = HostSevInfoSevState("initialized") + HostSevInfoSevStateWorking = HostSevInfoSevState("working") +) + +func init() { + t["HostSevInfoSevState"] = reflect.TypeOf((*HostSevInfoSevState)(nil)).Elem() +} + type HostSgxInfoFlcModes string const ( @@ -2228,6 +2255,18 @@ func init() { t["HostTpmAttestationInfoAcceptanceStatus"] = reflect.TypeOf((*HostTpmAttestationInfoAcceptanceStatus)(nil)).Elem() } +type HostTrustAuthorityAttestationInfoAttestationStatus string + +const ( + HostTrustAuthorityAttestationInfoAttestationStatusAttested = HostTrustAuthorityAttestationInfoAttestationStatus("attested") + HostTrustAuthorityAttestationInfoAttestationStatusNotAttested = HostTrustAuthorityAttestationInfoAttestationStatus("notAttested") + HostTrustAuthorityAttestationInfoAttestationStatusUnknown = HostTrustAuthorityAttestationInfoAttestationStatus("unknown") +) + +func init() { + t["HostTrustAuthorityAttestationInfoAttestationStatus"] = reflect.TypeOf((*HostTrustAuthorityAttestationInfoAttestationStatus)(nil)).Elem() +} + type HostUnresolvedVmfsExtentUnresolvedReason string const ( @@ -4280,174 +4319,187 @@ func init() { type VirtualMachineGuestOsIdentifier string const ( - VirtualMachineGuestOsIdentifierDosGuest = VirtualMachineGuestOsIdentifier("dosGuest") - VirtualMachineGuestOsIdentifierWin31Guest = VirtualMachineGuestOsIdentifier("win31Guest") - VirtualMachineGuestOsIdentifierWin95Guest = VirtualMachineGuestOsIdentifier("win95Guest") - VirtualMachineGuestOsIdentifierWin98Guest = VirtualMachineGuestOsIdentifier("win98Guest") - VirtualMachineGuestOsIdentifierWinMeGuest = VirtualMachineGuestOsIdentifier("winMeGuest") - VirtualMachineGuestOsIdentifierWinNTGuest = VirtualMachineGuestOsIdentifier("winNTGuest") - VirtualMachineGuestOsIdentifierWin2000ProGuest = VirtualMachineGuestOsIdentifier("win2000ProGuest") - VirtualMachineGuestOsIdentifierWin2000ServGuest = VirtualMachineGuestOsIdentifier("win2000ServGuest") - VirtualMachineGuestOsIdentifierWin2000AdvServGuest = VirtualMachineGuestOsIdentifier("win2000AdvServGuest") - VirtualMachineGuestOsIdentifierWinXPHomeGuest = VirtualMachineGuestOsIdentifier("winXPHomeGuest") - VirtualMachineGuestOsIdentifierWinXPProGuest = VirtualMachineGuestOsIdentifier("winXPProGuest") - VirtualMachineGuestOsIdentifierWinXPPro64Guest = VirtualMachineGuestOsIdentifier("winXPPro64Guest") - VirtualMachineGuestOsIdentifierWinNetWebGuest = VirtualMachineGuestOsIdentifier("winNetWebGuest") - VirtualMachineGuestOsIdentifierWinNetStandardGuest = VirtualMachineGuestOsIdentifier("winNetStandardGuest") - VirtualMachineGuestOsIdentifierWinNetEnterpriseGuest = VirtualMachineGuestOsIdentifier("winNetEnterpriseGuest") - VirtualMachineGuestOsIdentifierWinNetDatacenterGuest = VirtualMachineGuestOsIdentifier("winNetDatacenterGuest") - VirtualMachineGuestOsIdentifierWinNetBusinessGuest = VirtualMachineGuestOsIdentifier("winNetBusinessGuest") - VirtualMachineGuestOsIdentifierWinNetStandard64Guest = VirtualMachineGuestOsIdentifier("winNetStandard64Guest") - VirtualMachineGuestOsIdentifierWinNetEnterprise64Guest = VirtualMachineGuestOsIdentifier("winNetEnterprise64Guest") - VirtualMachineGuestOsIdentifierWinLonghornGuest = VirtualMachineGuestOsIdentifier("winLonghornGuest") - VirtualMachineGuestOsIdentifierWinLonghorn64Guest = VirtualMachineGuestOsIdentifier("winLonghorn64Guest") - VirtualMachineGuestOsIdentifierWinNetDatacenter64Guest = VirtualMachineGuestOsIdentifier("winNetDatacenter64Guest") - VirtualMachineGuestOsIdentifierWinVistaGuest = VirtualMachineGuestOsIdentifier("winVistaGuest") - VirtualMachineGuestOsIdentifierWinVista64Guest = VirtualMachineGuestOsIdentifier("winVista64Guest") - VirtualMachineGuestOsIdentifierWindows7Guest = VirtualMachineGuestOsIdentifier("windows7Guest") - VirtualMachineGuestOsIdentifierWindows7_64Guest = VirtualMachineGuestOsIdentifier("windows7_64Guest") - VirtualMachineGuestOsIdentifierWindows7Server64Guest = VirtualMachineGuestOsIdentifier("windows7Server64Guest") - VirtualMachineGuestOsIdentifierWindows8Guest = VirtualMachineGuestOsIdentifier("windows8Guest") - VirtualMachineGuestOsIdentifierWindows8_64Guest = VirtualMachineGuestOsIdentifier("windows8_64Guest") - VirtualMachineGuestOsIdentifierWindows8Server64Guest = VirtualMachineGuestOsIdentifier("windows8Server64Guest") - VirtualMachineGuestOsIdentifierWindows9Guest = VirtualMachineGuestOsIdentifier("windows9Guest") - VirtualMachineGuestOsIdentifierWindows9_64Guest = VirtualMachineGuestOsIdentifier("windows9_64Guest") - VirtualMachineGuestOsIdentifierWindows9Server64Guest = VirtualMachineGuestOsIdentifier("windows9Server64Guest") - VirtualMachineGuestOsIdentifierWindowsHyperVGuest = VirtualMachineGuestOsIdentifier("windowsHyperVGuest") - VirtualMachineGuestOsIdentifierWindows2019srv_64Guest = VirtualMachineGuestOsIdentifier("windows2019srv_64Guest") - VirtualMachineGuestOsIdentifierFreebsdGuest = VirtualMachineGuestOsIdentifier("freebsdGuest") - VirtualMachineGuestOsIdentifierFreebsd64Guest = VirtualMachineGuestOsIdentifier("freebsd64Guest") - VirtualMachineGuestOsIdentifierFreebsd11Guest = VirtualMachineGuestOsIdentifier("freebsd11Guest") - VirtualMachineGuestOsIdentifierFreebsd11_64Guest = VirtualMachineGuestOsIdentifier("freebsd11_64Guest") - VirtualMachineGuestOsIdentifierFreebsd12Guest = VirtualMachineGuestOsIdentifier("freebsd12Guest") - VirtualMachineGuestOsIdentifierFreebsd12_64Guest = VirtualMachineGuestOsIdentifier("freebsd12_64Guest") - VirtualMachineGuestOsIdentifierRedhatGuest = VirtualMachineGuestOsIdentifier("redhatGuest") - VirtualMachineGuestOsIdentifierRhel2Guest = VirtualMachineGuestOsIdentifier("rhel2Guest") - VirtualMachineGuestOsIdentifierRhel3Guest = VirtualMachineGuestOsIdentifier("rhel3Guest") - VirtualMachineGuestOsIdentifierRhel3_64Guest = VirtualMachineGuestOsIdentifier("rhel3_64Guest") - VirtualMachineGuestOsIdentifierRhel4Guest = VirtualMachineGuestOsIdentifier("rhel4Guest") - VirtualMachineGuestOsIdentifierRhel4_64Guest = VirtualMachineGuestOsIdentifier("rhel4_64Guest") - VirtualMachineGuestOsIdentifierRhel5Guest = VirtualMachineGuestOsIdentifier("rhel5Guest") - VirtualMachineGuestOsIdentifierRhel5_64Guest = VirtualMachineGuestOsIdentifier("rhel5_64Guest") - VirtualMachineGuestOsIdentifierRhel6Guest = VirtualMachineGuestOsIdentifier("rhel6Guest") - VirtualMachineGuestOsIdentifierRhel6_64Guest = VirtualMachineGuestOsIdentifier("rhel6_64Guest") - VirtualMachineGuestOsIdentifierRhel7Guest = VirtualMachineGuestOsIdentifier("rhel7Guest") - VirtualMachineGuestOsIdentifierRhel7_64Guest = VirtualMachineGuestOsIdentifier("rhel7_64Guest") - VirtualMachineGuestOsIdentifierRhel8_64Guest = VirtualMachineGuestOsIdentifier("rhel8_64Guest") - VirtualMachineGuestOsIdentifierCentosGuest = VirtualMachineGuestOsIdentifier("centosGuest") - VirtualMachineGuestOsIdentifierCentos64Guest = VirtualMachineGuestOsIdentifier("centos64Guest") - VirtualMachineGuestOsIdentifierCentos6Guest = VirtualMachineGuestOsIdentifier("centos6Guest") - VirtualMachineGuestOsIdentifierCentos6_64Guest = VirtualMachineGuestOsIdentifier("centos6_64Guest") - VirtualMachineGuestOsIdentifierCentos7Guest = VirtualMachineGuestOsIdentifier("centos7Guest") - VirtualMachineGuestOsIdentifierCentos7_64Guest = VirtualMachineGuestOsIdentifier("centos7_64Guest") - VirtualMachineGuestOsIdentifierCentos8_64Guest = VirtualMachineGuestOsIdentifier("centos8_64Guest") - VirtualMachineGuestOsIdentifierOracleLinuxGuest = VirtualMachineGuestOsIdentifier("oracleLinuxGuest") - VirtualMachineGuestOsIdentifierOracleLinux64Guest = VirtualMachineGuestOsIdentifier("oracleLinux64Guest") - VirtualMachineGuestOsIdentifierOracleLinux6Guest = VirtualMachineGuestOsIdentifier("oracleLinux6Guest") - VirtualMachineGuestOsIdentifierOracleLinux6_64Guest = VirtualMachineGuestOsIdentifier("oracleLinux6_64Guest") - VirtualMachineGuestOsIdentifierOracleLinux7Guest = VirtualMachineGuestOsIdentifier("oracleLinux7Guest") - VirtualMachineGuestOsIdentifierOracleLinux7_64Guest = VirtualMachineGuestOsIdentifier("oracleLinux7_64Guest") - VirtualMachineGuestOsIdentifierOracleLinux8_64Guest = VirtualMachineGuestOsIdentifier("oracleLinux8_64Guest") - VirtualMachineGuestOsIdentifierSuseGuest = VirtualMachineGuestOsIdentifier("suseGuest") - VirtualMachineGuestOsIdentifierSuse64Guest = VirtualMachineGuestOsIdentifier("suse64Guest") - VirtualMachineGuestOsIdentifierSlesGuest = VirtualMachineGuestOsIdentifier("slesGuest") - VirtualMachineGuestOsIdentifierSles64Guest = VirtualMachineGuestOsIdentifier("sles64Guest") - VirtualMachineGuestOsIdentifierSles10Guest = VirtualMachineGuestOsIdentifier("sles10Guest") - VirtualMachineGuestOsIdentifierSles10_64Guest = VirtualMachineGuestOsIdentifier("sles10_64Guest") - VirtualMachineGuestOsIdentifierSles11Guest = VirtualMachineGuestOsIdentifier("sles11Guest") - VirtualMachineGuestOsIdentifierSles11_64Guest = VirtualMachineGuestOsIdentifier("sles11_64Guest") - VirtualMachineGuestOsIdentifierSles12Guest = VirtualMachineGuestOsIdentifier("sles12Guest") - VirtualMachineGuestOsIdentifierSles12_64Guest = VirtualMachineGuestOsIdentifier("sles12_64Guest") - VirtualMachineGuestOsIdentifierSles15_64Guest = VirtualMachineGuestOsIdentifier("sles15_64Guest") - VirtualMachineGuestOsIdentifierNld9Guest = VirtualMachineGuestOsIdentifier("nld9Guest") - VirtualMachineGuestOsIdentifierOesGuest = VirtualMachineGuestOsIdentifier("oesGuest") - VirtualMachineGuestOsIdentifierSjdsGuest = VirtualMachineGuestOsIdentifier("sjdsGuest") - VirtualMachineGuestOsIdentifierMandrakeGuest = VirtualMachineGuestOsIdentifier("mandrakeGuest") - VirtualMachineGuestOsIdentifierMandrivaGuest = VirtualMachineGuestOsIdentifier("mandrivaGuest") - VirtualMachineGuestOsIdentifierMandriva64Guest = VirtualMachineGuestOsIdentifier("mandriva64Guest") - VirtualMachineGuestOsIdentifierTurboLinuxGuest = VirtualMachineGuestOsIdentifier("turboLinuxGuest") - VirtualMachineGuestOsIdentifierTurboLinux64Guest = VirtualMachineGuestOsIdentifier("turboLinux64Guest") - VirtualMachineGuestOsIdentifierUbuntuGuest = VirtualMachineGuestOsIdentifier("ubuntuGuest") - VirtualMachineGuestOsIdentifierUbuntu64Guest = VirtualMachineGuestOsIdentifier("ubuntu64Guest") - VirtualMachineGuestOsIdentifierDebian4Guest = VirtualMachineGuestOsIdentifier("debian4Guest") - VirtualMachineGuestOsIdentifierDebian4_64Guest = VirtualMachineGuestOsIdentifier("debian4_64Guest") - VirtualMachineGuestOsIdentifierDebian5Guest = VirtualMachineGuestOsIdentifier("debian5Guest") - VirtualMachineGuestOsIdentifierDebian5_64Guest = VirtualMachineGuestOsIdentifier("debian5_64Guest") - VirtualMachineGuestOsIdentifierDebian6Guest = VirtualMachineGuestOsIdentifier("debian6Guest") - VirtualMachineGuestOsIdentifierDebian6_64Guest = VirtualMachineGuestOsIdentifier("debian6_64Guest") - VirtualMachineGuestOsIdentifierDebian7Guest = VirtualMachineGuestOsIdentifier("debian7Guest") - VirtualMachineGuestOsIdentifierDebian7_64Guest = VirtualMachineGuestOsIdentifier("debian7_64Guest") - VirtualMachineGuestOsIdentifierDebian8Guest = VirtualMachineGuestOsIdentifier("debian8Guest") - VirtualMachineGuestOsIdentifierDebian8_64Guest = VirtualMachineGuestOsIdentifier("debian8_64Guest") - VirtualMachineGuestOsIdentifierDebian9Guest = VirtualMachineGuestOsIdentifier("debian9Guest") - VirtualMachineGuestOsIdentifierDebian9_64Guest = VirtualMachineGuestOsIdentifier("debian9_64Guest") - VirtualMachineGuestOsIdentifierDebian10Guest = VirtualMachineGuestOsIdentifier("debian10Guest") - VirtualMachineGuestOsIdentifierDebian10_64Guest = VirtualMachineGuestOsIdentifier("debian10_64Guest") - VirtualMachineGuestOsIdentifierDebian11Guest = VirtualMachineGuestOsIdentifier("debian11Guest") - VirtualMachineGuestOsIdentifierDebian11_64Guest = VirtualMachineGuestOsIdentifier("debian11_64Guest") - VirtualMachineGuestOsIdentifierAsianux3Guest = VirtualMachineGuestOsIdentifier("asianux3Guest") - VirtualMachineGuestOsIdentifierAsianux3_64Guest = VirtualMachineGuestOsIdentifier("asianux3_64Guest") - VirtualMachineGuestOsIdentifierAsianux4Guest = VirtualMachineGuestOsIdentifier("asianux4Guest") - VirtualMachineGuestOsIdentifierAsianux4_64Guest = VirtualMachineGuestOsIdentifier("asianux4_64Guest") - VirtualMachineGuestOsIdentifierAsianux5_64Guest = VirtualMachineGuestOsIdentifier("asianux5_64Guest") - VirtualMachineGuestOsIdentifierAsianux7_64Guest = VirtualMachineGuestOsIdentifier("asianux7_64Guest") - VirtualMachineGuestOsIdentifierAsianux8_64Guest = VirtualMachineGuestOsIdentifier("asianux8_64Guest") - VirtualMachineGuestOsIdentifierOpensuseGuest = VirtualMachineGuestOsIdentifier("opensuseGuest") - VirtualMachineGuestOsIdentifierOpensuse64Guest = VirtualMachineGuestOsIdentifier("opensuse64Guest") - VirtualMachineGuestOsIdentifierFedoraGuest = VirtualMachineGuestOsIdentifier("fedoraGuest") - VirtualMachineGuestOsIdentifierFedora64Guest = VirtualMachineGuestOsIdentifier("fedora64Guest") - VirtualMachineGuestOsIdentifierCoreos64Guest = VirtualMachineGuestOsIdentifier("coreos64Guest") - VirtualMachineGuestOsIdentifierVmwarePhoton64Guest = VirtualMachineGuestOsIdentifier("vmwarePhoton64Guest") - VirtualMachineGuestOsIdentifierOther24xLinuxGuest = VirtualMachineGuestOsIdentifier("other24xLinuxGuest") - VirtualMachineGuestOsIdentifierOther26xLinuxGuest = VirtualMachineGuestOsIdentifier("other26xLinuxGuest") - VirtualMachineGuestOsIdentifierOtherLinuxGuest = VirtualMachineGuestOsIdentifier("otherLinuxGuest") - VirtualMachineGuestOsIdentifierOther3xLinuxGuest = VirtualMachineGuestOsIdentifier("other3xLinuxGuest") - VirtualMachineGuestOsIdentifierOther4xLinuxGuest = VirtualMachineGuestOsIdentifier("other4xLinuxGuest") - VirtualMachineGuestOsIdentifierGenericLinuxGuest = VirtualMachineGuestOsIdentifier("genericLinuxGuest") - VirtualMachineGuestOsIdentifierOther24xLinux64Guest = VirtualMachineGuestOsIdentifier("other24xLinux64Guest") - VirtualMachineGuestOsIdentifierOther26xLinux64Guest = VirtualMachineGuestOsIdentifier("other26xLinux64Guest") - VirtualMachineGuestOsIdentifierOther3xLinux64Guest = VirtualMachineGuestOsIdentifier("other3xLinux64Guest") - VirtualMachineGuestOsIdentifierOther4xLinux64Guest = VirtualMachineGuestOsIdentifier("other4xLinux64Guest") - VirtualMachineGuestOsIdentifierOtherLinux64Guest = VirtualMachineGuestOsIdentifier("otherLinux64Guest") - VirtualMachineGuestOsIdentifierSolaris6Guest = VirtualMachineGuestOsIdentifier("solaris6Guest") - VirtualMachineGuestOsIdentifierSolaris7Guest = VirtualMachineGuestOsIdentifier("solaris7Guest") - VirtualMachineGuestOsIdentifierSolaris8Guest = VirtualMachineGuestOsIdentifier("solaris8Guest") - VirtualMachineGuestOsIdentifierSolaris9Guest = VirtualMachineGuestOsIdentifier("solaris9Guest") - VirtualMachineGuestOsIdentifierSolaris10Guest = VirtualMachineGuestOsIdentifier("solaris10Guest") - VirtualMachineGuestOsIdentifierSolaris10_64Guest = VirtualMachineGuestOsIdentifier("solaris10_64Guest") - VirtualMachineGuestOsIdentifierSolaris11_64Guest = VirtualMachineGuestOsIdentifier("solaris11_64Guest") - VirtualMachineGuestOsIdentifierOs2Guest = VirtualMachineGuestOsIdentifier("os2Guest") - VirtualMachineGuestOsIdentifierEComStationGuest = VirtualMachineGuestOsIdentifier("eComStationGuest") - VirtualMachineGuestOsIdentifierEComStation2Guest = VirtualMachineGuestOsIdentifier("eComStation2Guest") - VirtualMachineGuestOsIdentifierNetware4Guest = VirtualMachineGuestOsIdentifier("netware4Guest") - VirtualMachineGuestOsIdentifierNetware5Guest = VirtualMachineGuestOsIdentifier("netware5Guest") - VirtualMachineGuestOsIdentifierNetware6Guest = VirtualMachineGuestOsIdentifier("netware6Guest") - VirtualMachineGuestOsIdentifierOpenServer5Guest = VirtualMachineGuestOsIdentifier("openServer5Guest") - VirtualMachineGuestOsIdentifierOpenServer6Guest = VirtualMachineGuestOsIdentifier("openServer6Guest") - VirtualMachineGuestOsIdentifierUnixWare7Guest = VirtualMachineGuestOsIdentifier("unixWare7Guest") - VirtualMachineGuestOsIdentifierDarwinGuest = VirtualMachineGuestOsIdentifier("darwinGuest") - VirtualMachineGuestOsIdentifierDarwin64Guest = VirtualMachineGuestOsIdentifier("darwin64Guest") - VirtualMachineGuestOsIdentifierDarwin10Guest = VirtualMachineGuestOsIdentifier("darwin10Guest") - VirtualMachineGuestOsIdentifierDarwin10_64Guest = VirtualMachineGuestOsIdentifier("darwin10_64Guest") - VirtualMachineGuestOsIdentifierDarwin11Guest = VirtualMachineGuestOsIdentifier("darwin11Guest") - VirtualMachineGuestOsIdentifierDarwin11_64Guest = VirtualMachineGuestOsIdentifier("darwin11_64Guest") - VirtualMachineGuestOsIdentifierDarwin12_64Guest = VirtualMachineGuestOsIdentifier("darwin12_64Guest") - VirtualMachineGuestOsIdentifierDarwin13_64Guest = VirtualMachineGuestOsIdentifier("darwin13_64Guest") - VirtualMachineGuestOsIdentifierDarwin14_64Guest = VirtualMachineGuestOsIdentifier("darwin14_64Guest") - VirtualMachineGuestOsIdentifierDarwin15_64Guest = VirtualMachineGuestOsIdentifier("darwin15_64Guest") - VirtualMachineGuestOsIdentifierDarwin16_64Guest = VirtualMachineGuestOsIdentifier("darwin16_64Guest") - VirtualMachineGuestOsIdentifierDarwin17_64Guest = VirtualMachineGuestOsIdentifier("darwin17_64Guest") - VirtualMachineGuestOsIdentifierDarwin18_64Guest = VirtualMachineGuestOsIdentifier("darwin18_64Guest") - VirtualMachineGuestOsIdentifierDarwin19_64Guest = VirtualMachineGuestOsIdentifier("darwin19_64Guest") - VirtualMachineGuestOsIdentifierVmkernelGuest = VirtualMachineGuestOsIdentifier("vmkernelGuest") - VirtualMachineGuestOsIdentifierVmkernel5Guest = VirtualMachineGuestOsIdentifier("vmkernel5Guest") - VirtualMachineGuestOsIdentifierVmkernel6Guest = VirtualMachineGuestOsIdentifier("vmkernel6Guest") - VirtualMachineGuestOsIdentifierVmkernel65Guest = VirtualMachineGuestOsIdentifier("vmkernel65Guest") - VirtualMachineGuestOsIdentifierVmkernel7Guest = VirtualMachineGuestOsIdentifier("vmkernel7Guest") - VirtualMachineGuestOsIdentifierAmazonlinux2_64Guest = VirtualMachineGuestOsIdentifier("amazonlinux2_64Guest") - VirtualMachineGuestOsIdentifierCrxPod1Guest = VirtualMachineGuestOsIdentifier("crxPod1Guest") - VirtualMachineGuestOsIdentifierOtherGuest = VirtualMachineGuestOsIdentifier("otherGuest") - VirtualMachineGuestOsIdentifierOtherGuest64 = VirtualMachineGuestOsIdentifier("otherGuest64") + VirtualMachineGuestOsIdentifierDosGuest = VirtualMachineGuestOsIdentifier("dosGuest") + VirtualMachineGuestOsIdentifierWin31Guest = VirtualMachineGuestOsIdentifier("win31Guest") + VirtualMachineGuestOsIdentifierWin95Guest = VirtualMachineGuestOsIdentifier("win95Guest") + VirtualMachineGuestOsIdentifierWin98Guest = VirtualMachineGuestOsIdentifier("win98Guest") + VirtualMachineGuestOsIdentifierWinMeGuest = VirtualMachineGuestOsIdentifier("winMeGuest") + VirtualMachineGuestOsIdentifierWinNTGuest = VirtualMachineGuestOsIdentifier("winNTGuest") + VirtualMachineGuestOsIdentifierWin2000ProGuest = VirtualMachineGuestOsIdentifier("win2000ProGuest") + VirtualMachineGuestOsIdentifierWin2000ServGuest = VirtualMachineGuestOsIdentifier("win2000ServGuest") + VirtualMachineGuestOsIdentifierWin2000AdvServGuest = VirtualMachineGuestOsIdentifier("win2000AdvServGuest") + VirtualMachineGuestOsIdentifierWinXPHomeGuest = VirtualMachineGuestOsIdentifier("winXPHomeGuest") + VirtualMachineGuestOsIdentifierWinXPProGuest = VirtualMachineGuestOsIdentifier("winXPProGuest") + VirtualMachineGuestOsIdentifierWinXPPro64Guest = VirtualMachineGuestOsIdentifier("winXPPro64Guest") + VirtualMachineGuestOsIdentifierWinNetWebGuest = VirtualMachineGuestOsIdentifier("winNetWebGuest") + VirtualMachineGuestOsIdentifierWinNetStandardGuest = VirtualMachineGuestOsIdentifier("winNetStandardGuest") + VirtualMachineGuestOsIdentifierWinNetEnterpriseGuest = VirtualMachineGuestOsIdentifier("winNetEnterpriseGuest") + VirtualMachineGuestOsIdentifierWinNetDatacenterGuest = VirtualMachineGuestOsIdentifier("winNetDatacenterGuest") + VirtualMachineGuestOsIdentifierWinNetBusinessGuest = VirtualMachineGuestOsIdentifier("winNetBusinessGuest") + VirtualMachineGuestOsIdentifierWinNetStandard64Guest = VirtualMachineGuestOsIdentifier("winNetStandard64Guest") + VirtualMachineGuestOsIdentifierWinNetEnterprise64Guest = VirtualMachineGuestOsIdentifier("winNetEnterprise64Guest") + VirtualMachineGuestOsIdentifierWinLonghornGuest = VirtualMachineGuestOsIdentifier("winLonghornGuest") + VirtualMachineGuestOsIdentifierWinLonghorn64Guest = VirtualMachineGuestOsIdentifier("winLonghorn64Guest") + VirtualMachineGuestOsIdentifierWinNetDatacenter64Guest = VirtualMachineGuestOsIdentifier("winNetDatacenter64Guest") + VirtualMachineGuestOsIdentifierWinVistaGuest = VirtualMachineGuestOsIdentifier("winVistaGuest") + VirtualMachineGuestOsIdentifierWinVista64Guest = VirtualMachineGuestOsIdentifier("winVista64Guest") + VirtualMachineGuestOsIdentifierWindows7Guest = VirtualMachineGuestOsIdentifier("windows7Guest") + VirtualMachineGuestOsIdentifierWindows7_64Guest = VirtualMachineGuestOsIdentifier("windows7_64Guest") + VirtualMachineGuestOsIdentifierWindows7Server64Guest = VirtualMachineGuestOsIdentifier("windows7Server64Guest") + VirtualMachineGuestOsIdentifierWindows8Guest = VirtualMachineGuestOsIdentifier("windows8Guest") + VirtualMachineGuestOsIdentifierWindows8_64Guest = VirtualMachineGuestOsIdentifier("windows8_64Guest") + VirtualMachineGuestOsIdentifierWindows8Server64Guest = VirtualMachineGuestOsIdentifier("windows8Server64Guest") + VirtualMachineGuestOsIdentifierWindows9Guest = VirtualMachineGuestOsIdentifier("windows9Guest") + VirtualMachineGuestOsIdentifierWindows9_64Guest = VirtualMachineGuestOsIdentifier("windows9_64Guest") + VirtualMachineGuestOsIdentifierWindows9Server64Guest = VirtualMachineGuestOsIdentifier("windows9Server64Guest") + VirtualMachineGuestOsIdentifierWindowsHyperVGuest = VirtualMachineGuestOsIdentifier("windowsHyperVGuest") + VirtualMachineGuestOsIdentifierWindows2019srv_64Guest = VirtualMachineGuestOsIdentifier("windows2019srv_64Guest") + VirtualMachineGuestOsIdentifierWindows2019srvNext_64Guest = VirtualMachineGuestOsIdentifier("windows2019srvNext_64Guest") + VirtualMachineGuestOsIdentifierFreebsdGuest = VirtualMachineGuestOsIdentifier("freebsdGuest") + VirtualMachineGuestOsIdentifierFreebsd64Guest = VirtualMachineGuestOsIdentifier("freebsd64Guest") + VirtualMachineGuestOsIdentifierFreebsd11Guest = VirtualMachineGuestOsIdentifier("freebsd11Guest") + VirtualMachineGuestOsIdentifierFreebsd11_64Guest = VirtualMachineGuestOsIdentifier("freebsd11_64Guest") + VirtualMachineGuestOsIdentifierFreebsd12Guest = VirtualMachineGuestOsIdentifier("freebsd12Guest") + VirtualMachineGuestOsIdentifierFreebsd12_64Guest = VirtualMachineGuestOsIdentifier("freebsd12_64Guest") + VirtualMachineGuestOsIdentifierFreebsd13Guest = VirtualMachineGuestOsIdentifier("freebsd13Guest") + VirtualMachineGuestOsIdentifierFreebsd13_64Guest = VirtualMachineGuestOsIdentifier("freebsd13_64Guest") + VirtualMachineGuestOsIdentifierRedhatGuest = VirtualMachineGuestOsIdentifier("redhatGuest") + VirtualMachineGuestOsIdentifierRhel2Guest = VirtualMachineGuestOsIdentifier("rhel2Guest") + VirtualMachineGuestOsIdentifierRhel3Guest = VirtualMachineGuestOsIdentifier("rhel3Guest") + VirtualMachineGuestOsIdentifierRhel3_64Guest = VirtualMachineGuestOsIdentifier("rhel3_64Guest") + VirtualMachineGuestOsIdentifierRhel4Guest = VirtualMachineGuestOsIdentifier("rhel4Guest") + VirtualMachineGuestOsIdentifierRhel4_64Guest = VirtualMachineGuestOsIdentifier("rhel4_64Guest") + VirtualMachineGuestOsIdentifierRhel5Guest = VirtualMachineGuestOsIdentifier("rhel5Guest") + VirtualMachineGuestOsIdentifierRhel5_64Guest = VirtualMachineGuestOsIdentifier("rhel5_64Guest") + VirtualMachineGuestOsIdentifierRhel6Guest = VirtualMachineGuestOsIdentifier("rhel6Guest") + VirtualMachineGuestOsIdentifierRhel6_64Guest = VirtualMachineGuestOsIdentifier("rhel6_64Guest") + VirtualMachineGuestOsIdentifierRhel7Guest = VirtualMachineGuestOsIdentifier("rhel7Guest") + VirtualMachineGuestOsIdentifierRhel7_64Guest = VirtualMachineGuestOsIdentifier("rhel7_64Guest") + VirtualMachineGuestOsIdentifierRhel8_64Guest = VirtualMachineGuestOsIdentifier("rhel8_64Guest") + VirtualMachineGuestOsIdentifierRhel9_64Guest = VirtualMachineGuestOsIdentifier("rhel9_64Guest") + VirtualMachineGuestOsIdentifierCentosGuest = VirtualMachineGuestOsIdentifier("centosGuest") + VirtualMachineGuestOsIdentifierCentos64Guest = VirtualMachineGuestOsIdentifier("centos64Guest") + VirtualMachineGuestOsIdentifierCentos6Guest = VirtualMachineGuestOsIdentifier("centos6Guest") + VirtualMachineGuestOsIdentifierCentos6_64Guest = VirtualMachineGuestOsIdentifier("centos6_64Guest") + VirtualMachineGuestOsIdentifierCentos7Guest = VirtualMachineGuestOsIdentifier("centos7Guest") + VirtualMachineGuestOsIdentifierCentos7_64Guest = VirtualMachineGuestOsIdentifier("centos7_64Guest") + VirtualMachineGuestOsIdentifierCentos8_64Guest = VirtualMachineGuestOsIdentifier("centos8_64Guest") + VirtualMachineGuestOsIdentifierCentos9_64Guest = VirtualMachineGuestOsIdentifier("centos9_64Guest") + VirtualMachineGuestOsIdentifierOracleLinuxGuest = VirtualMachineGuestOsIdentifier("oracleLinuxGuest") + VirtualMachineGuestOsIdentifierOracleLinux64Guest = VirtualMachineGuestOsIdentifier("oracleLinux64Guest") + VirtualMachineGuestOsIdentifierOracleLinux6Guest = VirtualMachineGuestOsIdentifier("oracleLinux6Guest") + VirtualMachineGuestOsIdentifierOracleLinux6_64Guest = VirtualMachineGuestOsIdentifier("oracleLinux6_64Guest") + VirtualMachineGuestOsIdentifierOracleLinux7Guest = VirtualMachineGuestOsIdentifier("oracleLinux7Guest") + VirtualMachineGuestOsIdentifierOracleLinux7_64Guest = VirtualMachineGuestOsIdentifier("oracleLinux7_64Guest") + VirtualMachineGuestOsIdentifierOracleLinux8_64Guest = VirtualMachineGuestOsIdentifier("oracleLinux8_64Guest") + VirtualMachineGuestOsIdentifierOracleLinux9_64Guest = VirtualMachineGuestOsIdentifier("oracleLinux9_64Guest") + VirtualMachineGuestOsIdentifierSuseGuest = VirtualMachineGuestOsIdentifier("suseGuest") + VirtualMachineGuestOsIdentifierSuse64Guest = VirtualMachineGuestOsIdentifier("suse64Guest") + VirtualMachineGuestOsIdentifierSlesGuest = VirtualMachineGuestOsIdentifier("slesGuest") + VirtualMachineGuestOsIdentifierSles64Guest = VirtualMachineGuestOsIdentifier("sles64Guest") + VirtualMachineGuestOsIdentifierSles10Guest = VirtualMachineGuestOsIdentifier("sles10Guest") + VirtualMachineGuestOsIdentifierSles10_64Guest = VirtualMachineGuestOsIdentifier("sles10_64Guest") + VirtualMachineGuestOsIdentifierSles11Guest = VirtualMachineGuestOsIdentifier("sles11Guest") + VirtualMachineGuestOsIdentifierSles11_64Guest = VirtualMachineGuestOsIdentifier("sles11_64Guest") + VirtualMachineGuestOsIdentifierSles12Guest = VirtualMachineGuestOsIdentifier("sles12Guest") + VirtualMachineGuestOsIdentifierSles12_64Guest = VirtualMachineGuestOsIdentifier("sles12_64Guest") + VirtualMachineGuestOsIdentifierSles15_64Guest = VirtualMachineGuestOsIdentifier("sles15_64Guest") + VirtualMachineGuestOsIdentifierSles16_64Guest = VirtualMachineGuestOsIdentifier("sles16_64Guest") + VirtualMachineGuestOsIdentifierNld9Guest = VirtualMachineGuestOsIdentifier("nld9Guest") + VirtualMachineGuestOsIdentifierOesGuest = VirtualMachineGuestOsIdentifier("oesGuest") + VirtualMachineGuestOsIdentifierSjdsGuest = VirtualMachineGuestOsIdentifier("sjdsGuest") + VirtualMachineGuestOsIdentifierMandrakeGuest = VirtualMachineGuestOsIdentifier("mandrakeGuest") + VirtualMachineGuestOsIdentifierMandrivaGuest = VirtualMachineGuestOsIdentifier("mandrivaGuest") + VirtualMachineGuestOsIdentifierMandriva64Guest = VirtualMachineGuestOsIdentifier("mandriva64Guest") + VirtualMachineGuestOsIdentifierTurboLinuxGuest = VirtualMachineGuestOsIdentifier("turboLinuxGuest") + VirtualMachineGuestOsIdentifierTurboLinux64Guest = VirtualMachineGuestOsIdentifier("turboLinux64Guest") + VirtualMachineGuestOsIdentifierUbuntuGuest = VirtualMachineGuestOsIdentifier("ubuntuGuest") + VirtualMachineGuestOsIdentifierUbuntu64Guest = VirtualMachineGuestOsIdentifier("ubuntu64Guest") + VirtualMachineGuestOsIdentifierDebian4Guest = VirtualMachineGuestOsIdentifier("debian4Guest") + VirtualMachineGuestOsIdentifierDebian4_64Guest = VirtualMachineGuestOsIdentifier("debian4_64Guest") + VirtualMachineGuestOsIdentifierDebian5Guest = VirtualMachineGuestOsIdentifier("debian5Guest") + VirtualMachineGuestOsIdentifierDebian5_64Guest = VirtualMachineGuestOsIdentifier("debian5_64Guest") + VirtualMachineGuestOsIdentifierDebian6Guest = VirtualMachineGuestOsIdentifier("debian6Guest") + VirtualMachineGuestOsIdentifierDebian6_64Guest = VirtualMachineGuestOsIdentifier("debian6_64Guest") + VirtualMachineGuestOsIdentifierDebian7Guest = VirtualMachineGuestOsIdentifier("debian7Guest") + VirtualMachineGuestOsIdentifierDebian7_64Guest = VirtualMachineGuestOsIdentifier("debian7_64Guest") + VirtualMachineGuestOsIdentifierDebian8Guest = VirtualMachineGuestOsIdentifier("debian8Guest") + VirtualMachineGuestOsIdentifierDebian8_64Guest = VirtualMachineGuestOsIdentifier("debian8_64Guest") + VirtualMachineGuestOsIdentifierDebian9Guest = VirtualMachineGuestOsIdentifier("debian9Guest") + VirtualMachineGuestOsIdentifierDebian9_64Guest = VirtualMachineGuestOsIdentifier("debian9_64Guest") + VirtualMachineGuestOsIdentifierDebian10Guest = VirtualMachineGuestOsIdentifier("debian10Guest") + VirtualMachineGuestOsIdentifierDebian10_64Guest = VirtualMachineGuestOsIdentifier("debian10_64Guest") + VirtualMachineGuestOsIdentifierDebian11Guest = VirtualMachineGuestOsIdentifier("debian11Guest") + VirtualMachineGuestOsIdentifierDebian11_64Guest = VirtualMachineGuestOsIdentifier("debian11_64Guest") + VirtualMachineGuestOsIdentifierAsianux3Guest = VirtualMachineGuestOsIdentifier("asianux3Guest") + VirtualMachineGuestOsIdentifierAsianux3_64Guest = VirtualMachineGuestOsIdentifier("asianux3_64Guest") + VirtualMachineGuestOsIdentifierAsianux4Guest = VirtualMachineGuestOsIdentifier("asianux4Guest") + VirtualMachineGuestOsIdentifierAsianux4_64Guest = VirtualMachineGuestOsIdentifier("asianux4_64Guest") + VirtualMachineGuestOsIdentifierAsianux5_64Guest = VirtualMachineGuestOsIdentifier("asianux5_64Guest") + VirtualMachineGuestOsIdentifierAsianux7_64Guest = VirtualMachineGuestOsIdentifier("asianux7_64Guest") + VirtualMachineGuestOsIdentifierAsianux8_64Guest = VirtualMachineGuestOsIdentifier("asianux8_64Guest") + VirtualMachineGuestOsIdentifierAsianux9_64Guest = VirtualMachineGuestOsIdentifier("asianux9_64Guest") + VirtualMachineGuestOsIdentifierOpensuseGuest = VirtualMachineGuestOsIdentifier("opensuseGuest") + VirtualMachineGuestOsIdentifierOpensuse64Guest = VirtualMachineGuestOsIdentifier("opensuse64Guest") + VirtualMachineGuestOsIdentifierFedoraGuest = VirtualMachineGuestOsIdentifier("fedoraGuest") + VirtualMachineGuestOsIdentifierFedora64Guest = VirtualMachineGuestOsIdentifier("fedora64Guest") + VirtualMachineGuestOsIdentifierCoreos64Guest = VirtualMachineGuestOsIdentifier("coreos64Guest") + VirtualMachineGuestOsIdentifierVmwarePhoton64Guest = VirtualMachineGuestOsIdentifier("vmwarePhoton64Guest") + VirtualMachineGuestOsIdentifierOther24xLinuxGuest = VirtualMachineGuestOsIdentifier("other24xLinuxGuest") + VirtualMachineGuestOsIdentifierOther26xLinuxGuest = VirtualMachineGuestOsIdentifier("other26xLinuxGuest") + VirtualMachineGuestOsIdentifierOtherLinuxGuest = VirtualMachineGuestOsIdentifier("otherLinuxGuest") + VirtualMachineGuestOsIdentifierOther3xLinuxGuest = VirtualMachineGuestOsIdentifier("other3xLinuxGuest") + VirtualMachineGuestOsIdentifierOther4xLinuxGuest = VirtualMachineGuestOsIdentifier("other4xLinuxGuest") + VirtualMachineGuestOsIdentifierOther5xLinuxGuest = VirtualMachineGuestOsIdentifier("other5xLinuxGuest") + VirtualMachineGuestOsIdentifierGenericLinuxGuest = VirtualMachineGuestOsIdentifier("genericLinuxGuest") + VirtualMachineGuestOsIdentifierOther24xLinux64Guest = VirtualMachineGuestOsIdentifier("other24xLinux64Guest") + VirtualMachineGuestOsIdentifierOther26xLinux64Guest = VirtualMachineGuestOsIdentifier("other26xLinux64Guest") + VirtualMachineGuestOsIdentifierOther3xLinux64Guest = VirtualMachineGuestOsIdentifier("other3xLinux64Guest") + VirtualMachineGuestOsIdentifierOther4xLinux64Guest = VirtualMachineGuestOsIdentifier("other4xLinux64Guest") + VirtualMachineGuestOsIdentifierOther5xLinux64Guest = VirtualMachineGuestOsIdentifier("other5xLinux64Guest") + VirtualMachineGuestOsIdentifierOtherLinux64Guest = VirtualMachineGuestOsIdentifier("otherLinux64Guest") + VirtualMachineGuestOsIdentifierSolaris6Guest = VirtualMachineGuestOsIdentifier("solaris6Guest") + VirtualMachineGuestOsIdentifierSolaris7Guest = VirtualMachineGuestOsIdentifier("solaris7Guest") + VirtualMachineGuestOsIdentifierSolaris8Guest = VirtualMachineGuestOsIdentifier("solaris8Guest") + VirtualMachineGuestOsIdentifierSolaris9Guest = VirtualMachineGuestOsIdentifier("solaris9Guest") + VirtualMachineGuestOsIdentifierSolaris10Guest = VirtualMachineGuestOsIdentifier("solaris10Guest") + VirtualMachineGuestOsIdentifierSolaris10_64Guest = VirtualMachineGuestOsIdentifier("solaris10_64Guest") + VirtualMachineGuestOsIdentifierSolaris11_64Guest = VirtualMachineGuestOsIdentifier("solaris11_64Guest") + VirtualMachineGuestOsIdentifierOs2Guest = VirtualMachineGuestOsIdentifier("os2Guest") + VirtualMachineGuestOsIdentifierEComStationGuest = VirtualMachineGuestOsIdentifier("eComStationGuest") + VirtualMachineGuestOsIdentifierEComStation2Guest = VirtualMachineGuestOsIdentifier("eComStation2Guest") + VirtualMachineGuestOsIdentifierNetware4Guest = VirtualMachineGuestOsIdentifier("netware4Guest") + VirtualMachineGuestOsIdentifierNetware5Guest = VirtualMachineGuestOsIdentifier("netware5Guest") + VirtualMachineGuestOsIdentifierNetware6Guest = VirtualMachineGuestOsIdentifier("netware6Guest") + VirtualMachineGuestOsIdentifierOpenServer5Guest = VirtualMachineGuestOsIdentifier("openServer5Guest") + VirtualMachineGuestOsIdentifierOpenServer6Guest = VirtualMachineGuestOsIdentifier("openServer6Guest") + VirtualMachineGuestOsIdentifierUnixWare7Guest = VirtualMachineGuestOsIdentifier("unixWare7Guest") + VirtualMachineGuestOsIdentifierDarwinGuest = VirtualMachineGuestOsIdentifier("darwinGuest") + VirtualMachineGuestOsIdentifierDarwin64Guest = VirtualMachineGuestOsIdentifier("darwin64Guest") + VirtualMachineGuestOsIdentifierDarwin10Guest = VirtualMachineGuestOsIdentifier("darwin10Guest") + VirtualMachineGuestOsIdentifierDarwin10_64Guest = VirtualMachineGuestOsIdentifier("darwin10_64Guest") + VirtualMachineGuestOsIdentifierDarwin11Guest = VirtualMachineGuestOsIdentifier("darwin11Guest") + VirtualMachineGuestOsIdentifierDarwin11_64Guest = VirtualMachineGuestOsIdentifier("darwin11_64Guest") + VirtualMachineGuestOsIdentifierDarwin12_64Guest = VirtualMachineGuestOsIdentifier("darwin12_64Guest") + VirtualMachineGuestOsIdentifierDarwin13_64Guest = VirtualMachineGuestOsIdentifier("darwin13_64Guest") + VirtualMachineGuestOsIdentifierDarwin14_64Guest = VirtualMachineGuestOsIdentifier("darwin14_64Guest") + VirtualMachineGuestOsIdentifierDarwin15_64Guest = VirtualMachineGuestOsIdentifier("darwin15_64Guest") + VirtualMachineGuestOsIdentifierDarwin16_64Guest = VirtualMachineGuestOsIdentifier("darwin16_64Guest") + VirtualMachineGuestOsIdentifierDarwin17_64Guest = VirtualMachineGuestOsIdentifier("darwin17_64Guest") + VirtualMachineGuestOsIdentifierDarwin18_64Guest = VirtualMachineGuestOsIdentifier("darwin18_64Guest") + VirtualMachineGuestOsIdentifierDarwin19_64Guest = VirtualMachineGuestOsIdentifier("darwin19_64Guest") + VirtualMachineGuestOsIdentifierDarwin20_64Guest = VirtualMachineGuestOsIdentifier("darwin20_64Guest") + VirtualMachineGuestOsIdentifierDarwin21_64Guest = VirtualMachineGuestOsIdentifier("darwin21_64Guest") + VirtualMachineGuestOsIdentifierVmkernelGuest = VirtualMachineGuestOsIdentifier("vmkernelGuest") + VirtualMachineGuestOsIdentifierVmkernel5Guest = VirtualMachineGuestOsIdentifier("vmkernel5Guest") + VirtualMachineGuestOsIdentifierVmkernel6Guest = VirtualMachineGuestOsIdentifier("vmkernel6Guest") + VirtualMachineGuestOsIdentifierVmkernel65Guest = VirtualMachineGuestOsIdentifier("vmkernel65Guest") + VirtualMachineGuestOsIdentifierVmkernel7Guest = VirtualMachineGuestOsIdentifier("vmkernel7Guest") + VirtualMachineGuestOsIdentifierAmazonlinux2_64Guest = VirtualMachineGuestOsIdentifier("amazonlinux2_64Guest") + VirtualMachineGuestOsIdentifierAmazonlinux3_64Guest = VirtualMachineGuestOsIdentifier("amazonlinux3_64Guest") + VirtualMachineGuestOsIdentifierCrxPod1Guest = VirtualMachineGuestOsIdentifier("crxPod1Guest") + VirtualMachineGuestOsIdentifierOtherGuest = VirtualMachineGuestOsIdentifier("otherGuest") + VirtualMachineGuestOsIdentifierOtherGuest64 = VirtualMachineGuestOsIdentifier("otherGuest64") ) func init() { diff --git a/vendor/github.com/vmware/govmomi/vim25/types/helpers.go b/vendor/github.com/vmware/govmomi/vim25/types/helpers.go index 95c49f333..d6efec47e 100644 --- a/vendor/github.com/vmware/govmomi/vim25/types/helpers.go +++ b/vendor/github.com/vmware/govmomi/vim25/types/helpers.go @@ -17,6 +17,7 @@ limitations under the License. package types import ( + "net/url" "reflect" "strings" "time" @@ -63,6 +64,11 @@ func (r *ManagedObjectReference) FromString(o string) bool { return true } +// Encode ManagedObjectReference for use with URL and File paths +func (r ManagedObjectReference) Encode() string { + return strings.Join([]string{r.Type, url.QueryEscape(r.Value)}, "-") +} + func (c *PerfCounterInfo) Name() string { return c.GroupInfo.GetElementDescription().Key + "." + c.NameInfo.GetElementDescription().Key + "." + string(c.RollupType) } diff --git a/vendor/github.com/vmware/govmomi/vim25/types/if.go b/vendor/github.com/vmware/govmomi/vim25/types/if.go index 9b377c96d..d80255000 100644 --- a/vendor/github.com/vmware/govmomi/vim25/types/if.go +++ b/vendor/github.com/vmware/govmomi/vim25/types/if.go @@ -798,7 +798,6 @@ func (b *DvsFilterConfig) GetDvsFilterConfig() *DvsFilterConfig { return b } type BaseDvsFilterConfig interface { GetDvsFilterConfig() *DvsFilterConfig - GetDvsTrafficFilterConfig() *DvsTrafficFilterConfig } func init() { @@ -841,21 +840,12 @@ func (b *DvsNetworkRuleQualifier) GetDvsNetworkRuleQualifier() *DvsNetworkRuleQu type BaseDvsNetworkRuleQualifier interface { GetDvsNetworkRuleQualifier() *DvsNetworkRuleQualifier - GetDvsIpNetworkRuleQualifier() *DvsIpNetworkRuleQualifier } func init() { t["BaseDvsNetworkRuleQualifier"] = reflect.TypeOf((*DvsNetworkRuleQualifier)(nil)).Elem() } -func (b *DvsIpNetworkRuleQualifier) GetDvsIpNetworkRuleQualifier() *DvsIpNetworkRuleQualifier { - return b -} - -type BaseDvsIpNetworkRuleQualifier interface { - GetDvsIpNetworkRuleQualifier() *DvsIpNetworkRuleQualifier -} - func (b *DvsTrafficFilterConfig) GetDvsTrafficFilterConfig() *DvsTrafficFilterConfig { return b } type BaseDvsTrafficFilterConfig interface { @@ -3022,6 +3012,16 @@ func init() { t["BaseVirtualMachineBootOptionsBootableDevice"] = reflect.TypeOf((*VirtualMachineBootOptionsBootableDevice)(nil)).Elem() } +func (b *VirtualMachineConnection) GetVirtualMachineConnection() *VirtualMachineConnection { return b } + +type BaseVirtualMachineConnection interface { + GetVirtualMachineConnection() *VirtualMachineConnection +} + +func init() { + t["BaseVirtualMachineConnection"] = reflect.TypeOf((*VirtualMachineConnection)(nil)).Elem() +} + func (b *VirtualMachineDeviceRuntimeInfoDeviceRuntimeState) GetVirtualMachineDeviceRuntimeInfoDeviceRuntimeState() *VirtualMachineDeviceRuntimeInfoDeviceRuntimeState { return b } diff --git a/vendor/github.com/vmware/govmomi/vim25/types/types.go b/vendor/github.com/vmware/govmomi/vim25/types/types.go index e10cf8219..ac5de63b4 100644 --- a/vendor/github.com/vmware/govmomi/vim25/types/types.go +++ b/vendor/github.com/vmware/govmomi/vim25/types/types.go @@ -1803,6 +1803,14 @@ func init() { t["ArrayOfClusterComputeResourceValidationResultBase"] = reflect.TypeOf((*ArrayOfClusterComputeResourceValidationResultBase)(nil)).Elem() } +type ArrayOfClusterComputeResourceVcsSlots struct { + ClusterComputeResourceVcsSlots []ClusterComputeResourceVcsSlots `xml:"ClusterComputeResourceVcsSlots,omitempty"` +} + +func init() { + t["ArrayOfClusterComputeResourceVcsSlots"] = reflect.TypeOf((*ArrayOfClusterComputeResourceVcsSlots)(nil)).Elem() +} + type ArrayOfClusterDasAamNodeState struct { ClusterDasAamNodeState []ClusterDasAamNodeState `xml:"ClusterDasAamNodeState,omitempty"` } @@ -2683,6 +2691,14 @@ func init() { t["ArrayOfFcoeConfigVlanRange"] = reflect.TypeOf((*ArrayOfFcoeConfigVlanRange)(nil)).Elem() } +type ArrayOfFeatureEVCMode struct { + FeatureEVCMode []FeatureEVCMode `xml:"FeatureEVCMode,omitempty"` +} + +func init() { + t["ArrayOfFeatureEVCMode"] = reflect.TypeOf((*ArrayOfFeatureEVCMode)(nil)).Elem() +} + type ArrayOfFileInfo struct { FileInfo []BaseFileInfo `xml:"FileInfo,omitempty,typeattr"` } @@ -3843,6 +3859,14 @@ func init() { t["ArrayOfHostTpmEventLogEntry"] = reflect.TypeOf((*ArrayOfHostTpmEventLogEntry)(nil)).Elem() } +type ArrayOfHostTrustAuthorityAttestationInfo struct { + HostTrustAuthorityAttestationInfo []HostTrustAuthorityAttestationInfo `xml:"HostTrustAuthorityAttestationInfo,omitempty"` +} + +func init() { + t["ArrayOfHostTrustAuthorityAttestationInfo"] = reflect.TypeOf((*ArrayOfHostTrustAuthorityAttestationInfo)(nil)).Elem() +} + type ArrayOfHostUnresolvedVmfsExtent struct { HostUnresolvedVmfsExtent []HostUnresolvedVmfsExtent `xml:"HostUnresolvedVmfsExtent,omitempty"` } @@ -5491,6 +5515,14 @@ func init() { t["ArrayOfVirtualMachineConfigSpec"] = reflect.TypeOf((*ArrayOfVirtualMachineConfigSpec)(nil)).Elem() } +type ArrayOfVirtualMachineConnection struct { + VirtualMachineConnection []BaseVirtualMachineConnection `xml:"VirtualMachineConnection,omitempty,typeattr"` +} + +func init() { + t["ArrayOfVirtualMachineConnection"] = reflect.TypeOf((*ArrayOfVirtualMachineConnection)(nil)).Elem() +} + type ArrayOfVirtualMachineCpuIdInfoSpec struct { VirtualMachineCpuIdInfoSpec []VirtualMachineCpuIdInfoSpec `xml:"VirtualMachineCpuIdInfoSpec,omitempty"` } @@ -7207,17 +7239,19 @@ func init() { type Capability struct { DynamicData - ProvisioningSupported bool `xml:"provisioningSupported"` - MultiHostSupported bool `xml:"multiHostSupported"` - UserShellAccessSupported bool `xml:"userShellAccessSupported"` - SupportedEVCMode []EVCMode `xml:"supportedEVCMode,omitempty"` - NetworkBackupAndRestoreSupported *bool `xml:"networkBackupAndRestoreSupported"` - FtDrsWithoutEvcSupported *bool `xml:"ftDrsWithoutEvcSupported"` - HciWorkflowSupported *bool `xml:"hciWorkflowSupported"` - ComputePolicyVersion int32 `xml:"computePolicyVersion,omitempty"` - ClusterPlacementSupported *bool `xml:"clusterPlacementSupported"` - LifecycleManagementSupported *bool `xml:"lifecycleManagementSupported"` - ScalableSharesSupported *bool `xml:"scalableSharesSupported"` + ProvisioningSupported bool `xml:"provisioningSupported"` + MultiHostSupported bool `xml:"multiHostSupported"` + UserShellAccessSupported bool `xml:"userShellAccessSupported"` + SupportedEVCMode []EVCMode `xml:"supportedEVCMode,omitempty"` + SupportedEVCGraphicsMode []FeatureEVCMode `xml:"supportedEVCGraphicsMode,omitempty"` + NetworkBackupAndRestoreSupported *bool `xml:"networkBackupAndRestoreSupported"` + FtDrsWithoutEvcSupported *bool `xml:"ftDrsWithoutEvcSupported"` + HciWorkflowSupported *bool `xml:"hciWorkflowSupported"` + ComputePolicyVersion int32 `xml:"computePolicyVersion,omitempty"` + ClusterPlacementSupported *bool `xml:"clusterPlacementSupported"` + LifecycleManagementSupported *bool `xml:"lifecycleManagementSupported"` + ScalableSharesSupported *bool `xml:"scalableSharesSupported"` + HadcsSupported *bool `xml:"hadcsSupported"` } func init() { @@ -7533,8 +7567,9 @@ type CheckCompliance_TaskResponse struct { } type CheckConfigureEvcModeRequestType struct { - This ManagedObjectReference `xml:"_this"` - EvcModeKey string `xml:"evcModeKey"` + This ManagedObjectReference `xml:"_this"` + EvcModeKey string `xml:"evcModeKey"` + EvcGraphicsModeKey string `xml:"evcGraphicsModeKey,omitempty"` } func init() { @@ -8230,16 +8265,20 @@ func init() { type ClusterComputeResourceSummary struct { ComputeResourceSummary - CurrentFailoverLevel int32 `xml:"currentFailoverLevel"` - AdmissionControlInfo BaseClusterDasAdmissionControlInfo `xml:"admissionControlInfo,omitempty,typeattr"` - NumVmotions int32 `xml:"numVmotions"` - TargetBalance int32 `xml:"targetBalance,omitempty"` - CurrentBalance int32 `xml:"currentBalance,omitempty"` - DrsScore int32 `xml:"drsScore,omitempty"` - NumVmsPerDrsScoreBucket []int32 `xml:"numVmsPerDrsScoreBucket,omitempty"` - UsageSummary *ClusterUsageSummary `xml:"usageSummary,omitempty"` - CurrentEVCModeKey string `xml:"currentEVCModeKey,omitempty"` - DasData BaseClusterDasData `xml:"dasData,omitempty,typeattr"` + CurrentFailoverLevel int32 `xml:"currentFailoverLevel"` + AdmissionControlInfo BaseClusterDasAdmissionControlInfo `xml:"admissionControlInfo,omitempty,typeattr"` + NumVmotions int32 `xml:"numVmotions"` + TargetBalance int32 `xml:"targetBalance,omitempty"` + CurrentBalance int32 `xml:"currentBalance,omitempty"` + DrsScore int32 `xml:"drsScore,omitempty"` + NumVmsPerDrsScoreBucket []int32 `xml:"numVmsPerDrsScoreBucket,omitempty"` + UsageSummary *ClusterUsageSummary `xml:"usageSummary,omitempty"` + CurrentEVCModeKey string `xml:"currentEVCModeKey,omitempty"` + CurrentEVCGraphicsModeKey string `xml:"currentEVCGraphicsModeKey,omitempty"` + DasData BaseClusterDasData `xml:"dasData,omitempty,typeattr"` + ClusterMaintenanceModeStatus string `xml:"clusterMaintenanceModeStatus,omitempty"` + VcsHealthStatus string `xml:"vcsHealthStatus,omitempty"` + VcsSlots []ClusterComputeResourceVcsSlots `xml:"vcsSlots,omitempty"` } func init() { @@ -8249,8 +8288,9 @@ func init() { type ClusterComputeResourceVCProfile struct { DynamicData - ClusterSpec *ClusterConfigSpecEx `xml:"clusterSpec,omitempty"` - EvcModeKey string `xml:"evcModeKey,omitempty"` + ClusterSpec *ClusterConfigSpecEx `xml:"clusterSpec,omitempty"` + EvcModeKey string `xml:"evcModeKey,omitempty"` + EvcGraphicsModeKey string `xml:"evcGraphicsModeKey,omitempty"` } func init() { @@ -8267,6 +8307,17 @@ func init() { t["ClusterComputeResourceValidationResultBase"] = reflect.TypeOf((*ClusterComputeResourceValidationResultBase)(nil)).Elem() } +type ClusterComputeResourceVcsSlots struct { + DynamicData + + Host ManagedObjectReference `xml:"host"` + TotalSlots int32 `xml:"totalSlots"` +} + +func init() { + t["ClusterComputeResourceVcsSlots"] = reflect.TypeOf((*ClusterComputeResourceVcsSlots)(nil)).Elem() +} + type ClusterConfigInfo struct { DynamicData @@ -9583,6 +9634,7 @@ type ConfigTarget struct { DynamicPassthrough []VirtualMachineDynamicPassthroughInfo `xml:"dynamicPassthrough,omitempty"` SgxTargetInfo *VirtualMachineSgxTargetInfo `xml:"sgxTargetInfo,omitempty"` PrecisionClockInfo []VirtualMachinePrecisionClockInfo `xml:"precisionClockInfo,omitempty"` + SevSupported *bool `xml:"sevSupported"` } func init() { @@ -9647,8 +9699,9 @@ type ConfigureDatastorePrincipalResponse struct { } type ConfigureEvcModeRequestType struct { - This ManagedObjectReference `xml:"_this"` - EvcModeKey string `xml:"evcModeKey"` + This ManagedObjectReference `xml:"_this"` + EvcModeKey string `xml:"evcModeKey"` + EvcGraphicsModeKey string `xml:"evcGraphicsModeKey,omitempty"` } func init() { @@ -11128,9 +11181,10 @@ func init() { type CryptoKeyResult struct { DynamicData - KeyId CryptoKeyId `xml:"keyId"` - Success bool `xml:"success"` - Reason string `xml:"reason,omitempty"` + KeyId CryptoKeyId `xml:"keyId"` + Success bool `xml:"success"` + Reason string `xml:"reason,omitempty"` + Fault *LocalizedMethodFault `xml:"fault,omitempty"` } func init() { @@ -15207,6 +15261,25 @@ type DownloadDescriptionTreeResponse struct { Returnval []byte `xml:"returnval"` } +type DropConnections DropConnectionsRequestType + +func init() { + t["DropConnections"] = reflect.TypeOf((*DropConnections)(nil)).Elem() +} + +type DropConnectionsRequestType struct { + This ManagedObjectReference `xml:"_this"` + ListOfConnections []BaseVirtualMachineConnection `xml:"listOfConnections,omitempty,typeattr"` +} + +func init() { + t["DropConnectionsRequestType"] = reflect.TypeOf((*DropConnectionsRequestType)(nil)).Elem() +} + +type DropConnectionsResponse struct { + Returnval bool `xml:"returnval"` +} + type DrsDisabledEvent struct { ClusterEvent } @@ -18345,6 +18418,18 @@ func init() { t["FcoeFaultPnicHasNoPortSetFault"] = reflect.TypeOf((*FcoeFaultPnicHasNoPortSetFault)(nil)).Elem() } +type FeatureEVCMode struct { + ElementDescription + + Mask []HostFeatureMask `xml:"mask,omitempty"` + Capability []HostFeatureCapability `xml:"capability,omitempty"` + Requirement []VirtualMachineFeatureRequirement `xml:"requirement,omitempty"` +} + +func init() { + t["FeatureEVCMode"] = reflect.TypeOf((*FeatureEVCMode)(nil)).Elem() +} + type FeatureRequirementsNotMet struct { VirtualHardwareCompatibilityIssue @@ -22607,6 +22692,7 @@ type HostHardwareInfo struct { ReliableMemoryInfo *HostReliableMemoryInfo `xml:"reliableMemoryInfo,omitempty"` PersistentMemoryInfo *HostPersistentMemoryInfo `xml:"persistentMemoryInfo,omitempty"` SgxInfo *HostSgxInfo `xml:"sgxInfo,omitempty"` + SevInfo *HostSevInfo `xml:"sevInfo,omitempty"` } func init() { @@ -23335,19 +23421,21 @@ func init() { type HostListSummary struct { DynamicData - Host *ManagedObjectReference `xml:"host,omitempty"` - Hardware *HostHardwareSummary `xml:"hardware,omitempty"` - Runtime *HostRuntimeInfo `xml:"runtime,omitempty"` - Config HostConfigSummary `xml:"config"` - QuickStats HostListSummaryQuickStats `xml:"quickStats"` - OverallStatus ManagedEntityStatus `xml:"overallStatus"` - RebootRequired bool `xml:"rebootRequired"` - CustomValue []BaseCustomFieldValue `xml:"customValue,omitempty,typeattr"` - ManagementServerIp string `xml:"managementServerIp,omitempty"` - MaxEVCModeKey string `xml:"maxEVCModeKey,omitempty"` - CurrentEVCModeKey string `xml:"currentEVCModeKey,omitempty"` - Gateway *HostListSummaryGatewaySummary `xml:"gateway,omitempty"` - TpmAttestation *HostTpmAttestationInfo `xml:"tpmAttestation,omitempty"` + Host *ManagedObjectReference `xml:"host,omitempty"` + Hardware *HostHardwareSummary `xml:"hardware,omitempty"` + Runtime *HostRuntimeInfo `xml:"runtime,omitempty"` + Config HostConfigSummary `xml:"config"` + QuickStats HostListSummaryQuickStats `xml:"quickStats"` + OverallStatus ManagedEntityStatus `xml:"overallStatus"` + RebootRequired bool `xml:"rebootRequired"` + CustomValue []BaseCustomFieldValue `xml:"customValue,omitempty,typeattr"` + ManagementServerIp string `xml:"managementServerIp,omitempty"` + MaxEVCModeKey string `xml:"maxEVCModeKey,omitempty"` + CurrentEVCModeKey string `xml:"currentEVCModeKey,omitempty"` + CurrentEVCGraphicsModeKey string `xml:"currentEVCGraphicsModeKey,omitempty"` + Gateway *HostListSummaryGatewaySummary `xml:"gateway,omitempty"` + TpmAttestation *HostTpmAttestationInfo `xml:"tpmAttestation,omitempty"` + TrustAuthorityAttestationInfos []HostTrustAuthorityAttestationInfo `xml:"trustAuthorityAttestationInfos,omitempty"` } func init() { @@ -23885,6 +23973,7 @@ type HostNetCapabilities struct { DnsConfigSupported bool `xml:"dnsConfigSupported"` DhcpOnVnicSupported bool `xml:"dhcpOnVnicSupported"` IpV6Supported *bool `xml:"ipV6Supported"` + BackupNfcNiocSupported *bool `xml:"backupNfcNiocSupported"` } func init() { @@ -25676,6 +25765,17 @@ func init() { type HostSetVStorageObjectControlFlagsResponse struct { } +type HostSevInfo struct { + DynamicData + + SevState string `xml:"sevState"` + MaxSevEsGuests int64 `xml:"maxSevEsGuests"` +} + +func init() { + t["HostSevInfo"] = reflect.TypeOf((*HostSevInfo)(nil)).Elem() +} + type HostSgxInfo struct { DynamicData @@ -26282,6 +26382,20 @@ func init() { t["HostTpmSoftwareComponentEventDetails"] = reflect.TypeOf((*HostTpmSoftwareComponentEventDetails)(nil)).Elem() } +type HostTrustAuthorityAttestationInfo struct { + DynamicData + + AttestationStatus string `xml:"attestationStatus"` + ServiceId string `xml:"serviceId,omitempty"` + AttestedAt *time.Time `xml:"attestedAt"` + AttestedUntil *time.Time `xml:"attestedUntil"` + Messages []LocalizableMessage `xml:"messages,omitempty"` +} + +func init() { + t["HostTrustAuthorityAttestationInfo"] = reflect.TypeOf((*HostTrustAuthorityAttestationInfo)(nil)).Elem() +} + type HostUnresolvedVmfsExtent struct { DynamicData @@ -32707,7 +32821,7 @@ type NetworkSummary struct { Name string `xml:"name"` Accessible bool `xml:"accessible"` IpPoolName string `xml:"ipPoolName"` - IpPoolId int32 `xml:"ipPoolId,omitempty"` + IpPoolId *int32 `xml:"ipPoolId"` } func init() { @@ -37789,6 +37903,24 @@ type QueryConnectionInfoViaSpecResponse struct { Returnval HostConnectInfo `xml:"returnval"` } +type QueryConnections QueryConnectionsRequestType + +func init() { + t["QueryConnections"] = reflect.TypeOf((*QueryConnections)(nil)).Elem() +} + +type QueryConnectionsRequestType struct { + This ManagedObjectReference `xml:"_this"` +} + +func init() { + t["QueryConnectionsRequestType"] = reflect.TypeOf((*QueryConnectionsRequestType)(nil)).Elem() +} + +type QueryConnectionsResponse struct { + Returnval []BaseVirtualMachineConnection `xml:"returnval,omitempty,typeattr"` +} + type QueryCryptoKeyStatus QueryCryptoKeyStatusRequestType func init() { @@ -41144,6 +41276,7 @@ type RemoveInternetScsiSendTargetsRequestType struct { This ManagedObjectReference `xml:"_this"` IScsiHbaDevice string `xml:"iScsiHbaDevice"` Targets []HostInternetScsiHbaSendTarget `xml:"targets"` + Force *bool `xml:"force"` } func init() { @@ -46727,18 +46860,19 @@ func init() { type ToolsConfigInfo struct { DynamicData - ToolsVersion int32 `xml:"toolsVersion,omitempty"` - ToolsInstallType string `xml:"toolsInstallType,omitempty"` - AfterPowerOn *bool `xml:"afterPowerOn"` - AfterResume *bool `xml:"afterResume"` - BeforeGuestStandby *bool `xml:"beforeGuestStandby"` - BeforeGuestShutdown *bool `xml:"beforeGuestShutdown"` - BeforeGuestReboot *bool `xml:"beforeGuestReboot"` - ToolsUpgradePolicy string `xml:"toolsUpgradePolicy,omitempty"` - PendingCustomization string `xml:"pendingCustomization,omitempty"` - CustomizationKeyId *CryptoKeyId `xml:"customizationKeyId,omitempty"` - SyncTimeWithHost *bool `xml:"syncTimeWithHost"` - LastInstallInfo *ToolsConfigInfoToolsLastInstallInfo `xml:"lastInstallInfo,omitempty"` + ToolsVersion int32 `xml:"toolsVersion,omitempty"` + ToolsInstallType string `xml:"toolsInstallType,omitempty"` + AfterPowerOn *bool `xml:"afterPowerOn"` + AfterResume *bool `xml:"afterResume"` + BeforeGuestStandby *bool `xml:"beforeGuestStandby"` + BeforeGuestShutdown *bool `xml:"beforeGuestShutdown"` + BeforeGuestReboot *bool `xml:"beforeGuestReboot"` + ToolsUpgradePolicy string `xml:"toolsUpgradePolicy,omitempty"` + PendingCustomization string `xml:"pendingCustomization,omitempty"` + CustomizationKeyId *CryptoKeyId `xml:"customizationKeyId,omitempty"` + SyncTimeWithHostAllowed *bool `xml:"syncTimeWithHostAllowed"` + SyncTimeWithHost *bool `xml:"syncTimeWithHost"` + LastInstallInfo *ToolsConfigInfoToolsLastInstallInfo `xml:"lastInstallInfo,omitempty"` } func init() { @@ -52082,6 +52216,8 @@ type VirtualMachineCapability struct { VirtualMmuUsageIgnored *bool `xml:"virtualMmuUsageIgnored"` VirtualExecUsageIgnored *bool `xml:"virtualExecUsageIgnored"` DiskOnlySnapshotOnSuspendedVMSupported *bool `xml:"diskOnlySnapshotOnSuspendedVMSupported"` + ToolsSyncTimeAllowSupported *bool `xml:"toolsSyncTimeAllowSupported"` + SevSupported *bool `xml:"sevSupported"` } func init() { @@ -52186,6 +52322,7 @@ type VirtualMachineConfigInfo struct { SgxInfo *VirtualMachineSgxInfo `xml:"sgxInfo,omitempty"` ContentLibItemInfo *VirtualMachineContentLibraryItemInfo `xml:"contentLibItemInfo,omitempty"` GuestMonitoringModeInfo *VirtualMachineGuestMonitoringModeInfo `xml:"guestMonitoringModeInfo,omitempty"` + SevEnabled *bool `xml:"sevEnabled"` } func init() { @@ -52317,6 +52454,7 @@ type VirtualMachineConfigSpec struct { MigrateEncryption string `xml:"migrateEncryption,omitempty"` SgxInfo *VirtualMachineSgxInfo `xml:"sgxInfo,omitempty"` GuestMonitoringModeInfo *VirtualMachineGuestMonitoringModeInfo `xml:"guestMonitoringModeInfo,omitempty"` + SevEnabled *bool `xml:"sevEnabled"` } func init() { @@ -52353,6 +52491,18 @@ func init() { t["VirtualMachineConfigSummary"] = reflect.TypeOf((*VirtualMachineConfigSummary)(nil)).Elem() } +type VirtualMachineConnection struct { + DynamicData + + Label string `xml:"label"` + Client string `xml:"client"` + UserName string `xml:"userName"` +} + +func init() { + t["VirtualMachineConnection"] = reflect.TypeOf((*VirtualMachineConnection)(nil)).Elem() +} + type VirtualMachineConsolePreferences struct { DynamicData @@ -52887,6 +53037,14 @@ func init() { t["VirtualMachineMetadataManagerVmMetadataResult"] = reflect.TypeOf((*VirtualMachineMetadataManagerVmMetadataResult)(nil)).Elem() } +type VirtualMachineMksConnection struct { + VirtualMachineConnection +} + +func init() { + t["VirtualMachineMksConnection"] = reflect.TypeOf((*VirtualMachineMksConnection)(nil)).Elem() +} + type VirtualMachineMksTicket struct { DynamicData @@ -56490,6 +56648,17 @@ func init() { t["VsanClusterUuidMismatchFault"] = reflect.TypeOf((*VsanClusterUuidMismatchFault)(nil)).Elem() } +type VsanDatastoreInfo struct { + DatastoreInfo + + MembershipUuid string `xml:"membershipUuid,omitempty"` + AccessGenNo int32 `xml:"accessGenNo,omitempty"` +} + +func init() { + t["VsanDatastoreInfo"] = reflect.TypeOf((*VsanDatastoreInfo)(nil)).Elem() +} + type VsanDiskFault struct { VsanFault diff --git a/vendor/github.com/vmware/govmomi/vim25/xml/marshal.go b/vendor/github.com/vmware/govmomi/vim25/xml/marshal.go index 92c637177..c0c0a588b 100644 --- a/vendor/github.com/vmware/govmomi/vim25/xml/marshal.go +++ b/vendor/github.com/vmware/govmomi/vim25/xml/marshal.go @@ -479,8 +479,11 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat xmlname := tinfo.xmlname if xmlname.name != "" { start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name - } else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" { - start.Name = v + } else { + fv := xmlname.value(val, dontInitNilPointers) + if v, ok := fv.Interface().(Name); ok && v.Local != "" { + start.Name = v + } } } if start.Name.Local == "" && finfo != nil { @@ -505,7 +508,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat if finfo.flags&fAttr == 0 { continue } - fv := finfo.value(val) + fv := finfo.value(val, dontInitNilPointers) if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { continue @@ -814,7 +817,12 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { if finfo.flags&fAttr != 0 { continue } - vf := finfo.value(val) + vf := finfo.value(val, dontInitNilPointers) + if !vf.IsValid() { + // The field is behind an anonymous struct field that's + // nil. Skip it. + continue + } switch finfo.flags & fMode { case fCDATA, fCharData: @@ -925,7 +933,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { p.WriteString("-->") continue - case fInnerXml: + case fInnerXML: vf = indirect(vf) iface := vf.Interface() switch raw := iface.(type) { diff --git a/vendor/github.com/vmware/govmomi/vim25/xml/read.go b/vendor/github.com/vmware/govmomi/vim25/xml/read.go index 60f71582d..ea61352f6 100644 --- a/vendor/github.com/vmware/govmomi/vim25/xml/read.go +++ b/vendor/github.com/vmware/govmomi/vim25/xml/read.go @@ -491,7 +491,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { } return UnmarshalError(e) } - fv := finfo.value(sv) + fv := finfo.value(sv, initNilPointers) if _, ok := fv.Interface().(Name); ok { fv.Set(reflect.ValueOf(start.Name)) } @@ -505,7 +505,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { finfo := &tinfo.fields[i] switch finfo.flags & fMode { case fAttr: - strv := finfo.value(sv) + strv := finfo.value(sv, initNilPointers) if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) { needTypeAttr := (finfo.flags & fTypeAttr) != 0 // HACK: avoid using xsi:type value for a "type" attribute, such as ManagedObjectReference.Type for example. @@ -525,7 +525,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { } if !handled && any >= 0 { finfo := &tinfo.fields[any] - strv := finfo.value(sv) + strv := finfo.value(sv, initNilPointers) if err := d.unmarshalAttr(strv, a); err != nil { return err } @@ -538,22 +538,22 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { switch finfo.flags & fMode { case fCDATA, fCharData: if !saveData.IsValid() { - saveData = finfo.value(sv) + saveData = finfo.value(sv, initNilPointers) } case fComment: if !saveComment.IsValid() { - saveComment = finfo.value(sv) + saveComment = finfo.value(sv, initNilPointers) } case fAny, fAny | fElement: if !saveAny.IsValid() { - saveAny = finfo.value(sv) + saveAny = finfo.value(sv, initNilPointers) } - case fInnerXml: + case fInnerXML: if !saveXML.IsValid() { - saveXML = finfo.value(sv) + saveXML = finfo.value(sv, initNilPointers) if d.saved == nil { saveXMLIndex = 0 d.saved = new(bytes.Buffer) @@ -769,7 +769,7 @@ Loop: } if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { // It's a perfect match, unmarshal the field. - return true, d.unmarshal(finfo.value(sv), start) + return true, d.unmarshal(finfo.value(sv, initNilPointers), start) } if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { // It's a prefix for the field. Break and recurse diff --git a/vendor/github.com/vmware/govmomi/vim25/xml/typeinfo.go b/vendor/github.com/vmware/govmomi/vim25/xml/typeinfo.go index 0d240b1e3..5eb0b4e5f 100644 --- a/vendor/github.com/vmware/govmomi/vim25/xml/typeinfo.go +++ b/vendor/github.com/vmware/govmomi/vim25/xml/typeinfo.go @@ -33,14 +33,14 @@ const ( fAttr fCDATA fCharData - fInnerXml + fInnerXML fComment fAny fOmitEmpty fTypeAttr - fMode = fElement | fAttr | fCDATA | fCharData | fInnerXml | fComment | fAny + fMode = fElement | fAttr | fCDATA | fCharData | fInnerXML | fComment | fAny xmlName = "XMLName" ) @@ -135,7 +135,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro case "chardata": finfo.flags |= fCharData case "innerxml": - finfo.flags |= fInnerXml + finfo.flags |= fInnerXML case "comment": finfo.flags |= fComment case "any": @@ -152,7 +152,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro switch mode := finfo.flags & fMode; mode { case 0: finfo.flags |= fElement - case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny, fAny | fAttr: + case fAttr, fCDATA, fCharData, fInnerXML, fComment, fAny, fAny | fAttr: if f.Name == xmlName || tag != "" && mode != fAttr { valid = false } @@ -347,15 +347,25 @@ func (e *TagPathError) Error() string { return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2) } +const ( + initNilPointers = true + dontInitNilPointers = false +) + // value returns v's field value corresponding to finfo. -// It's equivalent to v.FieldByIndex(finfo.idx), but initializes -// and dereferences pointers as necessary. -func (finfo *fieldInfo) value(v reflect.Value) reflect.Value { +// It's equivalent to v.FieldByIndex(finfo.idx), but when passed +// initNilPointers, it initializes and dereferences pointers as necessary. +// When passed dontInitNilPointers and a nil pointer is reached, the function +// returns a zero reflect.Value. +func (finfo *fieldInfo) value(v reflect.Value, shouldInitNilPointers bool) reflect.Value { for i, x := range finfo.idx { if i > 0 { t := v.Type() if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { if v.IsNil() { + if !shouldInitNilPointers { + return reflect.Value{} + } v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() diff --git a/vendor/github.com/vmware/govmomi/vim25/xml/xml.go b/vendor/github.com/vmware/govmomi/vim25/xml/xml.go index 50117a00e..28631bdfe 100644 --- a/vendor/github.com/vmware/govmomi/vim25/xml/xml.go +++ b/vendor/github.com/vmware/govmomi/vim25/xml/xml.go @@ -290,7 +290,10 @@ func (d *Decoder) Token() (Token, error) { t = d.nextToken d.nextToken = nil } else if t, err = d.rawToken(); err != nil { - if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF { + switch { + case err == io.EOF && d.t != nil: + err = nil + case err == io.EOF && d.stk != nil && d.stk.kind != stkEOF: err = d.syntaxError("unexpected EOF") } return t, err @@ -961,7 +964,7 @@ func (d *Decoder) ungetc(b byte) { d.offset-- } -var entity = map[string]int{ +var entity = map[string]rune{ "lt": '<', "gt": '>', "amp": '&', @@ -1056,7 +1059,7 @@ Input: d.buf.WriteByte(';') n, err := strconv.ParseUint(s, base, 64) if err == nil && n <= unicode.MaxRune { - text = string(n) + text = string(rune(n)) haveText = true } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 37bc0452a..bf88192ee 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -564,6 +564,14 @@ github.com/hashicorp/packer-plugin-sdk/tmp github.com/hashicorp/packer-plugin-sdk/useragent github.com/hashicorp/packer-plugin-sdk/uuid github.com/hashicorp/packer-plugin-sdk/version +# github.com/hashicorp/packer-plugin-vsphere v0.0.0-20210409154313-881202ca3ffe +## explicit +github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/clone +github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/common +github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/driver +github.com/hashicorp/packer-plugin-vsphere/builder/vsphere/iso +github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere +github.com/hashicorp/packer-plugin-vsphere/post-processor/vsphere-template # github.com/hashicorp/serf v0.9.2 github.com/hashicorp/serf/coordinate # github.com/hashicorp/vault/api v1.0.4 @@ -789,19 +797,23 @@ github.com/ulikunitz/xz github.com/ulikunitz/xz/internal/hash github.com/ulikunitz/xz/internal/xlog github.com/ulikunitz/xz/lzma -# github.com/vmware/govmomi v0.23.1 +# github.com/vmware/govmomi v0.24.1 ## explicit github.com/vmware/govmomi github.com/vmware/govmomi/find +github.com/vmware/govmomi/internal github.com/vmware/govmomi/list github.com/vmware/govmomi/nfc github.com/vmware/govmomi/object +github.com/vmware/govmomi/ovf github.com/vmware/govmomi/property github.com/vmware/govmomi/session github.com/vmware/govmomi/session/keepalive github.com/vmware/govmomi/task github.com/vmware/govmomi/vapi/internal +github.com/vmware/govmomi/vapi/library github.com/vmware/govmomi/vapi/rest +github.com/vmware/govmomi/vapi/vcenter github.com/vmware/govmomi/vim25 github.com/vmware/govmomi/vim25/debug github.com/vmware/govmomi/vim25/methods @@ -947,7 +959,7 @@ golang.org/x/crypto/ssh/terminal # golang.org/x/lint v0.0.0-20200302205851-738671d3881b golang.org/x/lint golang.org/x/lint/golint -# golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2 +# golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 golang.org/x/mobile/event/key # golang.org/x/mod v0.3.0 ## explicit