Skip to content

Commit

Permalink
feat: check ovftool version
Browse files Browse the repository at this point in the history
Checks the minimum recommended version of VMware Open Virtualization Format Tool ('ovftool').

Ref: #135

Signed-off-by: Ryan Johnson <ryan.johnson@broadcom.com>
  • Loading branch information
tenthirtyam committed Jul 26, 2024
1 parent 4c6726a commit 939a252
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 12 deletions.
12 changes: 12 additions & 0 deletions .web-docs/components/builder/iso/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,18 @@ provisioner](/packer/docs/provisioner/file).
<!-- End of code generated from the comments of the ExportConfig struct in builder/vmware/common/export_config.go; -->


HCL Example:

```hcl
source "vmware-iso" "example" {
# ... omitted for brevity ...
format = "ova"
ovftool_options = ["--compress=9", "--makeDeltaDisks"]
skip_export = false
keep_registered = false
skip_compaction = true
```

### Communicator configuration

#### Optional common fields:
Expand Down
10 changes: 10 additions & 0 deletions .web-docs/components/builder/vmx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,16 @@ boot time.
<!-- End of code generated from the comments of the ExportConfig struct in builder/vmware/common/export_config.go; -->


HCL Example:

```hcl
format = "ova"
ovftool_options = ["--compress=9", "--makeDeltaDisks"]
skip_export = false
keep_registered = false
skip_compaction = true
```

### Output configuration

#### Optional:
Expand Down
69 changes: 59 additions & 10 deletions builder/vmware/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ import (
"strings"
"time"

"github.com/hashicorp/go-version"
"github.com/hashicorp/packer-plugin-sdk/multistep"
)

// Sets the minimum recommended version of the VMware OVF Tool.
// https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest
const minimumRecommendOvfToolVersion = "4.6.0"

// A regex to match the version of the VMware OVF Tool.
var ovfToolVersionRegex = regexp.MustCompile(`\d+\.\d+\.\d+`)

// A driver is able to talk to VMware, control virtual machines, etc.
type Driver interface {
// Clone clones the VMX and the disk to the destination path. The
Expand Down Expand Up @@ -630,10 +638,10 @@ func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
return "", fmt.Errorf("unable to find host IP from devices %v, last error: %s", devices, lastError)
}

