Merge pull request #9983 from hashicorp/tools_upload_path

allow user to set tools upload path
This commit is contained in:
Megan Marsh 2020-09-24 10:41:08 -07:00 committed by GitHub
commit 108455a7dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 155 additions and 3 deletions

View File

@ -11,6 +11,7 @@ import (
type StepPrepareTools struct {
RemoteType string
ToolsUploadFlavor string
ToolsSourcePath string
}
func (c *StepPrepareTools) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
@ -20,11 +21,15 @@ func (c *StepPrepareTools) Run(ctx context.Context, state multistep.StateBag) mu
return multistep.ActionContinue
}
if c.ToolsUploadFlavor == "" {
if c.ToolsUploadFlavor == "" && c.ToolsSourcePath == "" {
return multistep.ActionContinue
}
path := driver.ToolsIsoPath(c.ToolsUploadFlavor)
path := c.ToolsSourcePath
if path == "" {
path = driver.ToolsIsoPath(c.ToolsUploadFlavor)
}
if _, err := os.Stat(path); err != nil {
state.Put("error", fmt.Errorf(
"Couldn't find VMware tools for '%s'! VMware often downloads these\n"+

View File

@ -114,3 +114,65 @@ func TestStepPrepareTools_nonExist(t *testing.T) {
t.Fatal("should NOT have tools_upload_source")
}
}
func TestStepPrepareTools_SourcePath(t *testing.T) {
state := testState(t)
step := &StepPrepareTools{
RemoteType: "",
ToolsSourcePath: "/path/to/tool.iso",
}
driver := state.Get("driver").(*DriverMock)
// Mock results
driver.ToolsIsoPathResult = "foo"
// Test the run
if action := step.Run(context.Background(), state); action != multistep.ActionHalt {
t.Fatalf("Should have failed when stat failed %#v", action)
}
if _, ok := state.GetOk("error"); !ok {
t.Fatal("should have error")
}
// Test the driver
if driver.ToolsIsoPathCalled {
t.Fatal("tools iso path should not be called when ToolsSourcePath is set")
}
// Test the resulting state
if _, ok := state.GetOk("tools_upload_source"); ok {
t.Fatal("should NOT have tools_upload_source")
}
}
func TestStepPrepareTools_SourcePath_exists(t *testing.T) {
state := testState(t)
step := &StepPrepareTools{
RemoteType: "",
ToolsSourcePath: "./step_prepare_tools.go",
}
driver := state.Get("driver").(*DriverMock)
// Mock results
driver.ToolsIsoPathResult = "foo"
// Test the run
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("Step should succeed when stat succeeds: %#v", action)
}
if _, ok := state.GetOk("error"); ok {
t.Fatal("should NOT have error")
}
// Test the driver
if driver.ToolsIsoPathCalled {
t.Fatal("tools iso path should not be called when ToolsSourcePath is set")
}
// Test the resulting state
if _, ok := state.GetOk("tools_upload_source"); !ok {
t.Fatal("should have tools_upload_source")
}
}

View File

@ -3,6 +3,8 @@
package common
import (
"fmt"
"github.com/hashicorp/packer/template/interpolate"
)
@ -18,12 +20,22 @@ type ToolsConfig struct {
// the upload path is set to `{{.Flavor}}.iso`. This setting is not used
// when `remote_type` is `esx5`.
ToolsUploadPath string `mapstructure:"tools_upload_path" required:"false"`
// The path on your local machine to fetch the vmware tools from. If this
// is not set but the tools_upload_flavor is set, then Packer will try to
// load the VMWare tools from the VMWare installation directory.
ToolsSourcePath string `mapstructure:"tools_source_path" required:"false"`
}
func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []error {
errs := []error{}
if c.ToolsUploadPath == "" {
if c.ToolsSourcePath != "" && c.ToolsUploadFlavor == "" {
errs = append(errs, fmt.Errorf("If you provide a "+
"tools_source_path, you must also provide either a "+
"tools_upload_flavor or a tools_upload_path."))
}
c.ToolsUploadPath = "{{ .Flavor }}.iso"
}
return nil
return errs
}

View File

@ -0,0 +1,65 @@
package common
import (
"testing"
"github.com/hashicorp/packer/template/interpolate"
)
func TestToolsConfigPrepare_Empty(t *testing.T) {
c := &ToolsConfig{}
errs := c.Prepare(interpolate.NewContext())
if len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if c.ToolsUploadPath != "{{ .Flavor }}.iso" {
t.Fatal("should have defaulted tools upload path")
}
}
func TestToolsConfigPrepare_SetUploadPath(t *testing.T) {
c := &ToolsConfig{
ToolsUploadPath: "path/to/tools.iso",
}
errs := c.Prepare(interpolate.NewContext())
if len(errs) > 0 {
t.Fatalf("err: %#v", errs)
}
if c.ToolsUploadPath != "path/to/tools.iso" {
t.Fatal("should have used given tools upload path")
}
}
func TestToolsConfigPrepare_ErrorIfOnlySource(t *testing.T) {
c := &ToolsConfig{
ToolsSourcePath: "path/to/tools.iso",
}
errs := c.Prepare(interpolate.NewContext())
if len(errs) != 1 {
t.Fatalf("Should have received an error because the flavor and " +
"upload path aren't set")
}
}
func TestToolsConfigPrepare_SourceSuccess(t *testing.T) {
for _, c := range []*ToolsConfig{
&ToolsConfig{
ToolsSourcePath: "path/to/tools.iso",
ToolsUploadPath: "partypath.iso",
},
&ToolsConfig{
ToolsSourcePath: "path/to/tools.iso",
ToolsUploadFlavor: "linux",
},
} {
errs := c.Prepare(interpolate.NewContext())
if len(errs) != 0 {
t.Fatalf("Should not have received an error")
}
}
}

View File

@ -119,6 +119,7 @@ type FlatConfig struct {
SSHSkipRequestPty *bool `mapstructure:"ssh_skip_request_pty" cty:"ssh_skip_request_pty" hcl:"ssh_skip_request_pty"`
ToolsUploadFlavor *string `mapstructure:"tools_upload_flavor" required:"false" cty:"tools_upload_flavor" hcl:"tools_upload_flavor"`
ToolsUploadPath *string `mapstructure:"tools_upload_path" required:"false" cty:"tools_upload_path" hcl:"tools_upload_path"`
ToolsSourcePath *string `mapstructure:"tools_source_path" required:"false" cty:"tools_source_path" hcl:"tools_source_path"`
VMXData map[string]string `mapstructure:"vmx_data" required:"false" cty:"vmx_data" hcl:"vmx_data"`
VMXDataPost map[string]string `mapstructure:"vmx_data_post" required:"false" cty:"vmx_data_post" hcl:"vmx_data_post"`
VMXRemoveEthernet *bool `mapstructure:"vmx_remove_ethernet_interfaces" required:"false" cty:"vmx_remove_ethernet_interfaces" hcl:"vmx_remove_ethernet_interfaces"`
@ -263,6 +264,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ssh_skip_request_pty": &hcldec.AttrSpec{Name: "ssh_skip_request_pty", Type: cty.Bool, Required: false},
"tools_upload_flavor": &hcldec.AttrSpec{Name: "tools_upload_flavor", Type: cty.String, Required: false},
"tools_upload_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
"tools_source_path": &hcldec.AttrSpec{Name: "tools_source_path", Type: cty.String, Required: false},
"vmx_data": &hcldec.AttrSpec{Name: "vmx_data", Type: cty.Map(cty.String), Required: false},
"vmx_data_post": &hcldec.AttrSpec{Name: "vmx_data_post", Type: cty.Map(cty.String), Required: false},
"vmx_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},

View File

@ -104,6 +104,7 @@ type FlatConfig struct {
SSHSkipRequestPty *bool `mapstructure:"ssh_skip_request_pty" cty:"ssh_skip_request_pty" hcl:"ssh_skip_request_pty"`
ToolsUploadFlavor *string `mapstructure:"tools_upload_flavor" required:"false" cty:"tools_upload_flavor" hcl:"tools_upload_flavor"`
ToolsUploadPath *string `mapstructure:"tools_upload_path" required:"false" cty:"tools_upload_path" hcl:"tools_upload_path"`
ToolsSourcePath *string `mapstructure:"tools_source_path" required:"false" cty:"tools_source_path" hcl:"tools_source_path"`
VMXData map[string]string `mapstructure:"vmx_data" required:"false" cty:"vmx_data" hcl:"vmx_data"`
VMXDataPost map[string]string `mapstructure:"vmx_data_post" required:"false" cty:"vmx_data_post" hcl:"vmx_data_post"`
VMXRemoveEthernet *bool `mapstructure:"vmx_remove_ethernet_interfaces" required:"false" cty:"vmx_remove_ethernet_interfaces" hcl:"vmx_remove_ethernet_interfaces"`
@ -229,6 +230,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"ssh_skip_request_pty": &hcldec.AttrSpec{Name: "ssh_skip_request_pty", Type: cty.Bool, Required: false},
"tools_upload_flavor": &hcldec.AttrSpec{Name: "tools_upload_flavor", Type: cty.String, Required: false},
"tools_upload_path": &hcldec.AttrSpec{Name: "tools_upload_path", Type: cty.String, Required: false},
"tools_source_path": &hcldec.AttrSpec{Name: "tools_source_path", Type: cty.String, Required: false},
"vmx_data": &hcldec.AttrSpec{Name: "vmx_data", Type: cty.Map(cty.String), Required: false},
"vmx_data_post": &hcldec.AttrSpec{Name: "vmx_data_post", Type: cty.Map(cty.String), Required: false},
"vmx_remove_ethernet_interfaces": &hcldec.AttrSpec{Name: "vmx_remove_ethernet_interfaces", Type: cty.Bool, Required: false},

View File

@ -10,3 +10,7 @@
`Flavor`, which will be the value of `tools_upload_flavor`. By default
the upload path is set to `{{.Flavor}}.iso`. This setting is not used
when `remote_type` is `esx5`.
- `tools_source_path` (string) - The path on your local machine to fetch the vmware tools from. If this
is not set but the tools_upload_flavor is set, then Packer will try to
load the VMWare tools from the VMWare installation directory.