diff --git a/post-processor/vsphere/post-processor.go b/post-processor/vsphere/post-processor.go index 2d7c4c084..7b45c6a9e 100644 --- a/post-processor/vsphere/post-processor.go +++ b/post-processor/vsphere/post-processor.go @@ -115,19 +115,7 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { return nil } -func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { - source := "" - for _, path := range artifact.Files() { - if strings.HasSuffix(path, ".vmx") || strings.HasSuffix(path, ".ovf") || strings.HasSuffix(path, ".ova") { - source = path - break - } - } - - if source == "" { - return nil, false, false, fmt.Errorf("VMX, OVF or OVA file not found") - } - +func (p *PostProcessor) generateURI() string { password := escapeWithSpaces(p.config.Password) ovftool_uri := fmt.Sprintf("vi://%s:%s@%s/%s/host/%s", escapeWithSpaces(p.config.Username), @@ -147,6 +135,23 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact ovftool_uri += "/?dns=" + p.config.ESXiHost } } + return ovftool_uri +} + +func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) { + source := "" + for _, path := range artifact.Files() { + if strings.HasSuffix(path, ".vmx") || strings.HasSuffix(path, ".ovf") || strings.HasSuffix(path, ".ova") { + source = path + break + } + } + + if source == "" { + return nil, false, false, fmt.Errorf("VMX, OVF or OVA file not found") + } + + ovftool_uri := p.generateURI() args, err := p.BuildArgs(source, ovftool_uri) if err != nil { @@ -156,11 +161,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact ui.Message(fmt.Sprintf("Uploading %s to vSphere", source)) log.Printf("Starting ovftool with parameters: %s", - strings.Replace( - strings.Join(args, " "), - password, - "", - -1)) + p.filterLog(strings.Join(args, " "))) var errWriter io.Writer var errOut bytes.Buffer diff --git a/post-processor/vsphere/post-processor_test.go b/post-processor/vsphere/post-processor_test.go index 65b99f9a7..7b9351ec6 100644 --- a/post-processor/vsphere/post-processor_test.go +++ b/post-processor/vsphere/post-processor_test.go @@ -7,19 +7,25 @@ import ( "testing" ) +func getTestConfig() Config { + return Config{ + Username: "me", + Password: "notpassword", + Host: "myhost", + Datacenter: "mydc", + Cluster: "mycluster", + VMName: "my vm", + Datastore: "my datastore", + Insecure: true, + DiskMode: "thin", + VMFolder: "my folder", + } +} + func TestArgs(t *testing.T) { var p PostProcessor - p.config.Username = "me" - p.config.Password = "notpassword" - p.config.Host = "myhost" - p.config.Datacenter = "mydc" - p.config.Cluster = "mycluster" - p.config.VMName = "my vm" - p.config.Datastore = "my datastore" - p.config.Insecure = true - p.config.DiskMode = "thin" - p.config.VMFolder = "my folder" + p.config = getTestConfig() source := "something.vmx" ovftool_uri := fmt.Sprintf("vi://%s:%s@%s/%s/host/%s", @@ -41,6 +47,55 @@ func TestArgs(t *testing.T) { t.Logf("ovftool %s", strings.Join(args, " ")) } +func TestGenerateURI_Basic(t *testing.T) { + var p PostProcessor + + p.config = getTestConfig() + + uri := p.generateURI() + expected_uri := "vi://me:notpassword@myhost/mydc/host/mycluster" + if uri != expected_uri { + t.Fatalf("URI did not match. Recieved: %s. Expected: %s", uri, expected_uri) + } +} + +func TestGenerateURI_PasswordEscapes(t *testing.T) { + type escapeCases struct { + Input string + Expected string + } + + cases := []escapeCases{ + {`this has spaces`, `this%20has%20spaces`}, + {`exclaimation_!`, `exclaimation_%21`}, + {`hash_#_dollar_$`, `hash_%23_dollar_%24`}, + {`ampersand_&awesome`, `ampersand_%26awesome`}, + {`single_quote_'_and_another_'`, `single_quote_%27_and_another_%27`}, + {`open_paren_(_close_paren_)`, `open_paren_%28_close_paren_%29`}, + {`asterisk_*_plus_+`, `asterisk_%2A_plus_%2B`}, + {`comma_,slash_/`, `comma_%2Cslash_%2F`}, + {`colon_:semicolon_;`, `colon_%3Asemicolon_%3B`}, + {`equal_=question_?`, `equal_%3Dquestion_%3F`}, + {`at_@`, `at_%40`}, + {`open_bracket_[closed_bracket]`, `open_bracket_%5Bclosed_bracket%5D`}, + {`user:password with $paces@host/name.foo`, `user%3Apassword%20with%20%24paces%40host%2Fname.foo`}, + } + + for _, escapeCase := range cases { + var p PostProcessor + + p.config = getTestConfig() + p.config.Password = escapeCase.Input + + uri := p.generateURI() + expected_uri := fmt.Sprintf("vi://me:%s@myhost/mydc/host/mycluster", escapeCase.Expected) + + if uri != expected_uri { + t.Fatalf("URI did not match. Recieved: %s. Expected: %s", uri, expected_uri) + } + } +} + func TestEscaping(t *testing.T) { type escapeCases struct { Input string