diff --git a/builder/vmware/common/output_config.go b/builder/vmware/common/output_config.go index e99919dcb..5cc859a64 100644 --- a/builder/vmware/common/output_config.go +++ b/builder/vmware/common/output_config.go @@ -10,13 +10,39 @@ import ( ) type OutputConfig struct { - // This is the path to the directory where the - // resulting virtual machine will be created. This may be relative or absolute. - // If relative, the path is relative to the working directory when packer - // is executed. This directory must not exist or be empty prior to running - // the builder. By default this is output-BUILDNAME where "BUILDNAME" is the - // name of the build. + // This is the path on your local machine (the one running Packer) to the + // directory where the resulting virtual machine will be created. + // This may be relative or absolute. If relative, the path is relative to + // the working directory when packer is executed. + // + // If you are running a remote esx build, the output_dir is the path on your + // local machine (the machine running Packer) to which Packer will export + // the vm if you have `"skip_export": false`. If you want to manage the + // virtual machine's path on the remote datastore, use `remote_output_dir`. + // + // This directory must not exist or 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"` + // This is the directoy on your remote esx host where you will save your + // vm, relative to your remote_datastore. + // + // This option's default value is your `vm_name`, and the final path of your + // vm will be vmfs/volumes/$remote_datastore/$vm_name/$vm_name.vmx where + // `$remote_datastore` and `$vm_name` match their corresponding template + // options + // + // For example, setting `"remote_output_directory": "path/to/subdir` + // will create a directory `/vmfs/volumes/remote_datastore/path/to/subdir`. + // + // Packer will not create the remote datastore for you; it must already + // exist. However, Packer will create all directories defined in the option + // that do not currently exist. + // + // This option will be ignored unless you are building on a remote esx host. + RemoteOutputDir string `mapstructure:"remote_output_directory" required:"false"` } func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { diff --git a/builder/vmware/iso/builder.go b/builder/vmware/iso/builder.go index 0a492246d..dc9962f59 100644 --- a/builder/vmware/iso/builder.go +++ b/builder/vmware/iso/builder.go @@ -36,22 +36,37 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack return nil, fmt.Errorf("Failed creating VMware driver: %s", err) } - // Determine the output dir implementation + // Hold on to your pants. The output configuration is a little complex + // because of all the moving parts between local and remote output, and + // exports, and legacy behavior. var dir vmwcommon.OutputDir switch d := driver.(type) { case vmwcommon.OutputDir: + // Remote type is esx; the driver fulfils the OutputDir interface so + // that it can create output files on the remote instance. dir = d default: + // Remote type is ""; the driver will be running the build and creating + // the output directory locally dir = new(vmwcommon.LocalOutputDir) } - // The OutputDir will track remote esxi output; exportOutputPath preserves - // the path to the output on the machine running Packer. + // If remote type is esx, we need to track both the output dir on the remote + // instance and the output dir locally. This is where we track the local + // output dir. exportOutputPath := b.config.OutputDir if b.config.RemoteType != "" { - b.config.OutputDir = b.config.VMName + if b.config.RemoteOutputDir != "" { + b.config.OutputDir = b.config.RemoteOutputDir + } else { + // Default output dir to vm name. On remote esx instance, this will + // become something like /vmfs/volumes/mydatastore/vmname/vmname.vmx + b.config.OutputDir = b.config.VMName + } } + // Remember, this one's either the output from a local build, or the remote + // output from a remote build. Not the local export path for a remote build. dir.SetOutputDir(b.config.OutputDir) // Setup the state bag diff --git a/builder/vmware/iso/config.hcl2spec.go b/builder/vmware/iso/config.hcl2spec.go index bfb5a1b26..394aa9da0 100644 --- a/builder/vmware/iso/config.hcl2spec.go +++ b/builder/vmware/iso/config.hcl2spec.go @@ -56,6 +56,7 @@ type FlatConfig struct { Serial *string `mapstructure:"serial" required:"false" cty:"serial" hcl:"serial"` Parallel *string `mapstructure:"parallel" required:"false" cty:"parallel" hcl:"parallel"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` + RemoteOutputDir *string `mapstructure:"remote_output_directory" required:"false" cty:"remote_output_directory" hcl:"remote_output_directory"` Headless *bool `mapstructure:"headless" required:"false" cty:"headless" hcl:"headless"` VNCBindAddress *string `mapstructure:"vnc_bind_address" required:"false" cty:"vnc_bind_address" hcl:"vnc_bind_address"` VNCPortMin *int `mapstructure:"vnc_port_min" required:"false" cty:"vnc_port_min" hcl:"vnc_port_min"` @@ -194,6 +195,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "serial": &hcldec.AttrSpec{Name: "serial", Type: cty.String, Required: false}, "parallel": &hcldec.AttrSpec{Name: "parallel", Type: cty.String, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, + "remote_output_directory": &hcldec.AttrSpec{Name: "remote_output_directory", Type: cty.String, Required: false}, "headless": &hcldec.AttrSpec{Name: "headless", Type: cty.Bool, Required: false}, "vnc_bind_address": &hcldec.AttrSpec{Name: "vnc_bind_address", Type: cty.String, Required: false}, "vnc_port_min": &hcldec.AttrSpec{Name: "vnc_port_min", Type: cty.Number, Required: false}, diff --git a/builder/vmware/vmx/config.hcl2spec.go b/builder/vmware/vmx/config.hcl2spec.go index 6544a0081..2b817b80f 100644 --- a/builder/vmware/vmx/config.hcl2spec.go +++ b/builder/vmware/vmx/config.hcl2spec.go @@ -41,6 +41,7 @@ type FlatConfig struct { RemotePrivateKey *string `mapstructure:"remote_private_key_file" required:"false" cty:"remote_private_key_file" hcl:"remote_private_key_file"` SkipValidateCredentials *bool `mapstructure:"skip_validate_credentials" required:"false" cty:"skip_validate_credentials" hcl:"skip_validate_credentials"` OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` + RemoteOutputDir *string `mapstructure:"remote_output_directory" required:"false" cty:"remote_output_directory" hcl:"remote_output_directory"` Headless *bool `mapstructure:"headless" required:"false" cty:"headless" hcl:"headless"` VNCBindAddress *string `mapstructure:"vnc_bind_address" required:"false" cty:"vnc_bind_address" hcl:"vnc_bind_address"` VNCPortMin *int `mapstructure:"vnc_port_min" required:"false" cty:"vnc_port_min" hcl:"vnc_port_min"` @@ -156,6 +157,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "remote_private_key_file": &hcldec.AttrSpec{Name: "remote_private_key_file", Type: cty.String, Required: false}, "skip_validate_credentials": &hcldec.AttrSpec{Name: "skip_validate_credentials", Type: cty.Bool, Required: false}, "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, + "remote_output_directory": &hcldec.AttrSpec{Name: "remote_output_directory", Type: cty.String, Required: false}, "headless": &hcldec.AttrSpec{Name: "headless", Type: cty.Bool, Required: false}, "vnc_bind_address": &hcldec.AttrSpec{Name: "vnc_bind_address", Type: cty.String, Required: false}, "vnc_port_min": &hcldec.AttrSpec{Name: "vnc_port_min", Type: cty.Number, Required: false}, diff --git a/website/pages/partials/builder/vmware/common/OutputConfig-not-required.mdx b/website/pages/partials/builder/vmware/common/OutputConfig-not-required.mdx index 6487377d5..8ad2776dc 100644 --- a/website/pages/partials/builder/vmware/common/OutputConfig-not-required.mdx +++ b/website/pages/partials/builder/vmware/common/OutputConfig-not-required.mdx @@ -1,8 +1,34 @@ -- `output_directory` (string) - This is the path to the directory where the - resulting virtual machine will be created. This may be relative or absolute. - If relative, the path is relative to the working directory when packer - is executed. This directory must not exist or be empty prior to running - the builder. By default this is output-BUILDNAME where "BUILDNAME" is the - name of the build. +- `output_directory` (string) - This is the path on your local machine (the one running Packer) to the + directory where the resulting virtual machine will be created. + This may be relative or absolute. If relative, the path is relative to + the working directory when packer is executed. + + If you are running a remote esx build, the output_dir is the path on your + local machine (the machine running Packer) to which Packer will export + the vm if you have `"skip_export": false`. If you want to manage the + virtual machine's path on the remote datastore, use `remote_output_dir`. + + This directory must not exist or be empty prior to running + the builder. + + By default this is output-BUILDNAME where "BUILDNAME" is the name of the + build. + +- `remote_output_directory` (string) - This is the directoy on your remote esx host where you will save your + vm, relative to your remote_datastore. + + This option's default value is your `vm_name`, and the final path of your + vm will be vmfs/volumes/$remote_datastore/$vm_name/$vm_name.vmx where + `$remote_datastore` and `$vm_name` match their corresponding template + options + + For example, setting `"remote_output_directory": "path/to/subdir` + will create a directory `/vmfs/volumes/remote_datastore/path/to/subdir`. + + Packer will not create the remote datastore for you; it must already + exist. However, Packer will create all directories defined in the option + that do not currently exist. + + This option will be ignored unless you are building on a remote esx host.