func GetOVFTool() string {
func GetOvfTool() string {
ovftool := "ovftool"
if runtime.GOOS == "windows" {
ovftool = "ovftool.exe"
ovftool += ".exe"
}

if _, err := exec.LookPath(ovftool); err != nil {
Expand All @@ -642,8 +650,47 @@ func GetOVFTool() string {
return ovftool
}

// CheckOvfToolVersion checks the version of the VMware OVF Tool.
func CheckOvfToolVersion(ovftoolPath string) (bool, error) {
output, err := exec.Command(ovftoolPath, "--version").CombinedOutput()
if err != nil {
log.Printf("[WARN] Error running 'ovftool --version': %v.", err)
log.Printf("[WARN] Returned: %s", string(output))
return false, errors.New("failed to execute ovftool")
}
versionOutput := string(output)
log.Printf("Returned ovftool version: %s.", versionOutput)

fields := strings.Fields(versionOutput)
for _, field := range fields {
if ovfToolVersionRegex.MatchString(field) {
currentVersion, err := version.NewVersion(field)
if err != nil {
log.Printf("[WARN] Failed to parse version '%s': %v.", field, err)
return false, errors.New("failed to parse version")
}

minimumVersion, err := version.NewVersion(minimumRecommendOvfToolVersion)
if err != nil {
log.Printf("[WARN] Failed to parse minimum recommended version '%s': %v", minimumRecommendOvfToolVersion, err)
return false, errors.New("failed to parse minimum recommended version")
}

if currentVersion.LessThan(minimumVersion) {
log.Printf("[WARN] The version of ovftool (%s) is below the minimum recommended version (%s).", currentVersion, minimumVersion)
return false, errors.New("ovftool version is below the minimum recommended version")
}

return true, nil
}
}

log.Printf("[WARN] Unable to determine the version of ovftool.")
return false, errors.New("unable to determine the version of ovftool")
}

func (d *VmwareDriver) Export(args []string) error {
ovftool := GetOVFTool()
ovftool := GetOvfTool()
if ovftool == "" {
return fmt.Errorf("error finding ovftool in path")
}
Expand All @@ -661,13 +708,15 @@ func (d *VmwareDriver) VerifyOvfTool(SkipExport, _ bool) error {
}

log.Printf("Verifying that ovftool exists...")
// Validate that tool exists, but no need to validate credentials.
ovftool := GetOVFTool()
if ovftool != "" {
return nil
} else {
return fmt.Errorf("ovftool not found in path. either set " +
"'skip_export = true', remove 'format' option, or install ovftool")
ovftoolPath := GetOvfTool()
if ovftoolPath == "" {
return fmt.Errorf("ovftool not found; install and include it in your PATH")
}

log.Printf("Checking ovftool version...")
if !CheckOvfToolVersion(ovftoolPath) {

Check failure on line 717 in builder/vmware/common/driver.go

View workflow job for this annotation

GitHub Actions / Linux Go tests

multiple-value CheckOvfToolVersion(ovftoolPath) (value of type (bool, error)) in single-value context

Check failure on line 717 in builder/vmware/common/driver.go

View workflow job for this annotation

GitHub Actions / Darwin Go tests

multiple-value CheckOvfToolVersion(ovftoolPath) (value of type (bool, error)) in single-value context

Check failure on line 717 in builder/vmware/common/driver.go

View workflow job for this annotation

GitHub Actions / Windows Go tests

multiple-value CheckOvfToolVersion(ovftoolPath) (value of type (bool, error)) in single-value context
log.Printf("[WARN] ovftool does not meet the minimum recommended version: %s", minimumRecommendOvfToolVersion)
}

return nil
}
2 changes: 1 addition & 1 deletion builder/vmware/common/driver_esx5.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ func (d *ESX5Driver) VerifyOvfTool(SkipExport, skipValidateCredentials bool) err
// check that password is valid by sending a dummy ovftool command
// now, so that we don't fail for a simple mistake after a long
// build
ovftool := GetOVFTool()
ovftool := GetOvfTool()

if d.Password == "" {
return fmt.Errorf("exporting the vm from esxi with ovftool requires " +
Expand Down
2 changes: 1 addition & 1 deletion builder/vmware/common/step_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multiste

var args, ui_args []string

ovftool := GetOVFTool()
ovftool := GetOvfTool()
if c.RemoteType == "esx5" {
// Generate arguments for the ovftool command, but obfuscating the
// password that we can log the command to the UI for debugging.
Expand Down
12 changes: 12 additions & 0 deletions docs/builders/iso.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,18 @@ necessary for this build to succeed and can be found further down the page.

@include 'builder/vmware/common/ExportConfig-not-required.mdx'

HCL Example:

```hcl
source "vmware-iso" "example" {
# ... omitted for brevity ...
format = "ova"
ovftool_options = ["--compress=9", "--makeDeltaDisks"]
skip_export = false
keep_registered = false
skip_compaction = true
```

### Communicator configuration

#### Optional common fields:
Expand Down
10 changes: 10 additions & 0 deletions docs/builders/vmx.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ necessary for this build to succeed and can be found further down the page.

@include 'builder/vmware/common/ExportConfig-not-required.mdx'

HCL Example:

```hcl
format = "ova"
ovftool_options = ["--compress=9", "--makeDeltaDisks"]
skip_export = false
keep_registered = false
skip_compaction = true
```

### Output configuration

#### Optional:
Expand Down

0 comments on commit 939a252

Please sign in to comment.