func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) ui.Say("Starting the virtual machine...") err := driver.Start(vmName) if err != nil { err := fmt.Errorf("Error starting vm: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } s.vmName = vmName if int64(s.BootWait) > 0 { ui.Say(fmt.Sprintf("Waiting %s for boot...", s.BootWait)) wait := time.After(s.BootWait) WAITLOOP: for { select { case <-wait: break WAITLOOP case <-time.After(1 * time.Second): if _, ok := state.GetOk(multistep.StateCancelled); ok { return multistep.ActionHalt } } } } return multistep.ActionContinue }
func (s *StepAttachFloppy) Run(state multistep.StateBag) multistep.StepAction { // Determine if we even have a floppy disk to attach var floppyPath string if floppyPathRaw, ok := state.GetOk("floppy_path"); ok { floppyPath = floppyPathRaw.(string) } else { log.Println("No floppy disk, not attaching.") return multistep.ActionContinue } driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) ui.Say("Attaching floppy disk...") // Create the floppy disk controller command := []string{ "set", vmName, "--device-add", "fdd", "--image", floppyPath, } if err := driver.Prlctl(command...); err != nil { state.Put("error", fmt.Errorf("Error adding floppy: %s", err)) return multistep.ActionHalt } // Track the path so that we can unregister it from Parallels later s.floppyPath = floppyPath return multistep.ActionContinue }
func (s *StepOutputDir) Cleanup(state multistep.StateBag) { if !s.cleanup { return } _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) if cancelled || halted { ui := state.Get("ui").(packer.Ui) ui.Say("Deleting output directory...") /* for i := 0; i < 5; i++ { err := os.RemoveAll(s.Path) if err == nil { break } log.Printf("Error removing output dir: %s", err) time.Sleep(2 * time.Second) } */ } }
func (s *StepOutputDir) Cleanup(state multistep.StateBag) { if !s.success { return } _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) if cancelled || halted { /* dir := state.Get("dir").(OutputDir) ui := state.Get("ui").(packer.Ui) exists, _ := dir.DirExists() if exists { ui.Say("Deleting output directory...") for i := 0; i < 5; i++ { err := dir.RemoveAll() if err == nil { break } log.Printf("Error removing output dir: %s", err) time.Sleep(2 * time.Second) } } */ } }
func cancelCallback(state multistep.StateBag) bool { cancel := false if _, ok := state.GetOk(multistep.StateCancelled); ok { cancel = true } return cancel }
func (s *StepCreateSourceMachine) Cleanup(state multistep.StateBag) { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) machineIdRaw, ok := state.GetOk("machine") if ok && machineIdRaw.(string) != "" { machineId := machineIdRaw.(string) ui.Say(fmt.Sprintf("Stopping source machine (%s)...", machineId)) err := driver.StopMachine(machineId) if err != nil { state.Put("error", fmt.Errorf("Problem stopping source machine: %s", err)) return } ui.Say(fmt.Sprintf("Waiting for source machine to stop (%s)...", machineId)) err = driver.WaitForMachineState(machineId, "stopped", 10*time.Minute) if err != nil { state.Put("error", fmt.Errorf("Problem waiting for source machine to stop: %s", err)) return } ui.Say(fmt.Sprintf("Deleting source machine (%s)...", machineId)) err = driver.DeleteMachine(machineId) if err != nil { state.Put("error", fmt.Errorf("Problem deleting source machine: %s", err)) return } } }
func (s *stepCreateVM) Cleanup(state multistep.StateBag) { if s.vmName == "" { return } driver := state.Get("driver").(vboxcommon.Driver) ui := state.Get("ui").(packer.Ui) config := state.Get("config").(*Config) _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) if (config.KeepRegistered) && (!cancelled && !halted) { ui.Say("Keeping virtual machine registered with VirtualBox host (keep_registered = true)") return } ui.Say("Unregistering and deleting virtual machine...") var err error = nil for i := 0; i < 5; i++ { err = driver.VBoxManage("unregistervm", s.vmName, "--delete") if err == nil { break } time.Sleep(1 * time.Second * time.Duration(i)) } if err != nil { ui.Error(fmt.Sprintf("Error deleting virtual machine: %s", err)) } }
func (s *stepCreateVersion) Cleanup(state multistep.StateBag) { client := state.Get("client").(*VagrantCloudClient) ui := state.Get("ui").(packer.Ui) box := state.Get("box").(*Box) version := state.Get("version").(*Version) _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) // Return if we didn't cancel or halt, and thus need // no cleanup if !cancelled && !halted { return } path := fmt.Sprintf("box/%s/version/%v", box.Tag, version.Version) ui.Say("Cleaning up version") ui.Message(fmt.Sprintf("Deleting version: %s", version.Version)) // No need for resp from the cleanup DELETE _, err := client.Delete(path) if err != nil { ui.Error(fmt.Sprintf("Error destroying version: %s", err)) } }
func (s *stepCreateVersion) Cleanup(state multistep.StateBag) { client := state.Get("client").(*VagrantCloudClient) ui := state.Get("ui").(packer.Ui) config := state.Get("config").(Config) box := state.Get("box").(*Box) // If we didn't save the version number, it likely doesn't exist or // already existed if s.number == 0 { ui.Message("Version was not created or previously existed, not deleting") return } _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) // Return if we didn't cancel or halt, and thus need // no cleanup if !cancelled && !halted { return } path := fmt.Sprintf("box/%s/version/%v", box.Tag, s.number) ui.Say("Cleaning up version") ui.Message(fmt.Sprintf("Deleting version: %s", config.Version)) // No need for resp from the cleanup DELETE _, err := client.Delete(path) if err != nil { ui.Error(fmt.Sprintf("Error destroying version: %s", err)) } }
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { config := state.Get("config").(*Config) var privateKey string var auth []gossh.AuthMethod if config.Comm.SSHPassword != "" { auth = []gossh.AuthMethod{ gossh.Password(config.Comm.SSHPassword), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(config.Comm.SSHPassword)), } } if config.Comm.SSHPrivateKey != "" { if priv, ok := state.GetOk("privateKey"); ok { privateKey = priv.(string) } signer, err := gossh.ParsePrivateKey([]byte(privateKey)) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } if err != nil { return nil, err } auth = append(auth, gossh.PublicKeys(signer)) } return &gossh.ClientConfig{ User: config.Comm.SSHUsername, Auth: auth, }, nil }
func (s *StepProvision) Run(state multistep.StateBag) multistep.StepAction { comm := s.Comm if comm == nil { comm = state.Get("communicator").(packer.Communicator) } hook := state.Get("hook").(packer.Hook) ui := state.Get("ui").(packer.Ui) // Run the provisioner in a goroutine so we can continually check // for cancellations... log.Println("Running the provision hook") errCh := make(chan error, 1) go func() { errCh <- hook.Run(packer.HookProvision, ui, comm, nil) }() for { select { case err := <-errCh: if err != nil { state.Put("error", err) return multistep.ActionHalt } return multistep.ActionContinue case <-time.After(1 * time.Second): if _, ok := state.GetOk(multistep.StateCancelled); ok { log.Println("Cancelling provisioning due to interrupt...") hook.Cancel() return multistep.ActionHalt } } } }
func (s *stepCreateProvider) Cleanup(state multistep.StateBag) { client := state.Get("client").(*VagrantCloudClient) ui := state.Get("ui").(packer.Ui) box := state.Get("box").(*Box) version := state.Get("version").(*Version) // If we didn't save the provider name, it likely doesn't exist if s.name == "" { ui.Say("Cleaning up provider") ui.Message("Provider was not created, not deleting") return } _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) // Return if we didn't cancel or halt, and thus need // no cleanup if !cancelled && !halted { return } ui.Say("Cleaning up provider") ui.Message(fmt.Sprintf("Deleting provider: %s", s.name)) path := fmt.Sprintf("box/%s/version/%v/provider/%s", box.Tag, version.Number, s.name) // No need for resp from the cleanup DELETE _, err := client.Delete(path) if err != nil { ui.Error(fmt.Sprintf("Error destroying provider: %s", err)) } }
func (s *stepUpdateState) Cleanup(state multistep.StateBag) { buildJob := state.Get("buildJob").(Job) ctx := state.Get("ctx").(gocontext.Context) mresult, ok := state.GetOk("scriptResult") if ok { result := mresult.(*backend.RunResult) var err error switch result.ExitCode { case 0: err = buildJob.Finish(FinishStatePassed) case 1: err = buildJob.Finish(FinishStateFailed) default: err = buildJob.Finish(FinishStateErrored) } if err != nil { context.LoggerFromContext(ctx).WithField("err", err).Error("couldn't mark job as finished") } } }
// Cleanup destroys the GCE instance created during the image creation process. func (s *StepCreateInstance) Cleanup(state multistep.StateBag) { nameRaw, ok := state.GetOk("instance_name") if !ok { return } name := nameRaw.(string) if name == "" { return } config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say("Deleting instance...") errCh, err := driver.DeleteInstance(config.Zone, name) if err == nil { select { case err = <-errCh: case <-time.After(config.stateTimeout): err = errors.New("time out while waiting for instance to delete") } } if err != nil { ui.Error(fmt.Sprintf( "Error deleting instance. Please delete it manually.\n\n"+ "Name: %s\n"+ "Error: %s", name, err)) } state.Put("instance_name", "") return }
func (s *stepCreateServer) Cleanup(state multistep.StateBag) { c := state.Get("config").(*Config) ui := state.Get("ui").(packer.Ui) ui.Say("Removing Server...") token := oneandone.SetToken(c.Token) //Create an API client api := oneandone.New(token, oneandone.BaseUrl) var serverId string if temp, ok := state.GetOk("server_id"); ok { serverId = temp.(string) } if serverId != "" { server, err := api.ShutdownServer(serverId, false) if err != nil { ui.Error(fmt.Sprintf("Error shutting down 1and1 server. Please destroy it manually: %s", serverId)) ui.Error(err.Error()) } err = api.WaitForState(server, "POWERED_OFF", 10, c.Retries) server, err = api.DeleteServer(server.Id, false) if err != nil { ui.Error(fmt.Sprintf("Error deleting 1and1 server. Please destroy it manually: %s", serverId)) ui.Error(err.Error()) } } }
func (s *StepMountFloppydrive) Run(state multistep.StateBag) multistep.StepAction { // Determine if we even have a floppy disk to attach var floppyPath string if floppyPathRaw, ok := state.GetOk("floppy_path"); ok { floppyPath = floppyPathRaw.(string) } else { log.Println("No floppy disk, not attaching.") return multistep.ActionContinue } // Hyper-V is really dumb and can't figure out the format of the file // without an extension, so we need to add the "vfd" extension to the // floppy. floppyPath, err := s.copyFloppy(floppyPath) if err != nil { state.Put("error", fmt.Errorf("Error preparing floppy: %s", err)) return multistep.ActionHalt } ui := state.Get("ui").(packer.Ui) ui.Say("Mounting floppy drive...") vmName := state.Get("vmName").(string) driver := state.Get("driver").(hypervcommon.Driver) err = mountFloppyDrive(driver, vmName, floppyPath) if err != nil { state.Put("error", fmt.Errorf("Error mounting floppy drive: %s", err)) return multistep.ActionHalt } // Track the path so that we can unregister it from Hyper-V later s.floppyPath = floppyPath return multistep.ActionContinue }
func (s *stepWaitForShutdown) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) stopCh := make(chan struct{}) defer close(stopCh) cancelCh := make(chan struct{}) go func() { for { if _, ok := state.GetOk(multistep.StateCancelled); ok { close(cancelCh) return } select { case <-stopCh: return case <-time.After(100 * time.Millisecond): } } }() ui.Say(s.Message) driver.WaitForShutdown(cancelCh) return multistep.ActionContinue }
func (s *stepRun) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmxPath := state.Get("vmx_path").(string) vncIp := state.Get("vnc_ip").(string) vncPort := state.Get("vnc_port").(uint) // Set the VMX path so that we know we started the machine s.bootTime = time.Now() s.vmxPath = vmxPath ui.Say("Starting virtual machine...") if config.Headless { 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 without a password to\n"+ "%s:%d", vncIp, vncPort)) } if remoteDriver, ok := driver.(RemoteDriver); ok { if err := remoteDriver.Register(vmxPath); err != nil { err := fmt.Errorf("Error registering VM: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } s.registered = true } if err := driver.Start(vmxPath, config.Headless); err != nil { err := fmt.Errorf("Error starting VM: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Wait the wait amount if int64(config.bootWait) > 0 { ui.Say(fmt.Sprintf("Waiting %s for boot...", config.bootWait.String())) wait := time.After(config.bootWait) WAITLOOP: for { select { case <-wait: break WAITLOOP case <-time.After(1 * time.Second): if _, ok := state.GetOk(multistep.StateCancelled); ok { return multistep.ActionHalt } } } } return multistep.ActionContinue }
func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) // Clear out the Packer-created forwarding rule ui.Say("Preparing to export machine...") ui.Message(fmt.Sprintf("Deleting forwarded port mapping for SSH (host port %d)", state.Get("sshHostPort"))) command := []string{"modifyvm", vmName, "--natpf1", "delete", "packerssh"} if err := driver.VBoxManage(command...); err != nil { err := fmt.Errorf("Error deleting port forwarding rule: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Remove the attached floppy disk, if it exists if _, ok := state.GetOk("floppy_path"); ok { ui.Message("Removing floppy drive...") command := []string{ "storageattach", vmName, "--storagectl", "Floppy Controller", "--port", "0", "--device", "0", "--medium", "none", } if err := driver.VBoxManage(command...); err != nil { state.Put("error", fmt.Errorf("Error removing floppy: %s", err)) return multistep.ActionHalt } } // Export the VM to an OVF outputPath := filepath.Join(config.OutputDir, vmName+"."+config.Format) command = []string{ "export", vmName, "--output", outputPath, } ui.Say("Exporting virtual machine...") err := driver.VBoxManage(command...) if err != nil { err := fmt.Errorf("Error exporting virtual machine: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } state.Put("exportPath", outputPath) return multistep.ActionContinue }
func (s *StepGetPassword) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(Config) ui := state.Get("ui").(packer.Ui) // Skip if we're not using winrm if s.Comm.Type != "winrm" { log.Printf("[INFO] Not using winrm communicator, skipping get password...") return multistep.ActionContinue } // If we already have a password, skip it if s.Comm.WinRMPassword != "" { ui.Say("Skipping waiting for password since WinRM password set...") return multistep.ActionContinue } // We need the v2 compute client computeClient, err := config.computeV2Client() if err != nil { err = fmt.Errorf("Error initializing compute client: %s", err) state.Put("error", err) return multistep.ActionHalt } ui.Say("Waiting for password since WinRM password is not set...") server := state.Get("server").(*servers.Server) var password string privateKey, err := ssh.ParseRawPrivateKey([]byte(state.Get("privateKey").(string))) if err != nil { err = fmt.Errorf("Error parsing private key: %s", err) state.Put("error", err) return multistep.ActionHalt } for ; password == "" && err == nil; password, err = servers.GetPassword(computeClient, server.ID).ExtractPassword(privateKey.(*rsa.PrivateKey)) { // Check for an interrupt in between attempts. if _, ok := state.GetOk(multistep.StateCancelled); ok { return multistep.ActionHalt } log.Printf("Retrying to get a administrator password evry 5 seconds.") time.Sleep(5 * time.Second) } ui.Message(fmt.Sprintf("Password retrieved!")) s.Comm.WinRMPassword = password // In debug-mode, we output the password if s.Debug { ui.Message(fmt.Sprintf( "Password (since debug is enabled) \"%s\"", s.Comm.WinRMPassword)) } return multistep.ActionContinue }
// Cleanup destroys the GCE instance created during the image creation process. func (s *StepCreateInstance) Cleanup(state multistep.StateBag) { nameRaw, ok := state.GetOk("instance_name") if !ok { return } name := nameRaw.(string) if name == "" { return } config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say("Deleting instance...") errCh, err := driver.DeleteInstance(config.Zone, name) if err == nil { select { case err = <-errCh: case <-time.After(config.stateTimeout): err = errors.New("time out while waiting for instance to delete") } } if err != nil { ui.Error(fmt.Sprintf( "Error deleting instance. Please delete it manually.\n\n"+ "Name: %s\n"+ "Error: %s", name, err)) } ui.Message("Instance has been deleted!") state.Put("instance_name", "") // Deleting the instance does not remove the boot disk. This cleanup removes // the disk. ui.Say("Deleting disk...") errCh, err = driver.DeleteDisk(config.Zone, config.DiskName) if err == nil { select { case err = <-errCh: case <-time.After(config.stateTimeout): err = errors.New("time out while waiting for disk to delete") } } if err != nil { ui.Error(fmt.Sprintf( "Error deleting disk. Please delete it manually.\n\n"+ "Name: %s\n"+ "Error: %s", config.InstanceName, err)) } ui.Message("Disk has been deleted!") return }
func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*config) driver := state.Get("driver").(vboxcommon.Driver) httpPort := state.Get("http_port").(uint) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) tplData := &bootCommandTemplateData{ "10.0.2.2", httpPort, config.VMName, } ui.Say("Typing the boot command...") for _, command := range config.BootCommand { command, err := config.tpl.Process(command, tplData) if err != nil { err := fmt.Errorf("Error preparing boot command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } for _, code := range scancodes(command) { if code == "wait" { time.Sleep(1 * time.Second) continue } if code == "wait5" { time.Sleep(5 * time.Second) continue } if code == "wait10" { time.Sleep(10 * time.Second) continue } // Since typing is sometimes so slow, we check for an interrupt // in between each character. if _, ok := state.GetOk(multistep.StateCancelled); ok { return multistep.ActionHalt } if err := driver.VBoxManage("controlvm", vmName, "keyboardputscancode", code); err != nil { err := fmt.Errorf("Error sending boot command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } } } return multistep.ActionContinue }
func (s *StepConfigureVMX) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) vmxPath := state.Get("vmx_path").(string) vmxContents, err := ioutil.ReadFile(vmxPath) if err != nil { err := fmt.Errorf("Error reading VMX file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } vmxData := ParseVMX(string(vmxContents)) // Set this so that no dialogs ever appear from Packer. vmxData["msg.autoanswer"] = "true" // Create a new UUID for this VM, since it is a new VM vmxData["uuid.action"] = "create" // Delete any generated addresses since we want to regenerate // them. Conflicting MAC addresses is a bad time. addrRegex := regexp.MustCompile(`(?i)^ethernet\d+\.generatedAddress`) for k, _ := range vmxData { if addrRegex.MatchString(k) { delete(vmxData, k) } } // Set custom data for k, v := range s.CustomData { log.Printf("Setting VMX: '%s' = '%s'", k, v) k = strings.ToLower(k) vmxData[k] = v } // Set a floppy disk, but only if we should if !s.SkipFloppy { // Set a floppy disk if we have one if floppyPathRaw, ok := state.GetOk("floppy_path"); ok { log.Println("Floppy path present, setting in VMX") vmxData["floppy0.present"] = "TRUE" vmxData["floppy0.filetype"] = "file" vmxData["floppy0.filename"] = floppyPathRaw.(string) } } if err := WriteVMX(vmxPath, vmxData); err != nil { err := fmt.Errorf("Error writing VMX file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *stepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) httpPort := state.Get("http_port").(uint) ui := state.Get("ui").(packer.Ui) vncPort := state.Get("vnc_port").(uint) // Connect to VNC ui.Say("Connecting to VM via VNC") nc, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", vncPort)) if err != nil { err := fmt.Errorf("Error connecting to VNC: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } defer nc.Close() c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: false}) if err != nil { err := fmt.Errorf("Error handshaking with VNC: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } defer c.Close() log.Printf("Connected to VNC desktop: %s", c.DesktopName) ctx := config.ctx ctx.Data = &bootCommandTemplateData{ "10.0.2.2", httpPort, config.VMName, } ui.Say("Typing the boot command over VNC...") for _, command := range config.BootCommand { command, err := interpolate.Render(command, &ctx) if err != nil { err := fmt.Errorf("Error preparing boot command: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Check for interrupts between typing things so we can cancel // since this isn't the fastest thing. if _, ok := state.GetOk(multistep.StateCancelled); ok { return multistep.ActionHalt } vncSendString(c, command) } return multistep.ActionContinue }
func (s *StepAttachFloppy) Run(state multistep.StateBag) multistep.StepAction { // Determine if we even have a floppy disk to attach var floppyPath string if floppyPathRaw, ok := state.GetOk("floppy_path"); ok { floppyPath = floppyPathRaw.(string) } else { log.Println("No floppy disk, not attaching.") return multistep.ActionContinue } // VirtualBox is really dumb and can't figure out the format of the file // without an extension, so we need to add the "vfd" extension to the // floppy. floppyPath, err := s.copyFloppy(floppyPath) if err != nil { state.Put("error", fmt.Errorf("Error preparing floppy: %s", err)) return multistep.ActionHalt } driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) ui.Say("Attaching floppy disk...") // Create the floppy disk controller command := []string{ "storagectl", vmName, "--name", "Floppy Controller", "--add", "floppy", } if err := driver.VBoxManage(command...); err != nil { state.Put("error", fmt.Errorf("Error creating floppy controller: %s", err)) return multistep.ActionHalt } // Attach the floppy to the controller command = []string{ "storageattach", vmName, "--storagectl", "Floppy Controller", "--port", "0", "--device", "0", "--type", "fdd", "--medium", floppyPath, } if err := driver.VBoxManage(command...); err != nil { state.Put("error", fmt.Errorf("Error attaching floppy: %s", err)) return multistep.ActionHalt } // Track the path so that we can unregister it from VirtualBox later s.floppyPath = floppyPath return multistep.ActionContinue }
func (s abortStep) Cleanup(state multistep.StateBag) { if _, ok := state.GetOk(multistep.StateCancelled); ok { s.ui.Error("Interrupted, aborting...") os.Exit(1) } if _, ok := state.GetOk(multistep.StateHalted); ok { s.ui.Error(fmt.Sprintf("Step %q failed, aborting...", typeName(s.step))) os.Exit(1) } s.step.Cleanup(state) }
func (s StepCleanVMX) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) vmxPath := state.Get("vmx_path").(string) ui.Say("Cleaning VMX prior to finishing up...") vmxData, err := ReadVMX(vmxPath) if err != nil { state.Put("error", fmt.Errorf("Error reading VMX: %s", err)) return multistep.ActionHalt } if _, ok := state.GetOk("floppy_path"); ok { // Delete the floppy0 entries so the floppy is no longer mounted ui.Message("Unmounting floppy from VMX...") for k, _ := range vmxData { if strings.HasPrefix(k, "floppy0.") { log.Printf("Deleting key: %s", k) delete(vmxData, k) } } vmxData["floppy0.present"] = "FALSE" } if isoPathRaw, ok := state.GetOk("iso_path"); ok { isoPath := isoPathRaw.(string) ui.Message("Detaching ISO from CD-ROM device...") devRe := regexp.MustCompile(`^ide\d:\d\.`) for k, _ := range vmxData { match := devRe.FindString(k) if match == "" { continue } filenameKey := match + "filename" if filename, ok := vmxData[filenameKey]; ok { if filename == isoPath { // Change the CD-ROM device back to auto-detect to eject vmxData[filenameKey] = "auto detect" vmxData[match+"devicetype"] = "cdrom-raw" } } } } // Rewrite the VMX if err := WriteVMX(vmxPath, vmxData); err != nil { state.Put("error", fmt.Errorf("Error writing VMX: %s", err)) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *StepConnectSSH) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) var comm packer.Communicator var err error cancel := make(chan struct{}) waitDone := make(chan bool, 1) go func() { ui.Say("Waiting for SSH to become available...") comm, err = s.waitForSSH(state, cancel) waitDone <- true }() log.Printf("[INFO] Waiting for SSH, up to timeout: %s", s.Config.SSHTimeout) timeout := time.After(s.Config.SSHTimeout) WaitLoop: for { // Wait for either SSH to become available, a timeout to occur, // or an interrupt to come through. select { case <-waitDone: if err != nil { ui.Error(fmt.Sprintf("Error waiting for SSH: %s", err)) state.Put("error", err) return multistep.ActionHalt } ui.Say("Connected to SSH!") state.Put("communicator", comm) break WaitLoop case <-timeout: err := fmt.Errorf("Timeout waiting for SSH.") state.Put("error", err) ui.Error(err.Error()) close(cancel) return multistep.ActionHalt case <-time.After(1 * time.Second): if _, ok := state.GetOk(multistep.StateCancelled); ok { // The step sequence was cancelled, so cancel waiting for SSH // and just start the halting process. close(cancel) log.Println("[WARN] Interrupt detected, quitting waiting for SSH.") return multistep.ActionHalt } } } return multistep.ActionContinue }
// steps should check config.ShouldKeepVM first before cleaning up the VM func (c CommonConfig) ShouldKeepVM(state multistep.StateBag) bool { switch c.KeepVM { case "always": return true case "never": return false case "on_success": // only keep instance if build was successful _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) return !(cancelled || halted) default: panic(fmt.Sprintf("Unknown keep_vm value '%s'", c.KeepVM)) } }
/* Wait waits for up to Timeout duration, checking an optional Predicate every PredicateInterval duration. The first run of Predicate is immediately after Wait is called. If the command is interrupted by the user, then an InterruptedError is returned. If Predicate is not nil, a timeout leads to TimeoutError being returned, and a successful Predicate run leads to nil being returned. If Predicate is nil, a timeout is not an error, and nil is returned. */ func (wait InterruptibleWait) Wait(state multistep.StateBag) error { predicateResult := make(chan PredicateResult, 1) stopWaiting := make(chan struct{}) defer close(stopWaiting) if wait.Predicate != nil { go func() { for { if complete, err := wait.Predicate(); err != nil || complete { predicateResult <- PredicateResult{complete, err} return } select { case <-time.After(wait.PredicateInterval): continue case <-stopWaiting: return } } }() } timeout := time.After(wait.Timeout) for { // wait for either install to complete/error, // an interrupt to come through, or a timeout to occur if _, ok := state.GetOk(multistep.StateCancelled); ok { return InterruptedError{} } select { case result := <-predicateResult: return result.err case <-time.After(1 * time.Second): continue case <-timeout: if wait.Predicate != nil { return TimeoutError{} } else { return nil } } } }