From 99b0b9831120b895dd93580ba27b58496e26ddb4 Mon Sep 17 00:00:00 2001 From: jhawk28 Date: Thu, 19 Mar 2020 13:51:43 -0400 Subject: [PATCH] Add ovf export capability to vsphere builders (#8764) * add ovf export capability to vsphere builders * remove unneeded floppy ejection * add prepare step for export. updated output directory to be the actual destination directory * add step export documentation * add extra export options * add ui messages for export step Co-authored-by: Megan Marsh Co-authored-by: Wilken Rivera --- builder/vsphere/clone/builder.go | 11 + builder/vsphere/clone/config.go | 5 + builder/vsphere/clone/config.hcl2spec.go | 169 +++++----- builder/vsphere/common/output_config.go | 30 ++ .../vsphere/common/output_config.hcl2spec.go | 30 ++ builder/vsphere/common/step_export.go | 304 ++++++++++++++++++ .../vsphere/common/step_export.hcl2spec.go | 40 +++ builder/vsphere/driver/vm.go | 26 ++ builder/vsphere/iso/builder.go | 10 + builder/vsphere/iso/config.go | 6 + builder/vsphere/iso/config.hcl2spec.go | 223 ++++++------- vendor/github.com/vmware/govmomi/ovf/cim.go | 78 +++++ 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 | 191 +++++++++++ .../github.com/vmware/govmomi/ovf/manager.go | 103 ++++++ vendor/github.com/vmware/govmomi/ovf/ovf.go | 35 ++ vendor/modules.txt | 1 + .../docs/builders/vsphere-clone.html.md.erb | 11 + .../docs/builders/vsphere-iso.html.md.erb | 11 + .../clone/_Config-not-required.html.md | 3 +- .../common/_ExportConfig-not-required.html.md | 17 + .../vsphere/common/_ExportConfig.html.md | 21 ++ .../common/_OutputConfig-not-required.html.md | 10 + .../vsphere/iso/_Config-not-required.html.md | 3 + 25 files changed, 1268 insertions(+), 194 deletions(-) create mode 100644 builder/vsphere/common/output_config.go create mode 100644 builder/vsphere/common/output_config.hcl2spec.go create mode 100644 builder/vsphere/common/step_export.go create mode 100644 builder/vsphere/common/step_export.hcl2spec.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 website/source/partials/builder/vsphere/common/_ExportConfig-not-required.html.md create mode 100644 website/source/partials/builder/vsphere/common/_ExportConfig.html.md create mode 100644 website/source/partials/builder/vsphere/common/_OutputConfig-not-required.html.md diff --git a/builder/vsphere/clone/builder.go b/builder/vsphere/clone/builder.go index a74bb4559..10b524b86 100644 --- a/builder/vsphere/clone/builder.go +++ b/builder/vsphere/clone/builder.go @@ -82,6 +82,17 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, ) + 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 = packerCommon.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(ctx, state) diff --git a/builder/vsphere/clone/config.go b/builder/vsphere/clone/config.go index a473301be..89c5bb67f 100644 --- a/builder/vsphere/clone/config.go +++ b/builder/vsphere/clone/config.go @@ -32,6 +32,8 @@ type Config struct { // Convert VM to a template. Defaults to `false`. ConvertToTemplate bool `mapstructure:"convert_to_template"` + Export *common.ExportConfig `mapstructure:"export"` + ctx interpolate.Context } @@ -53,6 +55,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...) + if c.Export != nil { + errs = packer.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...) + } if len(errs.Errors) > 0 { return nil, errs diff --git a/builder/vsphere/clone/config.hcl2spec.go b/builder/vsphere/clone/config.hcl2spec.go index 0b6f217d3..96bbac00f 100644 --- a/builder/vsphere/clone/config.hcl2spec.go +++ b/builder/vsphere/clone/config.hcl2spec.go @@ -3,95 +3,97 @@ package clone import ( "github.com/hashicorp/hcl/v2/hcldec" + "github.com/hashicorp/packer/builder/vsphere/common" "github.com/zclconf/go-cty/cty" ) // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` - VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server"` - Username *string `mapstructure:"username" cty:"username"` - Password *string `mapstructure:"password" cty:"password"` - InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection"` - Datacenter *string `mapstructure:"datacenter" cty:"datacenter"` - Template *string `mapstructure:"template" cty:"template"` - DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"` - LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone"` - Network *string `mapstructure:"network" cty:"network"` - Notes *string `mapstructure:"notes" cty:"notes"` - VMName *string `mapstructure:"vm_name" cty:"vm_name"` - Folder *string `mapstructure:"folder" cty:"folder"` - Cluster *string `mapstructure:"cluster" cty:"cluster"` - Host *string `mapstructure:"host" cty:"host"` - ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool"` - Datastore *string `mapstructure:"datastore" cty:"datastore"` - CPUs *int32 `mapstructure:"CPUs" cty:"CPUs"` - CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores"` - CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation"` - CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit"` - CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug"` - RAM *int64 `mapstructure:"RAM" cty:"RAM"` - RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation"` - RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all"` - MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug"` - VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram"` - NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV"` - ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters"` - BootOrder *string `mapstructure:"boot_order" cty:"boot_order"` - WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout"` - SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout"` - Type *string `mapstructure:"communicator" cty:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` - Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"` - Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"` - CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"` - ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` + VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server"` + Username *string `mapstructure:"username" cty:"username"` + Password *string `mapstructure:"password" cty:"password"` + InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection"` + Datacenter *string `mapstructure:"datacenter" cty:"datacenter"` + Template *string `mapstructure:"template" cty:"template"` + DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"` + LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone"` + Network *string `mapstructure:"network" cty:"network"` + Notes *string `mapstructure:"notes" cty:"notes"` + VMName *string `mapstructure:"vm_name" cty:"vm_name"` + Folder *string `mapstructure:"folder" cty:"folder"` + Cluster *string `mapstructure:"cluster" cty:"cluster"` + Host *string `mapstructure:"host" cty:"host"` + ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool"` + Datastore *string `mapstructure:"datastore" cty:"datastore"` + CPUs *int32 `mapstructure:"CPUs" cty:"CPUs"` + CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores"` + CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation"` + CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit"` + CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug"` + RAM *int64 `mapstructure:"RAM" cty:"RAM"` + RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation"` + RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all"` + MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug"` + VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram"` + NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV"` + ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters"` + BootOrder *string `mapstructure:"boot_order" cty:"boot_order"` + WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout"` + SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout"` + Type *string `mapstructure:"communicator" cty:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` + Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"` + Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"` + CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"` + ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"` + Export *common.FlatExportConfig `mapstructure:"export" cty:"export"` } // FlatMapstructure returns a new FlatConfig. @@ -189,6 +191,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, 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())}, } return s } diff --git a/builder/vsphere/common/output_config.go b/builder/vsphere/common/output_config.go new file mode 100644 index 000000000..3a1538312 --- /dev/null +++ b/builder/vsphere/common/output_config.go @@ -0,0 +1,30 @@ +//go:generate struct-markdown +//go:generate mapstructure-to-hcl2 -type OutputConfig + +package common + +import ( + "fmt" + + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/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"` +} + +func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { + if c.OutputDir == "" { + c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName) + } + + return nil +} diff --git a/builder/vsphere/common/output_config.hcl2spec.go b/builder/vsphere/common/output_config.hcl2spec.go new file mode 100644 index 000000000..683b8f314 --- /dev/null +++ b/builder/vsphere/common/output_config.hcl2spec.go @@ -0,0 +1,30 @@ +// Code generated by "mapstructure-to-hcl2 -type OutputConfig"; DO NOT EDIT. +package common + +import ( + "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"` +} + +// 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}, + } + return s +} diff --git a/builder/vsphere/common/step_export.go b/builder/vsphere/common/step_export.go new file mode 100644 index 000000000..8fe59c7f4 --- /dev/null +++ b/builder/vsphere/common/step_export.go @@ -0,0 +1,304 @@ +//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/builder/vsphere/driver" + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/template/interpolate" + "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: +// +// ```json +// ... +// "vm_name": "example-ubuntu", +// ... +// "export": { +// "force": true, +// "output_directory": "./output_vsphere" +// }, +// ``` +// The above configuration would create the following files: +// +// ``` +// ./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"` + 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: + + // ```json + // ... + // "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 *packer.MultiError + + errs = packer.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 = packer.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 = packer.MultiErrorAppend(errs, fmt.Errorf("file already exists: %s", target)) + } + } + + if err := os.MkdirAll(c.OutputDir.OutputDir, 0750); err != nil { + errs = packer.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").(packer.Ui) + vm := state.Get("vm").(*driver.VirtualMachine) + + 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 + } + + ui.Message("Downloading: " + i.File().Path) + err = s.Download(ctx, lease, i) + if err != nil { + state.Put("error", err) + return multistep.ActionHalt + } + + ui.Message("Exporting file: " + i.File().Path) + cdp.OvfFiles = append(cdp.OvfFiles, i.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) 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) + } + + return lease.DownloadFile(ctx, path, item, opts) +} diff --git a/builder/vsphere/common/step_export.hcl2spec.go b/builder/vsphere/common/step_export.hcl2spec.go new file mode 100644 index 000000000..b250075cf --- /dev/null +++ b/builder/vsphere/common/step_export.hcl2spec.go @@ -0,0 +1,40 @@ +// Code generated by "mapstructure-to-hcl2 -type ExportConfig"; DO NOT EDIT. +package common + +import ( + "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"` + Force *bool `mapstructure:"force" cty:"force"` + Images *bool `mapstructure:"images" cty:"images"` + Manifest *string `mapstructure:"manifest" cty:"manifest"` + OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"` + Options []string `mapstructure:"options" cty:"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}, + "options": &hcldec.AttrSpec{Name: "options", Type: cty.List(cty.String), Required: false}, + } + return s +} diff --git a/builder/vsphere/driver/vm.go b/builder/vsphere/driver/vm.go index e0bafd6ed..2c1543932 100644 --- a/builder/vsphere/driver/vm.go +++ b/builder/vsphere/driver/vm.go @@ -8,6 +8,11 @@ import ( "strings" "time" + "github.com/vmware/govmomi/property" + + "github.com/vmware/govmomi/nfc" + "github.com/vmware/govmomi/ovf" + "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" @@ -688,6 +693,27 @@ func (vm *VirtualMachine) AddConfigParams(params map[string]string) error { return err } +func (vm *VirtualMachine) Export() (*nfc.Lease, error) { + return vm.vm.Export(vm.driver.ctx) +} + +func (vm *VirtualMachine) CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) { + return m.CreateDescriptor(vm.driver.ctx, vm.vm, cdp) +} + +func (vm *VirtualMachine) NewOvfManager() *ovf.Manager { + return ovf.NewManager(vm.vm.Client()) +} + +func (vm *VirtualMachine) 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 { diff --git a/builder/vsphere/iso/builder.go b/builder/vsphere/iso/builder.go index d35a9e3e3..c2b5eb298 100644 --- a/builder/vsphere/iso/builder.go +++ b/builder/vsphere/iso/builder.go @@ -132,6 +132,16 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack }, ) + 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, + }) + } + b.runner = packerCommon.NewRunner(steps, b.config.PackerConfig, ui) b.runner.Run(ctx, state) diff --git a/builder/vsphere/iso/config.go b/builder/vsphere/iso/config.go index af1a01faa..68b4913c7 100644 --- a/builder/vsphere/iso/config.go +++ b/builder/vsphere/iso/config.go @@ -39,6 +39,9 @@ type Config struct { 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"` ctx interpolate.Context } @@ -77,6 +80,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { errs = packer.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...) + if c.Export != nil { + errs = packer.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...) + } if len(errs.Errors) > 0 { return warnings, errs diff --git a/builder/vsphere/iso/config.hcl2spec.go b/builder/vsphere/iso/config.hcl2spec.go index be7a1b6b7..4cf98deef 100644 --- a/builder/vsphere/iso/config.hcl2spec.go +++ b/builder/vsphere/iso/config.hcl2spec.go @@ -3,122 +3,124 @@ package iso import ( "github.com/hashicorp/hcl/v2/hcldec" + "github.com/hashicorp/packer/builder/vsphere/common" "github.com/zclconf/go-cty/cty" ) // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max"` - VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server"` - Username *string `mapstructure:"username" cty:"username"` - Password *string `mapstructure:"password" cty:"password"` - InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection"` - Datacenter *string `mapstructure:"datacenter" cty:"datacenter"` - Version *uint `mapstructure:"vm_version" cty:"vm_version"` - GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type"` - Firmware *string `mapstructure:"firmware" cty:"firmware"` - DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type"` - DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"` - DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"` - DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub"` - Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage"` - Network *string `mapstructure:"network" cty:"network"` - NetworkCard *string `mapstructure:"network_card" cty:"network_card"` - NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters"` - USBController *bool `mapstructure:"usb_controller" cty:"usb_controller"` - Notes *string `mapstructure:"notes" cty:"notes"` - VMName *string `mapstructure:"vm_name" cty:"vm_name"` - Folder *string `mapstructure:"folder" cty:"folder"` - Cluster *string `mapstructure:"cluster" cty:"cluster"` - Host *string `mapstructure:"host" cty:"host"` - ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool"` - Datastore *string `mapstructure:"datastore" cty:"datastore"` - CPUs *int32 `mapstructure:"CPUs" cty:"CPUs"` - CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores"` - CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation"` - CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit"` - CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug"` - RAM *int64 `mapstructure:"RAM" cty:"RAM"` - RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation"` - RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all"` - MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug"` - VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram"` - NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV"` - ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters"` - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum"` - ISOChecksumURL *string `mapstructure:"iso_checksum_url" cty:"iso_checksum_url"` - ISOChecksumType *string `mapstructure:"iso_checksum_type" cty:"iso_checksum_type"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension"` - CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type"` - ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths"` - RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom"` - FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path"` - FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` - FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` - BootOrder *string `mapstructure:"boot_order" cty:"boot_order"` - BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` - BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` - HTTPIP *string `mapstructure:"http_ip" cty:"http_ip"` - WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout"` - SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout"` - Type *string `mapstructure:"communicator" cty:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` - Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"` - Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"` - CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"` - ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables"` + HTTPDir *string `mapstructure:"http_directory" cty:"http_directory"` + HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min"` + HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max"` + VCenterServer *string `mapstructure:"vcenter_server" cty:"vcenter_server"` + Username *string `mapstructure:"username" cty:"username"` + Password *string `mapstructure:"password" cty:"password"` + InsecureConnection *bool `mapstructure:"insecure_connection" cty:"insecure_connection"` + Datacenter *string `mapstructure:"datacenter" cty:"datacenter"` + Version *uint `mapstructure:"vm_version" cty:"vm_version"` + GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type"` + Firmware *string `mapstructure:"firmware" cty:"firmware"` + DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type"` + DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size"` + DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned"` + DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub"` + Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage"` + Network *string `mapstructure:"network" cty:"network"` + NetworkCard *string `mapstructure:"network_card" cty:"network_card"` + NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters"` + USBController *bool `mapstructure:"usb_controller" cty:"usb_controller"` + Notes *string `mapstructure:"notes" cty:"notes"` + VMName *string `mapstructure:"vm_name" cty:"vm_name"` + Folder *string `mapstructure:"folder" cty:"folder"` + Cluster *string `mapstructure:"cluster" cty:"cluster"` + Host *string `mapstructure:"host" cty:"host"` + ResourcePool *string `mapstructure:"resource_pool" cty:"resource_pool"` + Datastore *string `mapstructure:"datastore" cty:"datastore"` + CPUs *int32 `mapstructure:"CPUs" cty:"CPUs"` + CpuCores *int32 `mapstructure:"cpu_cores" cty:"cpu_cores"` + CPUReservation *int64 `mapstructure:"CPU_reservation" cty:"CPU_reservation"` + CPULimit *int64 `mapstructure:"CPU_limit" cty:"CPU_limit"` + CpuHotAddEnabled *bool `mapstructure:"CPU_hot_plug" cty:"CPU_hot_plug"` + RAM *int64 `mapstructure:"RAM" cty:"RAM"` + RAMReservation *int64 `mapstructure:"RAM_reservation" cty:"RAM_reservation"` + RAMReserveAll *bool `mapstructure:"RAM_reserve_all" cty:"RAM_reserve_all"` + MemoryHotAddEnabled *bool `mapstructure:"RAM_hot_plug" cty:"RAM_hot_plug"` + VideoRAM *int64 `mapstructure:"video_ram" cty:"video_ram"` + NestedHV *bool `mapstructure:"NestedHV" cty:"NestedHV"` + ConfigParams map[string]string `mapstructure:"configuration_parameters" cty:"configuration_parameters"` + ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum"` + ISOChecksumURL *string `mapstructure:"iso_checksum_url" cty:"iso_checksum_url"` + ISOChecksumType *string `mapstructure:"iso_checksum_type" cty:"iso_checksum_type"` + RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url"` + ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls"` + TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path"` + TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension"` + CdromType *string `mapstructure:"cdrom_type" cty:"cdrom_type"` + ISOPaths []string `mapstructure:"iso_paths" cty:"iso_paths"` + RemoveCdrom *bool `mapstructure:"remove_cdrom" cty:"remove_cdrom"` + FloppyIMGPath *string `mapstructure:"floppy_img_path" cty:"floppy_img_path"` + FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files"` + FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs"` + BootOrder *string `mapstructure:"boot_order" cty:"boot_order"` + BootCommand []string `mapstructure:"boot_command" cty:"boot_command"` + BootWait *string `mapstructure:"boot_wait" cty:"boot_wait"` + HTTPIP *string `mapstructure:"http_ip" cty:"http_ip"` + WaitTimeout *string `mapstructure:"ip_wait_timeout" cty:"ip_wait_timeout"` + SettleTimeout *string `mapstructure:"ip_settle_timeout" cty:"ip_settle_timeout"` + Type *string `mapstructure:"communicator" cty:"communicator"` + PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting"` + SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host"` + SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port"` + SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username"` + SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password"` + SSHKeyPairName *string `mapstructure:"ssh_keypair_name" cty:"ssh_keypair_name"` + SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" cty:"temporary_key_pair_name"` + SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys"` + SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" cty:"ssh_private_key_file"` + SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty"` + SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout"` + SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" cty:"ssh_agent_auth"` + SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding"` + SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts"` + SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host"` + SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port"` + SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth"` + SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username"` + SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password"` + SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive"` + SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file"` + SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method"` + SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host"` + SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port"` + SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username"` + SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password"` + SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval"` + SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout"` + SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels"` + SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels"` + SSHPublicKey []byte `mapstructure:"ssh_public_key" cty:"ssh_public_key"` + SSHPrivateKey []byte `mapstructure:"ssh_private_key" cty:"ssh_private_key"` + WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username"` + WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password"` + WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host"` + WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port"` + WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout"` + WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl"` + WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure"` + WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm"` + Command *string `mapstructure:"shutdown_command" cty:"shutdown_command"` + Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"` + CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"` + ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"` + Export *common.FlatExportConfig `mapstructure:"export" cty:"export"` } // FlatMapstructure returns a new FlatConfig. @@ -243,6 +245,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, 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())}, } return s } 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..ce20bde19 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/cim.go @@ -0,0 +1,78 @@ +/* +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 + +/* +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"` +} 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..d8b6fd895 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/ovf/envelope.go @@ -0,0 +1,191 @@ +/* +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 VirtualHardwareSection struct { + Section + + ID *string `xml:"id,attr"` + Transport *string `xml:"transport,attr"` + + System *VirtualSystemSettingData `xml:"System"` + Item []ResourceAllocationSettingData `xml:"Item"` +} + +type VirtualSystemSettingData struct { + CIMVirtualSystemSettingData +} + +type ResourceAllocationSettingData struct { + CIMResourceAllocationSettingData + + 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/modules.txt b/vendor/modules.txt index 24e0831cf..1f205dc22 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -572,6 +572,7 @@ github.com/vmware/govmomi/find 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/task diff --git a/website/source/docs/builders/vsphere-clone.html.md.erb b/website/source/docs/builders/vsphere-clone.html.md.erb index e7fc56cc2..23e98fe50 100644 --- a/website/source/docs/builders/vsphere-clone.html.md.erb +++ b/website/source/docs/builders/vsphere-clone.html.md.erb @@ -82,6 +82,17 @@ necessary for this build to succeed and can be found further down the page. <%= partial "partials/helper/communicator/WinRM-not-required" %> +### Export Configuration +<%= partial "partials/builder/vsphere/common/ExportConfig" %> + +### Optional: + +<%= partial "partials/builder/vsphere/common/ExportConfig-not-required" %> + +#### Output Configuration: + +<%= partial "partials/builder/vsphere/common/OutputConfig-not-required" %> + ## Working with Clusters #### Standalone Hosts Only use the `host` option. Optionally specify a `resource_pool`: diff --git a/website/source/docs/builders/vsphere-iso.html.md.erb b/website/source/docs/builders/vsphere-iso.html.md.erb index bbc339191..e1ed04208 100644 --- a/website/source/docs/builders/vsphere-iso.html.md.erb +++ b/website/source/docs/builders/vsphere-iso.html.md.erb @@ -106,6 +106,17 @@ from the datastore. Example: ### Floppy Configuration <%= partial "partials/builder/vsphere/iso/FloppyConfig-not-required" %> +### Export Configuration +<%= partial "partials/builder/vsphere/common/ExportConfig" %> + +### Optional: + +<%= partial "partials/builder/vsphere/common/ExportConfig-not-required" %> + +#### Output Configuration: + +<%= partial "partials/builder/vsphere/common/OutputConfig-not-required" %> + ### Extra Configuration Parameters <%= partial "partials/builder/vsphere/common/ConfigParamsConfig-not-required" %> diff --git a/website/source/partials/builder/vsphere/clone/_Config-not-required.html.md b/website/source/partials/builder/vsphere/clone/_Config-not-required.html.md index 479da57e2..98fbd4276 100644 --- a/website/source/partials/builder/vsphere/clone/_Config-not-required.html.md +++ b/website/source/partials/builder/vsphere/clone/_Config-not-required.html.md @@ -4,4 +4,5 @@ for linked clones. Defaults to `false`. - `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`. - \ No newline at end of file + +- `export` (\*common.ExportConfig) - Export \ No newline at end of file diff --git a/website/source/partials/builder/vsphere/common/_ExportConfig-not-required.html.md b/website/source/partials/builder/vsphere/common/_ExportConfig-not-required.html.md new file mode 100644 index 000000000..0f811bff4 --- /dev/null +++ b/website/source/partials/builder/vsphere/common/_ExportConfig-not-required.html.md @@ -0,0 +1,17 @@ + + +- `name` (string) - name of the ovf. defaults to the name of the VM + +- `force` (bool) - overwrite ovf if it exists + +- `images` (bool) - include iso and img image files that are attached to the VM + +- `manifest` (string) - generate manifest using sha1, sha256, sha512. Defaults to 'sha256'. Use 'none' for no manifest. + +- `options` ([]string) - ```json + ... + "export": { + "options": ["mac"] + }, + ``` + \ No newline at end of file diff --git a/website/source/partials/builder/vsphere/common/_ExportConfig.html.md b/website/source/partials/builder/vsphere/common/_ExportConfig.html.md new file mode 100644 index 000000000..26276b06a --- /dev/null +++ b/website/source/partials/builder/vsphere/common/_ExportConfig.html.md @@ -0,0 +1,21 @@ + +You may optionally export an ovf from VSphere to the instance running Packer. + +Example usage: + +```json +... + "vm_name": "example-ubuntu", +... + "export": { + "force": true, + "output_directory": "./output_vsphere" + }, +``` +The above configuration would create the following files: + +``` +./output_vsphere/example-ubuntu-disk-0.vmdk +./output_vsphere/example-ubuntu.mf +./output_vsphere/example-ubuntu.ovf +``` diff --git a/website/source/partials/builder/vsphere/common/_OutputConfig-not-required.html.md b/website/source/partials/builder/vsphere/common/_OutputConfig-not-required.html.md new file mode 100644 index 000000000..738898ba8 --- /dev/null +++ b/website/source/partials/builder/vsphere/common/_OutputConfig-not-required.html.md @@ -0,0 +1,10 @@ + + +- `output_directory` (string) - This setting specifies the directory that + artifacts from the build, such as the virtual machine files and disks, + will be output to. The path to the directory may be relative or + absolute. If relative, the path is relative to the working directory + packer is executed from. This directory must not exist or, if + created, must be empty prior to running the builder. By default this is + "output-BUILDNAME" where "BUILDNAME" is the name of the build. + \ No newline at end of file diff --git a/website/source/partials/builder/vsphere/iso/_Config-not-required.html.md b/website/source/partials/builder/vsphere/iso/_Config-not-required.html.md index a51e32583..c7f6b7fc1 100644 --- a/website/source/partials/builder/vsphere/iso/_Config-not-required.html.md +++ b/website/source/partials/builder/vsphere/iso/_Config-not-required.html.md @@ -4,4 +4,7 @@ for linked clones. Defaults to `false`. - `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`. + +- `export` (\*common.ExportConfig) - Configuration for exporting VM to an ovf file. + The VM will not be exported if no [Export Configuration](#export-configuration) is specified. \ No newline at end of file