refactor ovftool validation into vmware driver

This commit is contained in:
Megan Marsh 2020-08-26 15:45:59 -07:00
parent bbc3a5b0d1
commit 1c5bc41beb
6 changed files with 102 additions and 66 deletions

View File

@ -80,6 +80,9 @@ type Driver interface {
// Export the vm to ovf or ova format using ovftool
Export([]string) error
// OvfTool
VerifyOvfTool(bool, bool) error
}
// NewDriver returns a new driver implementation for this operating
@ -628,3 +631,22 @@ func (d *VmwareDriver) Export(args []string) error {
return nil
}
func (d *VmwareDriver) VerifyOvfTool(SkipExport, _ bool) error {
if SkipExport {
return nil
}
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("Couldn't find ovftool in path! Please either " +
"set `skip_export = true` and remove the `format` option " +
"from your template, or make sure ovftool is installed on " +
"your build system. ")
}
}

View File

@ -3,14 +3,8 @@
package common
import (
"bytes"
"context"
"fmt"
"net/url"
"os"
"os/exec"
"strings"
"time"
"github.com/hashicorp/packer/template/interpolate"
)
@ -93,65 +87,5 @@ func (c *DriverConfig) Validate(SkipExport bool) error {
"that you set a value for remote_password")
}
if c.RemoteType == "" {
// Validate that tool exists, but no need to validate credentials.
ovftool := GetOVFTool()
if ovftool != "" {
return nil
} else {
return fmt.Errorf("Couldn't find ovftool in path! Please either " +
"set `skip_export = true` and remove the `format` option " +
"from your template, or make sure ovftool is installed on " +
"your build system. ")
}
}
if c.SkipValidateCredentials {
return nil
}
// 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()
// Generate the uri of the host, with embedded credentials
ovftool_uri := fmt.Sprintf("vi://%s", c.RemoteHost)
u, err := url.Parse(ovftool_uri)
if err != nil {
return fmt.Errorf("Couldn't generate uri for ovftool: %s", err)
}
u.User = url.UserPassword(c.RemoteUser, c.RemotePassword)
ovfToolArgs := []string{"--noSSLVerify", "--verifyOnly", u.String()}
var out bytes.Buffer
cmdCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
cmd := exec.CommandContext(cmdCtx, ovftool, ovfToolArgs...)
cmd.Stdout = &out
// Need to manually close stdin or else the ofvtool call will hang
// forever in a situation where the user has provided an invalid
// password or username
stdin, _ := cmd.StdinPipe()
defer stdin.Close()
if err := cmd.Run(); err != nil {
outString := out.String()
// The command *should* fail with this error, if it
// authenticates properly.
if !strings.Contains(outString, "Found wrong kind of object") {
err := fmt.Errorf("ovftool validation error: %s; %s",
err, outString)
if strings.Contains(outString,
"Enter login information for source") {
err = fmt.Errorf("The username or password you " +
"provided to ovftool is invalid.")
}
return err
}
}
return nil
}

View File

@ -11,7 +11,9 @@ import (
"io"
"log"
"net"
"net/url"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
@ -263,6 +265,68 @@ func (d *ESX5Driver) Verify() error {
return nil
}
func (d *ESX5Driver) VerifyOvfTool(SkipExport, skipValidateCredentials bool) error {
err := d.base.VerifyOvfTool(SkipExport, skipValidateCredentials)
if err != nil {
return err
}
log.Printf("Verifying that ovftool credentials are valid...")
// 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()
if skipValidateCredentials {
return nil
}
if d.Password == "" {
return fmt.Errorf("exporting the vm from esxi with ovftool requires " +
"that you set a value for remote_password")
}
// Generate the uri of the host, with embedded credentials
ovftool_uri := fmt.Sprintf("vi://%s", d.Host)
u, err := url.Parse(ovftool_uri)
if err != nil {
return fmt.Errorf("Couldn't generate uri for ovftool: %s", err)
}
u.User = url.UserPassword(d.Username, d.Password)
ovfToolArgs := []string{"--noSSLVerify", "--verifyOnly", u.String()}
var out bytes.Buffer
cmdCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
cmd := exec.CommandContext(cmdCtx, ovftool, ovfToolArgs...)
cmd.Stdout = &out
// Need to manually close stdin or else the ofvtool call will hang
// forever in a situation where the user has provided an invalid
// password or username
stdin, _ := cmd.StdinPipe()
defer stdin.Close()
if err := cmd.Run(); err != nil {
outString := out.String()
// The command *should* fail with this error, if it
// authenticates properly.
if !strings.Contains(outString, "Found wrong kind of object") {
err := fmt.Errorf("ovftool validation error: %s; %s",
err, outString)
if strings.Contains(outString,
"Enter login information for source") {
err = fmt.Errorf("The username or password you " +
"provided to ovftool is invalid.")
}
return err
}
}
return nil
}
func (d *ESX5Driver) HostIP(multistep.StateBag) (string, error) {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", d.Host, d.Port))
if err != nil {

View File

@ -95,6 +95,8 @@ type DriverMock struct {
VerifyCalled bool
VerifyErr error
VerifyOvftoolCalled bool
}
type NetworkMapperMock struct {
@ -279,3 +281,7 @@ func (d *DriverMock) GetVmwareDriver() VmwareDriver {
}
return state
}
func (d *DriverMock) VerifyOvfTool(_ bool, _ bool) error {
return nil
}

View File

@ -35,6 +35,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
if err != nil {
return nil, fmt.Errorf("Failed creating VMware driver: %s", err)
}
// Before we get deep into the build, make sure ovftool is present and
// credentials are valid, if we're going to use ovftool.
if err := driver.VerifyOvfTool(b.config.SkipExport, b.config.SkipValidateCredentials); err != nil {
return nil, err
}
// Setup the state bag
state := new(multistep.BasicStateBag)

View File

@ -40,6 +40,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
if err != nil {
return nil, fmt.Errorf("Failed creating VMware driver: %s", err)
}
// Before we get deep into the build, make sure ovftool is present and
// credentials are valid, if we're going to use ovftool.
if err := driver.VerifyOvfTool(b.config.SkipExport, b.config.SkipValidateCredentials); err != nil {
return nil, err
}
// Set up the state.
state := new(multistep.BasicStateBag)