func (self *StepFindVdi) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) client := state.Get("client").(xsclient.XenAPIClient) // Ignore if VdiName is not specified if self.VdiName == "" { return multistep.ActionContinue } vdis, err := client.GetVdiByNameLabel(self.VdiName) switch { case len(vdis) == 0: ui.Error(fmt.Sprintf("Couldn't find a VDI named '%s'", self.VdiName)) return multistep.ActionHalt case len(vdis) > 1: ui.Error(fmt.Sprintf("Found more than one VDI with name '%s'. Name must be unique", self.VdiName)) return multistep.ActionHalt } vdi := vdis[0] vdiUuid, err := vdi.GetUuid() if err != nil { ui.Error(fmt.Sprintf("Unable to get UUID of VDI '%s': %s", self.VdiName, err.Error())) return multistep.ActionHalt } state.Put(self.VdiUuidKey, vdiUuid) return multistep.ActionContinue }
func (s *StepCreateSwitch) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) ui.Say("Creating internal switch...") var blockBuffer bytes.Buffer blockBuffer.WriteString("Invoke-Command -scriptblock {$TestSwitch = Get-VMSwitch -Name '") blockBuffer.WriteString(s.SwitchName) blockBuffer.WriteString("' -ErrorAction SilentlyContinue; if ($TestSwitch.Count -EQ 0){New-VMSwitch -Name '") blockBuffer.WriteString(s.SwitchName) blockBuffer.WriteString("' -SwitchType Internal}}") err := driver.HypervManage(blockBuffer.String()) if err != nil { err := fmt.Errorf("Error creating switch: %s", err) state.Put("error", err) ui.Error(err.Error()) s.SwitchName = "" return multistep.ActionHalt } // Set the final name in the state bag so others can use it state.Put("SwitchName", s.SwitchName) return multistep.ActionContinue }
func (s *StepOutputDir) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) if _, err := os.Stat(s.Path); err == nil && s.Force { ui.Say("Deleting previous output directory...") os.RemoveAll(s.Path) } // Create the directory if err := os.MkdirAll(s.Path, 0755); err != nil { state.Put("error", err) return multistep.ActionHalt } // Make sure we can write in the directory f, err := os.Create(filepath.Join(s.Path, "_packer_perm_check")) if err != nil { err = fmt.Errorf("Couldn't write to output directory: %s", err) state.Put("error", err) return multistep.ActionHalt } f.Close() os.Remove(f.Name()) return multistep.ActionContinue }
// Run executes the Packer build step that updates the gsutil utility to the // latest version available. // // This step is required to prevent the image creation process from hanging; // the image creation process utilizes the gcimagebundle cli tool which will // prompt to update gsutil if a newer version is available. func (s *StepUpdateGsutil) Run(state multistep.StateBag) multistep.StepAction { comm := state.Get("communicator").(packer.Communicator) config := state.Get("config").(*Config) ui := state.Get("ui").(packer.Ui) sudoPrefix := "" if config.SSHUsername != "root" { sudoPrefix = "sudo " } gsutilUpdateCmd := "/usr/local/bin/gsutil update -n -f" cmd := new(packer.RemoteCmd) cmd.Command = fmt.Sprintf("%s%s", sudoPrefix, gsutilUpdateCmd) ui.Say("Updating gsutil...") err := cmd.StartWithUi(comm, ui) if err == nil && cmd.ExitStatus != 0 { err = fmt.Errorf( "gsutil update exited with non-zero exit status: %d", cmd.ExitStatus) } if err != nil { err := fmt.Errorf("Error updating gsutil: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*config) driver := state.Get("driver").(hypervcommon.Driver) ui := state.Get("ui").(packer.Ui) errorMsg := "Error mounting dvd drive: %s" vmName := state.Get("vmName").(string) isoPath := config.RawSingleISOUrl ui.Say("Mounting dvd drive...") var blockBuffer bytes.Buffer blockBuffer.WriteString("Invoke-Command -scriptblock {Set-VMDvdDrive -VMName '") blockBuffer.WriteString(vmName) blockBuffer.WriteString("' -Path '") blockBuffer.WriteString(isoPath) blockBuffer.WriteString("'}") err := driver.HypervManage(blockBuffer.String()) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } s.path = isoPath return multistep.ActionContinue }
func (s *stepCreateDisk) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) name := config.VMName + "." + strings.ToLower(config.Format) path := filepath.Join(config.OutputDir, name) command := []string{ "create", "-f", config.Format, path, fmt.Sprintf("%vM", config.DiskSize), } if config.DiskImage == true { return multistep.ActionContinue } ui.Say("Creating hard drive...") if err := driver.QemuImg(command...); err != nil { err := fmt.Errorf("Error creating hard drive: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } state.Put("disk_filename", name) return multistep.ActionContinue }
func (s *stepAttachISO) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(parallelscommon.Driver) isoPath := state.Get("iso_path").(string) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) // Attach the disk to the cdrom0 device. We couldn't use a separated device because it is failed to boot in PD9 [GH-1667] ui.Say("Attaching ISO to the default CD/DVD ROM device...") command := []string{ "set", vmName, "--device-set", "cdrom0", "--image", isoPath, "--enable", "--connect", } if err := driver.Prlctl(command...); err != nil { err := fmt.Errorf("Error attaching ISO: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set some state so we know to remove state.Put("attachedIso", true) return multistep.ActionContinue }
func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*DigitalOceanClient) ui := state.Get("ui").(packer.Ui) c := state.Get("config").(config) sshKeyId := state.Get("ssh_key_id").(uint) ui.Say("Creating droplet...") // Some random droplet name as it's temporary name := fmt.Sprintf("packer-%s", hex.EncodeToString(identifier.NewUUID().Raw())) // Create the droplet based on configuration dropletId, err := client.CreateDroplet(name, c.SizeID, c.ImageID, c.RegionID, sshKeyId) if err != nil { err := fmt.Errorf("Error creating droplet: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // We use this in cleanup s.dropletId = dropletId // Store the droplet id for later state.Put("droplet_id", dropletId) return multistep.ActionContinue }
func (s *StepConfigureVlan) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) errorMsg := "Error configuring vlan: %s" vmName := state.Get("vmName").(string) switchName := state.Get("SwitchName").(string) vlanId := s.VlanId switchVlanId := s.SwitchVlanId ui.Say("Configuring vlan...") if switchVlanId != "" { err := driver.SetNetworkAdapterVlanId(switchName, vlanId) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } } if vlanId != "" { err := driver.SetVirtualMachineVlanId(vmName, vlanId) if err != nil { err := fmt.Errorf(errorMsg, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } } return multistep.ActionContinue }
func (s *StepUploadVersion) Run(state multistep.StateBag) multistep.StepAction { comm := state.Get("communicator").(packer.Communicator) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) if s.Path == "" { log.Println("VBoxVersionFile is empty. Not uploading.") return multistep.ActionContinue } version, err := driver.Version() if err != nil { state.Put("error", fmt.Errorf("Error reading version for metadata upload: %s", err)) return multistep.ActionHalt } ui.Say(fmt.Sprintf("Uploading VirtualBox version info (%s)", version)) var data bytes.Buffer data.WriteString(version) if err := comm.Upload(s.Path, &data); err != nil { state.Put("error", fmt.Errorf("Error uploading VirtualBox version: %s", err)) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *StepAttachParallelsTools) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) // If we're not attaching the guest additions then just return if s.ParallelsToolsMode != ParallelsToolsModeAttach { log.Println("Not attaching parallels tools since we're uploading.") return multistep.ActionContinue } // Get the Paralells Tools path on the host machine parallelsToolsPath := state.Get("parallels_tools_path").(string) // Attach the guest additions to the computer ui.Say("Attaching Parallels Tools ISO onto IDE controller...") command := []string{ "set", vmName, "--device-add", "cdrom", "--image", parallelsToolsPath, } if err := driver.Prlctl(command...); err != nil { err := fmt.Errorf("Error attaching Parallels Tools: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set some state so we know to remove state.Put("attachedToolsIso", true) return multistep.ActionContinue }
func (s *StepWaitForRackConnect) Run(state multistep.StateBag) multistep.StepAction { if !s.Wait { return multistep.ActionContinue } config := state.Get("config").(Config) server := state.Get("server").(*servers.Server) ui := state.Get("ui").(packer.Ui) // 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(fmt.Sprintf( "Waiting for server (%s) to become RackConnect ready...", server.ID)) for { server, err = servers.Get(computeClient, server.ID).Extract() if err != nil { return multistep.ActionHalt } if server.Metadata["rackconnect_automation_status"] == "DEPLOYED" { state.Put("server", server) break } time.Sleep(2 * time.Second) } return multistep.ActionContinue }
func (s *stepCreateDroplet) Run(state multistep.StateBag) multistep.StepAction { client := state.Get("client").(*DigitalOceanClient) ui := state.Get("ui").(packer.Ui) c := state.Get("config").(config) sshKeyId := state.Get("ssh_key_id").(uint) ui.Say("Creating droplet...") // Create the droplet based on configuration dropletId, err := client.CreateDroplet(c.DropletName, c.SizeID, c.ImageID, c.RegionID, sshKeyId) if err != nil { err := fmt.Errorf("Error creating droplet: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // We use this in cleanup s.dropletId = dropletId // Store the droplet id for later state.Put("droplet_id", dropletId) return multistep.ActionContinue }
func (self *StepForwardPortOverSSH) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("commonconfig").(CommonConfig) ui := state.Get("ui").(packer.Ui) // Find a free local port: l, sshHostPort := FindPort(self.HostPortMin, self.HostPortMax) if l == nil || sshHostPort == 0 { ui.Error("Error: unable to find free host port. Try providing a larger range [host_port_min, host_port_max]") return multistep.ActionHalt } ui.Say(fmt.Sprintf("Creating a local port forward over SSH on local port %d", sshHostPort)) remotePort, _ := self.RemotePort(state) remoteDest, _ := self.RemoteDest(state) go ssh_port_forward(l, remotePort, remoteDest, config.HostIp, config.Username, config.Password) ui.Say(fmt.Sprintf("Port forward setup. %d ---> %s:%d on %s", sshHostPort, remoteDest, remotePort, config.HostIp)) // Provide the local port to future steps. state.Put(self.ResultKey, sshHostPort) return multistep.ActionContinue }
func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction { ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packer.Ui) amis := state.Get("amis").(map[string]string) if len(s.Tags) > 0 { for region, ami := range amis { ui.Say(fmt.Sprintf("Adding tags to AMI (%s)...", ami)) var ec2Tags []*ec2.Tag for key, value := range s.Tags { ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"", key, value)) ec2Tags = append(ec2Tags, &ec2.Tag{Key: &key, Value: &value}) } regionconn := ec2.New(&aws.Config{ Credentials: ec2conn.Config.Credentials, Region: region, }) _, err := regionconn.CreateTags(&ec2.CreateTagsInput{ Resources: []*string{&ami}, Tags: ec2Tags, }) if err != nil { err := fmt.Errorf("Error adding tags to AMI (%s): %s", ami, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } } } return multistep.ActionContinue }
func (s *StepHTTPServer) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("commonconfig").(CommonConfig) ui := state.Get("ui").(packer.Ui) var httpPort uint = 0 if config.HTTPDir == "" { state.Put("http_port", httpPort) return multistep.ActionContinue } s.l, httpPort = FindPort(config.HTTPPortMin, config.HTTPPortMax) if s.l == nil || httpPort == 0 { ui.Error("Error: unable to find free HTTP server port. Try providing a larger range [http_port_min, http_port_max]") return multistep.ActionHalt } ui.Say(fmt.Sprintf("Starting HTTP server on port %d", httpPort)) // Start the HTTP server and run it in the background fileServer := http.FileServer(http.Dir(config.HTTPDir)) server := &http.Server{ Addr: fmt.Sprintf(":%d", httpPort), Handler: IPSnooper{ ch: s.Chan, handler: fileServer, }, } go server.Serve(s.l) // Save the address into the state so it can be accessed in the future state.Put("http_port", httpPort) return multistep.ActionContinue }
func (s *StepExport) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) if !config.Export { return multistep.ActionContinue } driver := state.Get("driver").(Driver) containerId := state.Get("container_id").(string) ui := state.Get("ui").(packer.Ui) // Open the file that we're going to write to f, err := os.Create(config.ExportPath) if err != nil { err := fmt.Errorf("Error creating output file: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Exporting the container") if err := driver.Export(containerId, f); err != nil { f.Close() os.Remove(f.Name()) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } f.Close() return multistep.ActionContinue }
func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) tempDir := state.Get("temp_dir").(string) ui := state.Get("ui").(packer.Ui) runConfig := ContainerConfig{ Image: config.Image, RunCommand: config.RunCommand, Volumes: make(map[string]string), } for host, container := range config.Volumes { runConfig.Volumes[host] = container } runConfig.Volumes[tempDir] = "/packer-files" ui.Say("Starting docker container...") containerId, err := driver.StartContainer(&runConfig) if err != nil { err := fmt.Errorf("Error running container: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Save the container ID s.containerId = containerId state.Put("container_id", s.containerId) ui.Message(fmt.Sprintf("Container ID: %s", s.containerId)) return multistep.ActionContinue }
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 } } } }
// Run executes the Packer build step that tears down a GCE instance. func (s *StepTeardownInstance) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) name := config.InstanceName if name == "" { return multistep.ActionHalt } ui.Say("Deleting instance...") instanceLog, _ := driver.GetSerialPortOutput(config.Zone, name) state.Put("instance_log", instanceLog) 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)) return multistep.ActionHalt } ui.Message("Instance has been deleted!") state.Put("instance_name", "") return multistep.ActionContinue }
func (s *StepCloneVMX) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(vmwcommon.Driver) ui := state.Get("ui").(packer.Ui) vmxPath := filepath.Join(s.OutputDir, s.VMName+".vmx") ui.Say("Cloning source VM...") log.Printf("Cloning from: %s", s.Path) log.Printf("Cloning to: %s", vmxPath) if err := driver.Clone(vmxPath, s.Path); err != nil { state.Put("error", err) return multistep.ActionHalt } vmxData, err := vmwcommon.ReadVMX(vmxPath) if err != nil { state.Put("error", err) return multistep.ActionHalt } diskName, ok := vmxData["scsi0:0.filename"] if !ok { err := fmt.Errorf("Root disk filename could not be found!") state.Put("error", err) return multistep.ActionHalt } state.Put("full_disk_path", filepath.Join(s.OutputDir, diskName)) state.Put("vmx_path", vmxPath) return multistep.ActionContinue }
func (s *stepResizeDisk) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) path := filepath.Join(config.OutputDir, config.VMName) command := []string{ "resize", path, fmt.Sprintf("%vM", config.DiskSize), } if config.DiskImage == false { return multistep.ActionContinue } ui.Say("Resizing hard drive...") if err := driver.QemuImg(command...); err != nil { err := fmt.Errorf("Error creating hard drive: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *stepCopyDisk) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*config) driver := state.Get("driver").(Driver) isoPath := state.Get("iso_path").(string) ui := state.Get("ui").(packer.Ui) path := filepath.Join(config.OutputDir, fmt.Sprintf("%s.%s", config.VMName, strings.ToLower(config.Format))) command := []string{ "convert", "-f", config.Format, isoPath, path, } if config.DiskImage == false { return multistep.ActionContinue } ui.Say("Copying hard drive...") if err := driver.QemuImg(command...); err != nil { err := fmt.Errorf("Error creating hard drive: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ui := state.Get("ui").(packer.Ui) // Find an open VNC port. Note that this can still fail later on // because we have to release the port at some point. But this does its // best. msg := fmt.Sprintf("Looking for available port between %d and %d on %s", config.VNCPortMin, config.VNCPortMax, config.VNCBindAddress) ui.Say(msg) log.Printf(msg) var vncPort uint portRange := int(config.VNCPortMax - config.VNCPortMin) for { if portRange > 0 { vncPort = uint(rand.Intn(portRange)) + config.VNCPortMin } else { vncPort = config.VNCPortMin } log.Printf("Trying port: %d", vncPort) l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.VNCBindAddress, vncPort)) if err == nil { defer l.Close() break } } log.Printf("Found available VNC port: %d on IP: %s", vncPort, config.VNCBindAddress) state.Put("vnc_port", vncPort) state.Put("vnc_ip", config.VNCBindAddress) return multistep.ActionContinue }
func (s *StepConnect) Run(state multistep.StateBag) multistep.StepAction { typeMap := map[string]multistep.Step{ "none": nil, "ssh": &StepConnectSSH{ Config: s.Config, Host: s.Host, SSHConfig: s.SSHConfig, SSHPort: s.SSHPort, }, "winrm": &StepConnectWinRM{ Config: s.Config, Host: s.Host, WinRMConfig: s.WinRMConfig, WinRMPort: s.SSHPort, }, } for k, v := range s.CustomConnect { typeMap[k] = v } step, ok := typeMap[s.Config.Type] if !ok { state.Put("error", fmt.Errorf("unknown communicator type: %s", s.Config.Type)) return multistep.ActionHalt } if step == nil { log.Printf("[INFO] communicator disabled, will not connect") return multistep.ActionContinue } s.substep = step return s.substep.Run(state) }
func (s *StepPreValidate) Run(state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packer.Ui) if s.ForceDeregister { ui.Say("Force Deregister flag found, skipping prevalidating AMI Name") return multistep.ActionContinue } ec2conn := state.Get("ec2").(*ec2.EC2) ui.Say("Prevalidating AMI Name...") resp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ Filters: []*ec2.Filter{&ec2.Filter{ Name: aws.String("name"), Values: []*string{aws.String(s.DestAmiName)}, }}}) if err != nil { err := fmt.Errorf("Error querying AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } if len(resp.Images) > 0 { err := fmt.Errorf("Error: name conflicts with an existing AMI: %s", *resp.Images[0].ImageId) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
// NewRunnerWithPauseFn returns a multistep.Runner that runs steps augmented // with support for -debug and -on-error command line arguments. With -debug it // puts the multistep.DebugPauseFn that will pause execution between steps into // the state under the key "pauseFn". func NewRunnerWithPauseFn(steps []multistep.Step, config PackerConfig, ui packer.Ui, state multistep.StateBag) multistep.Runner { runner, pauseFn := newRunner(steps, config, ui) if pauseFn != nil { state.Put("pauseFn", pauseFn) } return runner }
func (s *StepConnectDocker) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) containerId := state.Get("container_id").(string) driver := state.Get("driver").(Driver) tempDir := state.Get("temp_dir").(string) // Get the version so we can pass it to the communicator version, err := driver.Version() if err != nil { state.Put("error", err) return multistep.ActionHalt } // Create the communicator that talks to Docker via various // os/exec tricks. comm := &Communicator{ ContainerId: containerId, HostDir: tempDir, ContainerDir: "/packer-files", Version: version, Config: config, } state.Put("communicator", comm) return multistep.ActionContinue }
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 *StepForwardSSH) Run(state multistep.StateBag) multistep.StepAction { driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) vmName := state.Get("vmName").(string) guestPort := s.CommConfig.Port() sshHostPort := guestPort if !s.SkipNatMapping { log.Printf("Looking for available communicator (SSH, WinRM, etc) port between %d and %d", s.HostPortMin, s.HostPortMax) offset := 0 portRange := int(s.HostPortMax - s.HostPortMin) if portRange > 0 { // Have to check if > 0 to avoid a panic offset = rand.Intn(portRange) } for { sshHostPort = offset + int(s.HostPortMin) if sshHostPort >= int(s.HostPortMax) { offset = 0 sshHostPort = int(s.HostPortMin) } log.Printf("Trying port: %d", sshHostPort) l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", sshHostPort)) if err == nil { defer l.Close() break } offset++ } // Create a forwarded port mapping to the VM ui.Say(fmt.Sprintf("Creating forwarded port mapping for communicator (SSH, WinRM, etc) (host port %d)", sshHostPort)) command := []string{ "modifyvm", vmName, "--natpf1", "delete", "packercomm", } driver.VBoxManage(command...) command = []string{ "modifyvm", vmName, "--natpf1", fmt.Sprintf("packercomm,tcp,127.0.0.1,%d,,%d", sshHostPort, guestPort), } if err := driver.VBoxManage(command...); err != nil { err := fmt.Errorf("Error creating port forwarding rule: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } } // Save the port we're using so that future steps can use it state.Put("sshHostPort", sshHostPort) return multistep.ActionContinue }