From ce1d2d58cbfdbeb8097386e119f6fdf45beb6697 Mon Sep 17 00:00:00 2001 From: Ryan Johnson Date: Wed, 14 Aug 2024 15:45:34 -0400 Subject: [PATCH] chore: error technical debt - Update errors that don't require formatting to use `errors.New` instead of `fmt.Errorf` to be more idiomatic. - Updates UI errors that need formatting to `ui.Errorf` instead of `ui.Error(fmt.Sprintf(` - Correct spelling mistakes in docs/comments. Signed-off-by: Ryan Johnson --- .web-docs/components/builder/vmx/README.md | 2 +- builder/vmware/common/driver.go | 26 ++++----- builder/vmware/common/driver_esx5.go | 14 ++--- builder/vmware/common/driver_esx5_test.go | 2 +- builder/vmware/common/driver_fusion6.go | 2 +- builder/vmware/common/driver_parser.go | 17 +++--- builder/vmware/common/driver_parser_test.go | 16 +++--- builder/vmware/common/run_config.go | 5 +- builder/vmware/common/run_config_test.go | 2 +- builder/vmware/common/ssh.go | 2 +- builder/vmware/common/step_clean_files.go | 2 +- builder/vmware/common/step_configure_vmx.go | 9 ++-- .../vmware/common/step_configure_vmx_test.go | 2 +- builder/vmware/common/step_configure_vnc.go | 7 +-- builder/vmware/common/step_create_disks.go | 2 +- builder/vmware/common/step_export.go | 9 ++-- .../vmware/common/step_http_ip_discover.go | 2 +- builder/vmware/common/step_register.go | 53 ++++++++++--------- builder/vmware/common/step_remote_upload.go | 4 +- builder/vmware/common/step_run.go | 31 ++++++----- builder/vmware/common/step_shutdown.go | 23 ++++---- .../vmware/common/step_suppress_messages.go | 2 +- builder/vmware/common/step_upload_tools.go | 9 ++-- builder/vmware/common/step_upload_vmx.go | 4 +- .../vmware/common/step_vnc_boot_command.go | 8 +-- builder/vmware/common/step_vnc_connect.go | 7 +-- builder/vmware/common/tools_config.go | 3 +- builder/vmware/iso/step_create_vmx.go | 5 +- builder/vmware/iso/step_create_vmx_test.go | 13 ++--- builder/vmware/vmx/config.go | 7 +-- builder/vmware/vmx/step_clone_vmx.go | 2 +- .../vmware/vmx/Config-not-required.mdx | 2 +- 32 files changed, 158 insertions(+), 136 deletions(-) diff --git a/.web-docs/components/builder/vmx/README.md b/.web-docs/components/builder/vmx/README.md index 5b204084..abda13f6 100644 --- a/.web-docs/components/builder/vmx/README.md +++ b/.web-docs/components/builder/vmx/README.md @@ -65,7 +65,7 @@ JSON Example: - `linked` (bool) - By default Packer creates a 'full' clone of the virtual machine specified in source_path. The resultant virtual machine is fully - independant from the parent it was cloned from. + independent from the parent it was cloned from. Setting linked to true instead causes Packer to create the virtual machine as a 'linked' clone. Linked clones use and require ongoing diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go index 72083941..454e5587 100644 --- a/builder/vmware/common/driver.go +++ b/builder/vmware/common/driver.go @@ -133,7 +133,7 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver, NewPlayer5Driver(config), } default: - return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS) + return nil, fmt.Errorf("error finding a driver for %s", runtime.GOOS) } } @@ -141,7 +141,7 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver, for _, driver := range drivers { err := driver.Verify() - log.Printf("Testing against vmware driver %T, Success: %t", driver, err == nil) + log.Printf("Testing against driver %T, Success: %t", driver, err == nil) if err == nil { return driver, nil } @@ -170,20 +170,22 @@ func runAndLog(cmd *exec.Cmd) (string, string, error) { message = stdoutString } - err = fmt.Errorf("VMware error: %s", message) + err = fmt.Errorf("error: %s", message) // If "unknown error" is in there, add some additional notes re := regexp.MustCompile(`(?i)unknown error`) if re.MatchString(message) { err = fmt.Errorf( "%s\n\n%s", err, - "Packer detected a VMware 'Unknown Error'. Unfortunately VMware\n"+ - "often has extremely vague error messages such as this and Packer\n"+ - "itself can't do much about that. Please check the vmware.log files\n"+ - "created by VMware when a VM is started (in the directory of the\n"+ - "vmx file), which often contains more detailed error information.\n\n"+ - "You may need to set the command line flag --on-error=abort to\n\n"+ - "prevent Packer from cleaning up the vmx file directory.") + "Packer detected an error from the VMware hypervisor "+ + "platform. Unfortunately, the error message provided is "+ + "not very specific. Please check the `vmware.log` files "+ + "created by the hypervisor platform when a virtual "+ + "machine is started. The logs are located in the "+ + "directory of the .vmx file and often contain more "+ + "detailed error information.\n\nYou may need to set the "+ + "command line flag --on-error=abort to prevent the plugin "+ + "from cleaning up the file directory.") } } @@ -688,7 +690,7 @@ func CheckOvfToolVersion(ovftoolPath string) error { func (d *VmwareDriver) Export(args []string) error { ovftool := GetOvfTool() if ovftool == "" { - return fmt.Errorf("error finding ovftool in path") + return errors.New("error finding ovftool in path") } cmd := exec.Command(ovftool, args...) if _, _, err := runAndLog(cmd); err != nil { @@ -706,7 +708,7 @@ func (d *VmwareDriver) VerifyOvfTool(SkipExport, _ bool) error { log.Printf("Verifying that ovftool exists...") ovftoolPath := GetOvfTool() if ovftoolPath == "" { - return fmt.Errorf("ovftool not found; install and include it in your PATH") + return errors.New("ovftool not found; install and include it in your PATH") } log.Printf("Checking ovftool version...") diff --git a/builder/vmware/common/driver_esx5.go b/builder/vmware/common/driver_esx5.go index 8cce8a73..ae092ddf 100644 --- a/builder/vmware/common/driver_esx5.go +++ b/builder/vmware/common/driver_esx5.go @@ -436,13 +436,13 @@ func (d *ESX5Driver) HostAddress(multistep.StateBag) (string, error) { // get the local address (the host) host, _, err := net.SplitHostPort(conn.LocalAddr().String()) if err != nil { - return "", fmt.Errorf("unable to determine host address : %v", err) + return "", fmt.Errorf("unable to determine host address : %s", err) } // iterate through all the interfaces.. interfaces, err := net.Interfaces() if err != nil { - return "", fmt.Errorf("unable to enumerate host interfaces : %v", err) + return "", fmt.Errorf("unable to enumerate host interfaces : %s", err) } for _, intf := range interfaces { @@ -467,7 +467,7 @@ func (d *ESX5Driver) GuestAddress(multistep.StateBag) (string, error) { // list all the interfaces on the ESXi host r, err := d.esxcli("network", "ip", "interface", "list") if err != nil { - return "", fmt.Errorf("unable to retrieve host interfaces : %v", err) + return "", fmt.Errorf("unable to retrieve host interfaces : %s", err) } // rip out the interface name and the MAC address from the csv output @@ -482,7 +482,7 @@ func (d *ESX5Driver) GuestAddress(multistep.StateBag) (string, error) { // list all the addresses on the ESXi host r, err = d.esxcli("network", "ip", "interface", "ipv4", "get") if err != nil { - return "", fmt.Errorf("unable to retrieve host addresses : %v", err) + return "", fmt.Errorf("unable to retrieve host addresses : %s", err) } // figure out the interface name that matches the specified d.Host address @@ -501,7 +501,7 @@ func (d *ESX5Driver) GuestAddress(multistep.StateBag) (string, error) { // find the MAC address according to the interface name result, ok := addrs[intf] if !ok { - return "", fmt.Errorf("unable to find address for guest interface") + return "", errors.New("unable to find address for guest interface") } // ..and we're good @@ -516,7 +516,7 @@ func (d *ESX5Driver) VNCAddress(ctx context.Context, _ string, portMin, portMax //it will ignore any ports listened to by only localhost r, err := d.esxcli("network", "ip", "connection", "list") if err != nil { - err = fmt.Errorf("unable to retrieve network information for host : %v", err) + err = fmt.Errorf("unable to retrieve network information for host : %s", err) return "", 0, err } @@ -856,7 +856,7 @@ func (d *ESX5Driver) VerifyChecksum(hash string, file string) bool { Src: file + "?checksum=" + hash, }) if err != nil { - log.Printf("[ERROR] Error parsing the checksum: %v", err) + log.Printf("[ERROR] Error parsing the checksum: %s", err) return false } diff --git a/builder/vmware/common/driver_esx5_test.go b/builder/vmware/common/driver_esx5_test.go index fde45922..bd6e3701 100644 --- a/builder/vmware/common/driver_esx5_test.go +++ b/builder/vmware/common/driver_esx5_test.go @@ -73,7 +73,7 @@ func TestESX5Driver_CommHost(t *testing.T) { var commConfig communicator.Config err := config.Decode(&commConfig, nil, conf) if err != nil { - t.Fatalf("error decoding config: %v", err) + t.Fatalf("error decoding config: %s", err) } state := new(multistep.BasicStateBag) sshConfig := SSHConfig{Comm: commConfig} diff --git a/builder/vmware/common/driver_fusion6.go b/builder/vmware/common/driver_fusion6.go index 411073dd..cbe4d75e 100644 --- a/builder/vmware/common/driver_fusion6.go +++ b/builder/vmware/common/driver_fusion6.go @@ -131,7 +131,7 @@ func (d *Fusion6Driver) ToolsIsoPath(k string) string { cmd := exec.Command(vmxpath, "-v") cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - log.Printf("[DEBUG] failed to execute vmware-vmx command to get version %v", err) + log.Printf("[DEBUG] failed to execute vmware-vmx command to get version %s", err) log.Printf("[DEBUG] continuing with default iso path for fusion6+.") return filepath.Join(d.AppPath, "Contents", "Library", "isoimages", "x86_x64", k+".iso") } diff --git a/builder/vmware/common/driver_parser.go b/builder/vmware/common/driver_parser.go index 61ef3125..92b7040f 100644 --- a/builder/vmware/common/driver_parser.go +++ b/builder/vmware/common/driver_parser.go @@ -6,6 +6,7 @@ package common import ( "bytes" "encoding/hex" + "errors" "fmt" "log" "math" @@ -68,7 +69,7 @@ func tokenizeDhcpConfig(in chan byte) chan string { } // If we're in a quote, then we continue until we're not in a quote - // before we start looing for tokens + // before we start looking for tokens if quote { if by == '"' { out <- state + string(by) @@ -81,7 +82,7 @@ func tokenizeDhcpConfig(in chan byte) chan string { switch by { case '"': - // Otherwise we're outside any quotes and can process bytes normaly + // Otherwise we're outside any quotes and can process bytes normally quote = true state += string(by) continue @@ -240,10 +241,10 @@ func parseDhcpConfig(in chan string) (tkGroup, error) { // that was because they were unterminated. Raise an error in that case. if node.parent == nil { - return tkGroup{}, fmt.Errorf("refused to close the global declaration") + return tkGroup{}, errors.New("refused to close the global declaration") } if len(tokens) > 0 { - return tkGroup{}, fmt.Errorf("list of tokens was left unterminated : %v", tokens) + return tkGroup{}, fmt.Errorf("list of tokens was left unterminated: %v", tokens) } node = node.parent @@ -415,12 +416,12 @@ func parseNetworkMapConfig(in chan string) (NetworkMap, error) { switch tk { case ".": if len(state) != 1 { - return nil, fmt.Errorf("network index missing") + return nil, errors.New("network index missing") } case "=": if len(state) != 2 { - return nil, fmt.Errorf("assigned to empty attribute") + return nil, errors.New("assigned to empty attribute") } case "\n": @@ -1031,7 +1032,7 @@ func (e *configDeclaration) IP4() (net.IP, error) { return nil, fmt.Errorf("more than one ipv4 address returned : %v", result) } else if len(result) == 0 { - return nil, fmt.Errorf("no ipv4 address found") + return nil, errors.New("no IPv4 address found") } // Try and parse it as an IP4. If so, then it's good to return it as-is. @@ -1064,7 +1065,7 @@ func (e *configDeclaration) IP6() (net.IP, error) { return nil, fmt.Errorf("more than one ipv6 address returned : %v", result) } else if len(result) == 0 { - return nil, fmt.Errorf("no ipv6 address found") + return nil, errors.New("no IPv6 address found") } // If we were able to parse it into an IP, then we can just return it. diff --git a/builder/vmware/common/driver_parser_test.go b/builder/vmware/common/driver_parser_test.go index adcf051d..5c0dcb49 100644 --- a/builder/vmware/common/driver_parser_test.go +++ b/builder/vmware/common/driver_parser_test.go @@ -359,7 +359,7 @@ parameters : map[default-lease-time:1800 max-lease-time:7200] config, err := ReadDhcpConfiguration(f) if err != nil { - t.Fatalf("Unable to read dhcpd.conf samplpe: %s", err) + t.Fatalf("Unable to read dhcpd.conf sample: %s", err) } if len(config) != 3 { @@ -429,7 +429,7 @@ func TestParserReadNetworkMap(t *testing.T) { netmap, err := ReadNetworkMap(f) if err != nil { - t.Fatalf("Unable to read netmap.conf samplpe: %s", err) + t.Fatalf("Unable to read netmap.conf sample: %s", err) } expected_keys := []string{"device", "name"} @@ -711,7 +711,7 @@ func TestParserReadDhcpdLeaseEntry(t *testing.T) { result, err := readDhcpdLeaseEntry(consumeLeaseString(test_1)) if err != nil { - t.Errorf("error parsing entry: %v", err) + t.Errorf("error parsing entry: %s", err) } if result.address != expected_1["address"] { t.Errorf("expected address %v, got %v", expected_1["address"], result.address) @@ -733,7 +733,7 @@ func TestParserReadDhcpdLeaseEntry(t *testing.T) { } result, err = readDhcpdLeaseEntry(consumeLeaseString(test_2)) if err != nil { - t.Errorf("error parsing entry: %v", err) + t.Errorf("error parsing entry: %s", err) } if result.address != expected_2["address"] { t.Errorf("expected address %v, got %v", expected_2["address"], result.address) @@ -896,7 +896,7 @@ func TestParserReadAppleDhcpdLeaseEntry(t *testing.T) { result, err := readAppleDhcpdLeaseEntry(consumeAppleLeaseString(test_1)) if err != nil { - t.Errorf("error parsing entry: %v", err) + t.Errorf("error parsing entry: %s", err) } if result.ipAddress != expected_1["ipAddress"] { t.Errorf("expected ipAddress %v, got %v", expected_1["ipAddress"], result.ipAddress) @@ -930,7 +930,7 @@ func TestParserReadAppleDhcpdLeaseEntry(t *testing.T) { result, err = readAppleDhcpdLeaseEntry(consumeAppleLeaseString(test_2)) if err != nil { - t.Errorf("error parsing entry: %v", err) + t.Errorf("error parsing entry: %s", err) } if result.ipAddress != expected_2["ipAddress"] { t.Errorf("expected ipAddress %v, got %v", expected_2["ipAddress"], result.ipAddress) @@ -1212,13 +1212,13 @@ func TestParserReadNetworingConfig(t *testing.T) { f, err := os.Open(filepath.Join("testdata", "networking-example")) if err != nil { - t.Fatalf("Unable to open networking-example sample: %v", err) + t.Fatalf("Unable to open networking-example sample: %s", err) } defer f.Close() config, err := ReadNetworkingConfig(f) if err != nil { - t.Fatalf("error parsing networking-example: %v", err) + t.Fatalf("error parsing networking-example: %s", err) } if vnet, ok := config.answer[1]; ok { diff --git a/builder/vmware/common/run_config.go b/builder/vmware/common/run_config.go index f95178b1..8d0b1100 100644 --- a/builder/vmware/common/run_config.go +++ b/builder/vmware/common/run_config.go @@ -6,6 +6,7 @@ package common import ( + "errors" "fmt" "github.com/hashicorp/packer-plugin-sdk/template/interpolate" @@ -68,11 +69,11 @@ type RunConfig struct { func (c *RunConfig) Prepare(_ *interpolate.Context, driverConfig *DriverConfig) (warnings []string, errs []error) { if c.VNCOverWebsocket { if driverConfig.RemoteType == "" { - errs = append(errs, fmt.Errorf("'vnc_over_websocket' can only be used with remote hypervisor builds")) + errs = append(errs, errors.New("'vnc_over_websocket' can only be used with remote hypervisor builds")) return } if c.VNCPortMin != 0 || c.VNCPortMax != 0 || c.VNCBindAddress != "" || c.VNCDisablePassword { - warnings = append(warnings, "[WARN] 'vnc_over_websocket' enabled, any other VNC configuration will be ignored.") + warnings = append(warnings, "[WARN] 'vnc_over_websocket' enabled; other VNC configurations will be ignored.") } return } diff --git a/builder/vmware/common/run_config_test.go b/builder/vmware/common/run_config_test.go index b8e3dfd5..c6d218a8 100644 --- a/builder/vmware/common/run_config_test.go +++ b/builder/vmware/common/run_config_test.go @@ -94,7 +94,7 @@ func TestRunConfig_Prepare(t *testing.T) { }, driver: &DriverConfig{RemoteType: "esx5"}, errs: nil, - warnings: []string{"[WARN] 'vnc_over_websocket' enabled, any other VNC configuration will be ignored."}, + warnings: []string{"[WARN] 'vnc_over_websocket' enabled; other VNC configurations will be ignored."}, }, } diff --git a/builder/vmware/common/ssh.go b/builder/vmware/common/ssh.go index 33690f2a..e427b181 100644 --- a/builder/vmware/common/ssh.go +++ b/builder/vmware/common/ssh.go @@ -33,7 +33,7 @@ func CommHost(config *SSHConfig) func(multistep.StateBag) (string, error) { hosts, err := driver.PotentialGuestIP(state) if err != nil { log.Printf("IP lookup failed: %s", err) - return "", fmt.Errorf("IP lookup failed: %s", err) + return "", fmt.Errorf("failed to lookup IP: %s", err) } if len(hosts) == 0 { diff --git a/builder/vmware/common/step_clean_files.go b/builder/vmware/common/step_clean_files.go index 8a041aa6..a9c194ad 100644 --- a/builder/vmware/common/step_clean_files.go +++ b/builder/vmware/common/step_clean_files.go @@ -32,7 +32,7 @@ func (StepCleanFiles) Run(ctx context.Context, state multistep.StateBag) multist dir := state.Get("dir").(OutputDir) ui := state.Get("ui").(packersdk.Ui) - ui.Say("Deleting unnecessary VMware files...") + ui.Say("Deleting unnecessary files...") files, err := dir.ListFiles() if err != nil { state.Put("error", err) diff --git a/builder/vmware/common/step_configure_vmx.go b/builder/vmware/common/step_configure_vmx.go index 8c68ad5a..2d449b7c 100644 --- a/builder/vmware/common/step_configure_vmx.go +++ b/builder/vmware/common/step_configure_vmx.go @@ -5,6 +5,7 @@ package common import ( "context" + "errors" "fmt" "log" "regexp" @@ -37,7 +38,7 @@ func (s *StepConfigureVMX) Run(ctx context.Context, state multistep.StateBag) mu vmxPath := state.Get("vmx_path").(string) vmxData, err := ReadVMX(vmxPath) if err != nil { - err := fmt.Errorf("error reading VMX file: %s", err) + err = fmt.Errorf("error reading VMX file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -110,7 +111,7 @@ func (s *StepConfigureVMX) Run(ctx context.Context, state multistep.StateBag) mu } else { displayName, ok := vmxData["displayname"] if !ok { // Packer converts key names to lowercase! - err := fmt.Errorf("error returning value of displayName from VMX data") + err := errors.New("error returning value of displayName from VMX data") state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -122,7 +123,7 @@ func (s *StepConfigureVMX) Run(ctx context.Context, state multistep.StateBag) mu // Set the extendedConfigFile setting for the .vmxf filename to the VMName // if displayName is not set. This is needed so that when VMware creates // the .vmxf file it matches the displayName if it is set. When just using - // the sisplayName if it was empty VMware would make a file named ".vmxf". + // the displayName if it was empty VMware would make a file named ".vmxf". // The ".vmxf" file would not get deleted when the VM got deleted. if s.DisplayName != "" { vmxData["extendedconfigfile"] = fmt.Sprintf("%s.vmxf", s.DisplayName) @@ -133,7 +134,7 @@ func (s *StepConfigureVMX) Run(ctx context.Context, state multistep.StateBag) mu err = WriteVMX(vmxPath, vmxData) if err != nil { - err := fmt.Errorf("error writing VMX file: %s", err) + err = fmt.Errorf("error writing VMX file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/common/step_configure_vmx_test.go b/builder/vmware/common/step_configure_vmx_test.go index d79260ce..bae367d0 100644 --- a/builder/vmware/common/step_configure_vmx_test.go +++ b/builder/vmware/common/step_configure_vmx_test.go @@ -21,7 +21,7 @@ func testVMXFile(t *testing.T) string { // displayName must always be set err = WriteVMX(tf.Name(), map[string]string{"displayName": "PackerBuild"}) if err != nil { - t.Fatalf("error writing .vmx file: %v", err) + t.Fatalf("error writing .vmx file: %s", err) } tf.Close() diff --git a/builder/vmware/common/step_configure_vnc.go b/builder/vmware/common/step_configure_vnc.go index e9f59bc7..d62a1185 100644 --- a/builder/vmware/common/step_configure_vnc.go +++ b/builder/vmware/common/step_configure_vnc.go @@ -86,7 +86,7 @@ func (s *StepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu vmxData, err := ReadVMX(vmxPath) if err != nil { - err := fmt.Errorf("error reading VMX file: %s", err) + err = fmt.Errorf("error reading VMX file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -103,6 +103,7 @@ func (s *StepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu vncBindAddress, vncPort, err := vncFinder.VNCAddress(ctx, s.VNCBindAddress, s.VNCPortMin, s.VNCPortMax) if err != nil { + err = fmt.Errorf("error finding available VNC port: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -115,7 +116,7 @@ func (s *StepConfigureVNC) Run(ctx context.Context, state multistep.StateBag) mu vncFinder.UpdateVMX(vncBindAddress, vncPassword, vncPort, vmxData) if err := WriteVMX(vmxPath, vmxData); err != nil { - err := fmt.Errorf("error writing VMX data: %s", err) + err = fmt.Errorf("error writing VMX data: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -140,7 +141,7 @@ func (*StepConfigureVNC) UpdateVMX(address, password string, port int, data map[ func (s *StepConfigureVNC) Cleanup(multistep.StateBag) { if s.l != nil { if err := s.l.Close(); err != nil { - log.Printf("failed to unlock port lockfile: %v", err) + log.Printf("failed to unlock port lockfile: %s", err) } } } diff --git a/builder/vmware/common/step_create_disks.go b/builder/vmware/common/step_create_disks.go index 6c886e69..ad48dd00 100644 --- a/builder/vmware/common/step_create_disks.go +++ b/builder/vmware/common/step_create_disks.go @@ -28,7 +28,7 @@ func (s *StepCreateDisks) Run(ctx context.Context, state multistep.StateBag) mul driver := state.Get("driver").(Driver) ui := state.Get("ui").(packersdk.Ui) - ui.Say("Creating required virtual machine disks") + ui.Say("Creating virtual machine disks...") // Users can configure disks at several locations in the template so // first collate all the disk requirements diff --git a/builder/vmware/common/step_export.go b/builder/vmware/common/step_export.go index b2a9fa1e..cf8e81b0 100644 --- a/builder/vmware/common/step_export.go +++ b/builder/vmware/common/step_export.go @@ -80,7 +80,8 @@ func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multiste err := os.MkdirAll(exportOutputPath, 0755) if err != nil { - state.Put("error creating export directory", err) + err = fmt.Errorf("error creating export directory: %s", err) + state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } @@ -99,7 +100,7 @@ func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multiste // password that we can log the command to the UI for debugging. ui_args, err := s.generateRemoteExportArgs(c, displayName, true, exportOutputPath) if err != nil { - err := fmt.Errorf("error generating ovftool export args: %s", err) + err = fmt.Errorf("error generating ovftool export args: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -110,7 +111,7 @@ func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multiste // password, so we can actually use it. args, err = s.generateRemoteExportArgs(c, displayName, false, exportOutputPath) if err != nil { - err := fmt.Errorf("error generating ovftool export args: %s", err) + err = fmt.Errorf("error generating ovftool export args: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -128,7 +129,7 @@ func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multiste } if err := driver.Export(args); err != nil { - err := fmt.Errorf("error performing ovftool export: %s", err) + err = fmt.Errorf("error performing ovftool export: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/common/step_http_ip_discover.go b/builder/vmware/common/step_http_ip_discover.go index ff721d25..90ee7f0f 100644 --- a/builder/vmware/common/step_http_ip_discover.go +++ b/builder/vmware/common/step_http_ip_discover.go @@ -24,7 +24,7 @@ func (s *StepHTTPIPDiscover) Run(ctx context.Context, state multistep.StateBag) // Determine the host IP hostIP, err := driver.HostIP(state) if err != nil { - err := fmt.Errorf("error detecting host IP: %s", err) + err = fmt.Errorf("error detecting host IP: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/common/step_register.go b/builder/vmware/common/step_register.go index f8f0fb75..6881df85 100644 --- a/builder/vmware/common/step_register.go +++ b/builder/vmware/common/step_register.go @@ -31,7 +31,7 @@ func (s *StepRegister) Run(ctx context.Context, state multistep.StateBag) multis if remoteDriver, ok := driver.(RemoteDriver); ok { ui.Say("Registering virtual machine on remote hypervisor...") if err := remoteDriver.Register(vmxPath); err != nil { - err := fmt.Errorf("error registering virtual machine on remote hypervisor: %s", err) + err = fmt.Errorf("error registering virtual machine on remote hypervisor: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -59,37 +59,40 @@ func (s *StepRegister) Cleanup(state multistep.StateBag) { } if remoteDriver, ok := driver.(RemoteDriver); ok { + var err error + if s.SkipExport && !cancelled && !halted { ui.Say("Removing virtual machine from inventory...") - if err := remoteDriver.Unregister(s.registeredPath); err != nil { - ui.Errorf("error removing virtual machine: %s", err) - } - + err = remoteDriver.Unregister(s.registeredPath) s.registeredPath = "" } else { ui.Say("Deleting virtual machine...") - if err := remoteDriver.Destroy(); err != nil { - ui.Errorf("error deleting virtual machine: %s", err) - } - - // Wait for the virtual machine to be deleted. - start := time.Now() - ticker := time.NewTicker(1 * time.Second) - defer ticker.Stop() - - for range ticker.C { - destroyed, err := remoteDriver.IsDestroyed() - if destroyed { - break - } - if err != nil { - log.Printf("error deleting virtual machine: %s", err) - } - if time.Since(start) >= destroyTimeout { - ui.Error("error removing virtual machine from inventory; manual cleanup may be required") - break + err = remoteDriver.Destroy() + + if err == nil { + // Wait for the virtual machine to be deleted. + start := time.Now() + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for range ticker.C { + var destroyed bool + destroyed, err = remoteDriver.IsDestroyed() + if err != nil || destroyed { + break + } + if time.Since(start) >= destroyTimeout { + err = fmt.Errorf("timeout after %s", destroyTimeout) + break + } } } } + + if err != nil { + ui.Errorf("error: %s", err) + ui.Message("Please perform the necessary manual operations to clean up the virtual machine.") + return + } } } diff --git a/builder/vmware/common/step_remote_upload.go b/builder/vmware/common/step_remote_upload.go index f6fe5ee1..d559c95d 100644 --- a/builder/vmware/common/step_remote_upload.go +++ b/builder/vmware/common/step_remote_upload.go @@ -39,7 +39,7 @@ func (s *StepRemoteUpload) Run(ctx context.Context, state multistep.StateBag) mu remotePath := esx5.CachePath(path) if esx5.VerifyChecksum(s.Checksum, remotePath) { - ui.Say("Remote cache was verified skipping remote upload...") + ui.Say("Remote cache verified; skipping remote upload...") state.Put(s.Key, remotePath) return multistep.ActionContinue } @@ -50,7 +50,7 @@ func (s *StepRemoteUpload) Run(ctx context.Context, state multistep.StateBag) mu log.Printf("Remote uploading: %s", path) newPath, err := remote.UploadISO(path, s.Checksum, ui) if err != nil { - err := fmt.Errorf("error uploading file: %s", err) + err = fmt.Errorf("error uploading file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/common/step_run.go b/builder/vmware/common/step_run.go index 9e1af4f7..06e1fc50 100644 --- a/builder/vmware/common/step_run.go +++ b/builder/vmware/common/step_run.go @@ -30,7 +30,7 @@ func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.S s.bootTime = time.Now() s.vmxPath = vmxPath - ui.Say("Starting virtual machine...") + ui.Say("Powering on virtual machine...") if s.Headless { vncIpRaw, vncIpOk := state.GetOk("vnc_ip") vncPortRaw, vncPortOk := state.GetOk("vnc_port") @@ -42,18 +42,20 @@ func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.S vncPassword := vncPasswordRaw.(string) ui.Message(fmt.Sprintf( - "The VM will be run headless, without a GUI. If you want to\n"+ - "view the screen of the VM, connect via VNC with the password \"%s\" to\n"+ - "vnc://%s:%d", vncPassword, vncIp, vncPort)) + "The virtual machine will be run headless, without a GUI.\n"+ + "To view the virtual machine console, connect using VNC:\n\n"+ + "Endpoint: \"vnc://%s:%d\"\n"+ + "Password: \"%s\"", vncIp, vncPort, vncPassword)) } else { - ui.Message("The VM will be run headless, without a GUI, as configured.\n" + - "If the run isn't succeeding as you expect, please enable the GUI\n" + - "to inspect the progress of the build.") + ui.Message(fmt.Sprintf( + "The virtual machine will be run headless, without a GUI.\n" + + "If the build is not succeeding, enable the GUI to\n" + + "inspect the progress of the build.")) } } if err := driver.Start(vmxPath, s.Headless); err != nil { - err := fmt.Errorf("error starting virtual machine: %s", err) + err = fmt.Errorf("error starting virtual machine: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -70,24 +72,25 @@ func (s *StepRun) Cleanup(state multistep.StateBag) { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packersdk.Ui) - // If we started the machine... stop it. + // If the virtual machine was started, stop it. if s.vmxPath != "" { - // If we started it less than 5 seconds ago... wait. + // If started, wait for the duration before stopping. sinceBootTime := time.Since(s.bootTime) waitBootTime := s.DurationBeforeStop if sinceBootTime < waitBootTime { sleepTime := waitBootTime - sinceBootTime - ui.Say(fmt.Sprintf( - "Waiting %s to give VMware time to clean up...", sleepTime.String())) + ui.Sayf("Waiting %s for clean up...", sleepTime.String()) time.Sleep(sleepTime) } - // See if it is running + // If the virtual machine is running, stop it. running, _ := driver.IsRunning(s.vmxPath) if running { ui.Say("Stopping virtual machine...") if err := driver.Stop(s.vmxPath); err != nil { - ui.Error(fmt.Sprintf("Error stopping VM: %s", err)) + ui.Errorf("error stopping the virtual machine: %s", err) + ui.Message("Please perform the necessary manual operations to stop the virtual machine.") + return } } } diff --git a/builder/vmware/common/step_shutdown.go b/builder/vmware/common/step_shutdown.go index 04d7cf63..7b3fd88f 100644 --- a/builder/vmware/common/step_shutdown.go +++ b/builder/vmware/common/step_shutdown.go @@ -45,14 +45,14 @@ func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multis Stderr: &stderr, } if err := comm.Start(ctx, cmd); err != nil { - err := fmt.Errorf("error sending shutdown command: %s", err) + err = fmt.Errorf("error sending shutdown command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Wait for the machine to actually shut down - log.Printf("Waiting max %s for shutdown to complete", s.Timeout) + log.Printf("Waiting up to %s for shutdown to complete", s.Timeout) shutdownTimer := time.After(s.Timeout) for { running, _ := driver.IsRunning(vmxPath) @@ -99,12 +99,12 @@ LockWaitLoop: } if len(locks) == 0 { - log.Println("No more lock files found. VMware is clean.") + log.Println("No more lock files found. Assuming the virtual machine is clean.") break } if len(locks) == 1 && strings.HasSuffix(locks[0], ".vmx.lck") { - log.Println("Only waiting on VMX lock. VMware is clean.") + log.Println("Only waiting on the '.vmx.lck' file. Assuming the virtual machine is clean.") break } @@ -113,7 +113,7 @@ LockWaitLoop: select { case <-timer: - log.Println("Reached timeout on waiting for clean VMware. Assuming clean.") + log.Println("Reached timeout on waiting for lock files to be cleaned up. Assuming the virtual machine is clean.") break LockWaitLoop case <-time.After(150 * time.Millisecond): } @@ -121,16 +121,17 @@ LockWaitLoop: if !s.Testing { // Windows takes a while to yield control of the files when the - // process is exiting. Ubuntu and OS X will yield control of the files - // but VMware may overwrite the VMX cleanup steps that run after this, - // so we wait to ensure VMware has exited and flushed the VMX. + // process is exiting. Ubuntu and macOS will yield control of the files + // but the the hypervisor may overwrite the VMX cleanup steps that run + // after this, so we wait to ensure hypervisor has exited and flushed the + // VMX. - // We just sleep here. In the future, it'd be nice to find a better - // solution to this. + // We just sleep here. + // TO DO: Develop a better solution to this. time.Sleep(5 * time.Second) } - log.Println("VM shut down.") + log.Println("Shutdown of virtual machine has completed.") return multistep.ActionContinue } diff --git a/builder/vmware/common/step_suppress_messages.go b/builder/vmware/common/step_suppress_messages.go index 633377b8..cde1f684 100644 --- a/builder/vmware/common/step_suppress_messages.go +++ b/builder/vmware/common/step_suppress_messages.go @@ -22,7 +22,7 @@ func (s *StepSuppressMessages) Run(ctx context.Context, state multistep.StateBag log.Println("Suppressing messages in VMX") if err := driver.SuppressMessages(vmxPath); err != nil { - err := fmt.Errorf("error suppressing messages: %s", err) + err = fmt.Errorf("error suppressing messages: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/common/step_upload_tools.go b/builder/vmware/common/step_upload_tools.go index cee95be7..2ddf184f 100644 --- a/builder/vmware/common/step_upload_tools.go +++ b/builder/vmware/common/step_upload_tools.go @@ -5,6 +5,7 @@ package common import ( "context" + "errors" "fmt" "os" @@ -33,7 +34,7 @@ func (c *StepUploadTools) Run(ctx context.Context, state multistep.StateBag) mul if c.RemoteType == "esx5" { if err := driver.ToolsInstall(); err != nil { - state.Put("error", fmt.Errorf("unable to mount VMware Tools ISO, check the 'guest_os_type'")) + state.Put("error", errors.New("unable to mount VMware Tools ISO, check the 'guest_os_type'")) } return multistep.ActionContinue } @@ -42,7 +43,7 @@ func (c *StepUploadTools) Run(ctx context.Context, state multistep.StateBag) mul tools_source := state.Get("tools_upload_source").(string) ui := state.Get("ui").(packersdk.Ui) - ui.Say(fmt.Sprintf("Uploading VMware Tools (%s)...", c.ToolsUploadFlavor)) + ui.Sayf("Uploading VMware Tools (%s)...", c.ToolsUploadFlavor) f, err := os.Open(tools_source) if err != nil { state.Put("error", fmt.Errorf("error opening VMware Tools ISO: %s", err)) @@ -55,14 +56,14 @@ func (c *StepUploadTools) Run(ctx context.Context, state multistep.StateBag) mul } c.ToolsUploadPath, err = interpolate.Render(c.ToolsUploadPath, &c.Ctx) if err != nil { - err := fmt.Errorf("error preparing upload path: %s", err) + err = fmt.Errorf("error preparing upload path: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } if err := comm.Upload(c.ToolsUploadPath, f, nil); err != nil { - err := fmt.Errorf("error uploading vmware tools: %s", err) + err = fmt.Errorf("error uploading vmware tools: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/common/step_upload_vmx.go b/builder/vmware/common/step_upload_vmx.go index 7e29ef92..579e585d 100644 --- a/builder/vmware/common/step_upload_vmx.go +++ b/builder/vmware/common/step_upload_vmx.go @@ -33,7 +33,9 @@ func (c *StepUploadVMX) Run(ctx context.Context, state multistep.StateBag) multi } } if err := remoteDriver.ReloadVM(); err != nil { - ui.Error(fmt.Sprintf("error reloading virtual machine: %s", err)) + err = fmt.Errorf("error reloading virtual machine: %s", err) + state.Put("error", err) + ui.Errorf(err.Error()) } } diff --git a/builder/vmware/common/step_vnc_boot_command.go b/builder/vmware/common/step_vnc_boot_command.go index 7a63ce8c..c2fb7e69 100644 --- a/builder/vmware/common/step_vnc_boot_command.go +++ b/builder/vmware/common/step_vnc_boot_command.go @@ -44,9 +44,9 @@ func (s *StepVNCBootCommand) Run(ctx context.Context, state multistep.StateBag) conn := state.Get("vnc_conn").(*vnc.ClientConn) defer conn.Close() - // Wait the for the vm to boot. + // Wait the for the virtual machine to boot. if int64(s.Config.BootWait) > 0 { - ui.Say(fmt.Sprintf("Waiting %s for boot...", s.Config.BootWait.String())) + ui.Sayf("Waiting %s for boot...", s.Config.BootWait.String()) select { case <-time.After(s.Config.BootWait): break @@ -73,7 +73,7 @@ func (s *StepVNCBootCommand) Run(ctx context.Context, state multistep.StateBag) flatBootCommand := s.Config.FlatBootCommand() command, err := interpolate.Render(flatBootCommand, &s.Ctx) if err != nil { - err := fmt.Errorf("error preparing boot command: %s", err) + err = fmt.Errorf("error preparing boot command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -88,7 +88,7 @@ func (s *StepVNCBootCommand) Run(ctx context.Context, state multistep.StateBag) } if err := seq.Do(ctx, d); err != nil { - err := fmt.Errorf("error running boot command: %s", err) + err = fmt.Errorf("error running boot command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/common/step_vnc_connect.go b/builder/vmware/common/step_vnc_connect.go index 18d66dca..0ed2be27 100644 --- a/builder/vmware/common/step_vnc_connect.go +++ b/builder/vmware/common/step_vnc_connect.go @@ -42,6 +42,7 @@ func (s *StepVNCConnect) Run(ctx context.Context, state multistep.StateBag) mult } if err != nil { + err = fmt.Errorf("error connecting to VNC: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -57,7 +58,7 @@ func (s *StepVNCConnect) ConnectVNCOverWebsocketClient(state multistep.StateBag) // Acquire websocket ticket ticket, err := driver.AcquireVNCOverWebsocketTicket() if err != nil { - err := fmt.Errorf("error acquiring VNC over websocket ticket: %s", err) + err = fmt.Errorf("error acquiring VNC over websocket ticket: %s", err) state.Put("error", err) return nil, err } @@ -74,13 +75,13 @@ func (s *StepVNCConnect) ConnectVNCOverWebsocketClient(state multistep.StateBag) log.Printf("[DEBUG] websocket url: %s", websocketUrl) u, err := url.Parse(websocketUrl) if err != nil { - err := fmt.Errorf("error parsing websocket url: %s", err) + err = fmt.Errorf("error parsing websocket url: %s", err) state.Put("error", err) return nil, err } origin, err := url.Parse("http://localhost") if err != nil { - err := fmt.Errorf("error parsing websocket origin url: %s", err) + err = fmt.Errorf("error parsing websocket origin url: %s", err) state.Put("error", err) return nil, err } diff --git a/builder/vmware/common/tools_config.go b/builder/vmware/common/tools_config.go index 5d187128..9f442464 100644 --- a/builder/vmware/common/tools_config.go +++ b/builder/vmware/common/tools_config.go @@ -6,6 +6,7 @@ package common import ( + "errors" "fmt" "slices" "strings" @@ -52,7 +53,7 @@ func (c *ToolsConfig) Prepare(ctx *interpolate.Context) []error { var errs []error if c.ToolsSourcePath != "" && c.ToolsUploadFlavor == "" { - errs = append(errs, fmt.Errorf("provide either 'tools_upload_flavor' or 'tools_upload_path' with 'tools_source_path'")) + errs = append(errs, errors.New("provide either 'tools_upload_flavor' or 'tools_upload_path' with 'tools_source_path'")) } else if c.ToolsUploadFlavor != "" && !slices.Contains(allowedToolsFlavorValues, c.ToolsUploadFlavor) { errs = append(errs, fmt.Errorf("invalid 'tools_upload_flavor' specified: %s; must be one of %s", c.ToolsUploadFlavor, strings.Join(allowedToolsFlavorValues, ", "))) } else { diff --git a/builder/vmware/iso/step_create_vmx.go b/builder/vmware/iso/step_create_vmx.go index be51057d..3104a35d 100644 --- a/builder/vmware/iso/step_create_vmx.go +++ b/builder/vmware/iso/step_create_vmx.go @@ -81,7 +81,7 @@ func (s *stepCreateVMX) Run(ctx context.Context, state multistep.StateBag) multi isoPath = relativeIsoPath } - ui.Say("Building and writing VMX file") + ui.Say("Generating the .vmx file...") vmxTemplate := DefaultVMXTemplate if config.VMXTemplatePath != "" { @@ -212,6 +212,7 @@ func (s *stepCreateVMX) Run(ctx context.Context, state multistep.StateBag) multi // read network map configuration into a NetworkNameMapper. netmap, err := driver.NetworkMapper() if err != nil { + err := fmt.Errorf("error reading network map configuration: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt @@ -399,7 +400,7 @@ func (s *stepCreateVMX) Run(ctx context.Context, state multistep.StateBag) multi // Write the vmxData to the vmxPath vmxPath := filepath.Join(vmxDir, config.VMName+".vmx") if err := common.WriteVMX(vmxPath, vmxData); err != nil { - err := fmt.Errorf("error creating VMX file: %s", err) + err = fmt.Errorf("error creating VMX file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt diff --git a/builder/vmware/iso/step_create_vmx_test.go b/builder/vmware/iso/step_create_vmx_test.go index 81a08613..29940858 100644 --- a/builder/vmware/iso/step_create_vmx_test.go +++ b/builder/vmware/iso/step_create_vmx_test.go @@ -6,6 +6,7 @@ package iso import ( "bytes" "encoding/json" + "errors" "fmt" "io" "os" @@ -23,7 +24,7 @@ import ( func createFloppyOutput(prefix string) (string, map[string]string, error) { f, err := tmp.File(prefix) if err != nil { - return "", map[string]string{}, fmt.Errorf("unable to create temp file") + return "", map[string]string{}, errors.New("unable to create temp file") } f.Close() @@ -129,7 +130,7 @@ func TestAccStepCreateVmx_SerialFile(t *testing.T) { } _, err := os.Stat(tmpfile.Name()) if err != nil { - return fmt.Errorf("VMware builder did not create a file for serial port: %s", err) + return fmt.Errorf("Unable to create a file for serial port: %s", err) } return nil }, @@ -182,7 +183,7 @@ func TestStepCreateVmx_SerialPort(t *testing.T) { } _, err := os.Stat(output) if err != nil { - return fmt.Errorf("VMware builder did not create a file for serial port: %s", err) + return fmt.Errorf("Unable to create a file for serial port: %s", err) } // check the output data, err := readFloppyOutput(output) @@ -244,7 +245,7 @@ func TestStepCreateVmx_ParallelPort(t *testing.T) { } _, err := os.Stat(output) if err != nil { - return fmt.Errorf("VMware builder did not create a file for serial port: %s", err) + return fmt.Errorf("Unable to create a file for serial port: %s", err) } // check the output data, err := readFloppyOutput(output) @@ -298,7 +299,7 @@ func TestStepCreateVmx_Usb(t *testing.T) { } _, err := os.Stat(output) if err != nil { - return fmt.Errorf("VMware builder did not create a file for serial port: %s", err) + return fmt.Errorf("Unable to create a file for serial port: %s", err) } // check the output data, err := readFloppyOutput(output) @@ -358,7 +359,7 @@ func TestStepCreateVmx_Sound(t *testing.T) { } _, err := os.Stat(output) if err != nil { - return fmt.Errorf("VMware builder did not create a file for serial port: %s", err) + return fmt.Errorf("Unable to create a file for serial port: %s", err) } // check the output data, err := readFloppyOutput(output) diff --git a/builder/vmware/vmx/config.go b/builder/vmware/vmx/config.go index eeefc4b8..d9ce5080 100644 --- a/builder/vmware/vmx/config.go +++ b/builder/vmware/vmx/config.go @@ -7,6 +7,7 @@ package vmx import ( + "errors" "fmt" "os" @@ -37,7 +38,7 @@ type Config struct { vmwcommon.DiskConfig `mapstructure:",squash"` // By default Packer creates a 'full' clone of the virtual machine // specified in source_path. The resultant virtual machine is fully - // independant from the parent it was cloned from. + // independent from the parent it was cloned from. // // Setting linked to true instead causes Packer to create the virtual // machine as a 'linked' clone. Linked clones use and require ongoing @@ -111,7 +112,7 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { if c.RemoteType == "" { if c.SourcePath == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("source_path is blank, but is required")) + errs = packersdk.MultiErrorAppend(errs, errors.New("'source_path' is blank, but is required")) } else { if _, err := os.Stat(c.SourcePath); err != nil { errs = packersdk.MultiErrorAppend(errs, @@ -145,7 +146,7 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { if c.RemoteType == "" && c.Format == "vmx" { // if we're building locally and want a vmx, there's nothing to export. // Set skip export flag here to keep the export step from attempting - // an unneded export + // an unneeded export c.SkipExport = true } diff --git a/builder/vmware/vmx/step_clone_vmx.go b/builder/vmware/vmx/step_clone_vmx.go index dba2400b..4b780113 100644 --- a/builder/vmware/vmx/step_clone_vmx.go +++ b/builder/vmware/vmx/step_clone_vmx.go @@ -38,7 +38,7 @@ func (s *StepCloneVMX) Run(ctx context.Context, state multistep.StateBag) multis // Set the path we want for the new .vmx file and clone vmxPath := filepath.Join(*s.OutputDir, s.VMName+".vmx") - ui.Say("Cloning source VM...") + ui.Say("Cloning source virtual machine...") log.Printf("Cloning from: %s", s.Path) log.Printf("Cloning to: %s", vmxPath) diff --git a/docs-partials/builder/vmware/vmx/Config-not-required.mdx b/docs-partials/builder/vmware/vmx/Config-not-required.mdx index 8269b5aa..1bff27cc 100644 --- a/docs-partials/builder/vmware/vmx/Config-not-required.mdx +++ b/docs-partials/builder/vmware/vmx/Config-not-required.mdx @@ -2,7 +2,7 @@ - `linked` (bool) - By default Packer creates a 'full' clone of the virtual machine specified in source_path. The resultant virtual machine is fully - independant from the parent it was cloned from. + independent from the parent it was cloned from. Setting linked to true instead causes Packer to create the virtual machine as a 'linked' clone. Linked clones use and require ongoing