package common import ( "bytes" "context" "fmt" "net/url" "os" "os/exec" "runtime" "strings" "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" ) // This step exports a VM built on ESXi using ovftool // // Uses: // display_name string type StepExport struct { Format string SkipExport bool VMName string OVFToolOptions []string OutputDir string } func GetOVFTool() string { ovftool := "ovftool" if runtime.GOOS == "windows" { ovftool = "ovftool.exe" } if _, err := exec.LookPath(ovftool); err != nil { return "" } return ovftool } func (s *StepExport) generateArgs(c *DriverConfig, displayName string, hidePassword bool) []string { password := url.QueryEscape(c.RemotePassword) username := url.QueryEscape(c.RemoteUser) if hidePassword { password = "****" } args := []string{ "--noSSLVerify=true", "--skipManifestCheck", "-tt=" + s.Format, "vi://" + username + ":" + password + "@" + c.RemoteHost + "/" + displayName, s.OutputDir, } return append(s.OVFToolOptions, args...) } func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { c := state.Get("driverConfig").(*DriverConfig) ui := state.Get("ui").(packer.Ui) // Skip export if requested if s.SkipExport { ui.Say("Skipping export of virtual machine...") return multistep.ActionContinue } if c.RemoteType != "esx5" { ui.Say("Skipping export of virtual machine (export is allowed only for ESXi)...") return multistep.ActionContinue } ovftool := GetOVFTool() if ovftool == "" { err := fmt.Errorf("Error ovftool not found") state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Export the VM if s.OutputDir == "" { s.OutputDir = s.VMName + "." + s.Format } os.MkdirAll(s.OutputDir, 0755) ui.Say("Exporting virtual machine...") var displayName string if v, ok := state.GetOk("display_name"); ok { displayName = v.(string) } ui.Message(fmt.Sprintf("Executing: %s %s", ovftool, strings.Join(s.generateArgs(c, displayName, true), " "))) var out bytes.Buffer cmd := exec.Command(ovftool, s.generateArgs(c, displayName, false)...) cmd.Stdout = &out if err := cmd.Run(); err != nil { err := fmt.Errorf("Error exporting virtual machine: %s\n%s\n", err, out.String()) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } ui.Message(out.String()) return multistep.ActionContinue } func (s *StepExport) Cleanup(state multistep.StateBag) {}