Skip to content

Commit

Permalink
feat: upload max retries (#379)
Browse files Browse the repository at this point in the history
- Updates the `vsphere` post-processor to support `max_retries` for the upload to a vSphere endpoint. Defaults to 5.
- Sets and uses constants for `DefaultMaxRetries`, `DefaultDiskMode`,
 and `OvftoolWindows`.

Ref: #30

Signed-off-by: Ryan Johnson <[email protected]>
  • Loading branch information
Ryan Johnson authored Apr 3, 2024
1 parent 310be57 commit 0a8ddcd
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 16 deletions.
3 changes: 3 additions & 0 deletions .web-docs/components/post-processor/vsphere/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ Optional:
See [VMware KB 1003746](https://kb.vmware.com/s/article/1003746) for more information on the
virtual hardware versions supported.

- `max_retries` (int) - Specifies the maximum number of times to retry the upload operation if it fails.
Defaults to `5`.

<!-- End of code generated from the comments of the Config struct in post-processor/vsphere/post-processor.go; -->


Expand Down
3 changes: 3 additions & 0 deletions docs-partials/post-processor/vsphere/Config-not-required.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@
See [VMware KB 1003746](https://kb.vmware.com/s/article/1003746) for more information on the
virtual hardware versions supported.

- `max_retries` (int) - Specifies the maximum number of times to retry the upload operation if it fails.
Defaults to `5`.

<!-- End of code generated from the comments of the Config struct in post-processor/vsphere/post-processor.go; -->
53 changes: 37 additions & 16 deletions post-processor/vsphere/post-processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer-plugin-sdk/common"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/retry"
shelllocal "github.com/hashicorp/packer-plugin-sdk/shell-local"
"github.com/hashicorp/packer-plugin-sdk/template/config"
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
)

const DefaultMaxRetries = 5
const DefaultDiskMode = "thick"
const OvftoolWindows = "ovftool.exe"

var ovftool string = "ovftool"

var (
Expand Down Expand Up @@ -94,6 +99,9 @@ type Config struct {
// See [VMware KB 1003746](https://kb.vmware.com/s/article/1003746) for more information on the
// virtual hardware versions supported.
HardwareVersion string `mapstructure:"hardware_version"`
// Specifies the maximum number of times to retry the upload operation if it fails.
// Defaults to `5`.
MaxRetries int `mapstructure:"max_retries"`

ctx interpolate.Context
}
Expand All @@ -117,16 +125,21 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
return err
}

// Set default value for MaxRetries if not provided.
if p.config.MaxRetries == 0 {
p.config.MaxRetries = DefaultMaxRetries // Set default value
}

// Defaults
if p.config.DiskMode == "" {
p.config.DiskMode = "thick"
p.config.DiskMode = DefaultDiskMode
}

// Accumulate any errors
errs := new(packersdk.MultiError)

if runtime.GOOS == "windows" {
ovftool = "ovftool.exe"
ovftool = OvftoolWindows
}

if _, err := exec.LookPath(ovftool); err != nil {
Expand Down Expand Up @@ -171,7 +184,7 @@ func (p *PostProcessor) generateURI() (*url.URL, error) {

u, err := url.Parse(ovftool_uri)
if err != nil {
return nil, fmt.Errorf("Couldn't generate uri for ovftool: %s", err)
return nil, fmt.Errorf("error generating uri for ovftool: %s", err)
}
u.User = url.UserPassword(p.config.Username, p.config.Password)

Expand Down Expand Up @@ -207,7 +220,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
}

if source == "" {
return nil, false, false, fmt.Errorf("VMX, OVF or OVA file not found")
return nil, false, false, fmt.Errorf("error locating expected .vmx, .ovf, or .ova artifact")
}

ovftool_uri, err := p.generateURI()
Expand All @@ -224,31 +237,39 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
ui.Message(fmt.Sprintf("Failed: %s\n", err))
}

ui.Message(fmt.Sprintf("Uploading %s to vSphere", source))
ui.Message(fmt.Sprintf("Uploading %s to vSphere...", source))

log.Printf("Starting ovftool with parameters: %s", strings.Join(args, " "))

ui.Message("Validating Username and Password with dry-run")
ui.Message("Validating username and password with dry-run...")
err = p.ValidateOvfTool(args, ovftool)
if err != nil {
return nil, false, false, err
}

// Validation has passed, so run for real.
ui.Message("Calling OVFtool to upload vm")
ui.Message("Uploading virtual machine using OVFtool...")
commandAndArgs := []string{ovftool}
commandAndArgs = append(commandAndArgs, args...)
comm := &shelllocal.Communicator{
ExecuteCommand: commandAndArgs,
}
flattenedCmd := strings.Join(commandAndArgs, " ")
cmd := &packersdk.RemoteCmd{Command: flattenedCmd}
log.Printf("[INFO] (vsphere): starting ovftool command: %s", flattenedCmd)
err = cmd.RunWithUi(ctx, comm, ui)
if err != nil || cmd.ExitStatus() != 0 {
return nil, false, false, fmt.Errorf(
"Error uploading virtual machine: Please see output above for more information.")
}
err = retry.Config{
Tries: p.config.MaxRetries,
ShouldRetry: func(err error) bool {
return err != nil
},
RetryDelay: (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 30 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
cmd := &packersdk.RemoteCmd{Command: flattenedCmd}
log.Printf("Starting OVFtool command: %s", flattenedCmd)
err = cmd.RunWithUi(ctx, comm, ui)
if err != nil || cmd.ExitStatus() != 0 {
return fmt.Errorf("error uploading virtual machine")
}
return nil
})

artifact = NewArtifact(p.config.Datastore, p.config.VMFolder, p.config.VMName, artifact.Files())

Expand All @@ -275,8 +296,8 @@ func (p *PostProcessor) ValidateOvfTool(args []string, ofvtool string) error {
if err := cmd.Run(); err != nil {
outString := out.String()
if strings.Contains(outString, "Enter login information for") {
err = fmt.Errorf("Error performing OVFtool dry run; the username " +
"or password you provided to ovftool is likely invalid.")
err = fmt.Errorf("error performing ovftool dry run; the username " +
"or password you provided may be incorrect")
return err
}
return nil
Expand Down
2 changes: 2 additions & 0 deletions post-processor/vsphere/post-processor.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0a8ddcd

Please sign in to comment.