github.com/emate/packer@v0.8.1-0.20150625195101-fe0fde195dc6/helper/communicator/step_connect_winrm.go (about) 1 package communicator 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "time" 8 9 "github.com/mitchellh/multistep" 10 "github.com/mitchellh/packer/communicator/winrm" 11 "github.com/mitchellh/packer/packer" 12 ) 13 14 // StepConnectWinRM is a multistep Step implementation that waits for WinRM 15 // to become available. It gets the connection information from a single 16 // configuration when creating the step. 17 // 18 // Uses: 19 // ui packer.Ui 20 // 21 // Produces: 22 // communicator packer.Communicator 23 type StepConnectWinRM struct { 24 // All the fields below are documented on StepConnect 25 Config *Config 26 Host func(multistep.StateBag) (string, error) 27 WinRMConfig func(multistep.StateBag) (*WinRMConfig, error) 28 } 29 30 func (s *StepConnectWinRM) Run(state multistep.StateBag) multistep.StepAction { 31 ui := state.Get("ui").(packer.Ui) 32 33 var comm packer.Communicator 34 var err error 35 36 cancel := make(chan struct{}) 37 waitDone := make(chan bool, 1) 38 go func() { 39 ui.Say("Waiting for WinRM to become available...") 40 comm, err = s.waitForWinRM(state, cancel) 41 waitDone <- true 42 }() 43 44 log.Printf("Waiting for WinRM, up to timeout: %s", s.Config.WinRMTimeout) 45 timeout := time.After(s.Config.WinRMTimeout) 46 WaitLoop: 47 for { 48 // Wait for either WinRM to become available, a timeout to occur, 49 // or an interrupt to come through. 50 select { 51 case <-waitDone: 52 if err != nil { 53 ui.Error(fmt.Sprintf("Error waiting for WinRM: %s", err)) 54 return multistep.ActionHalt 55 } 56 57 ui.Say("Connected to WinRM!") 58 state.Put("communicator", comm) 59 break WaitLoop 60 case <-timeout: 61 err := fmt.Errorf("Timeout waiting for WinRM.") 62 state.Put("error", err) 63 ui.Error(err.Error()) 64 close(cancel) 65 return multistep.ActionHalt 66 case <-time.After(1 * time.Second): 67 if _, ok := state.GetOk(multistep.StateCancelled); ok { 68 // The step sequence was cancelled, so cancel waiting for WinRM 69 // and just start the halting process. 70 close(cancel) 71 log.Println("Interrupt detected, quitting waiting for WinRM.") 72 return multistep.ActionHalt 73 } 74 } 75 } 76 77 return multistep.ActionContinue 78 } 79 80 func (s *StepConnectWinRM) Cleanup(multistep.StateBag) { 81 } 82 83 func (s *StepConnectWinRM) waitForWinRM(state multistep.StateBag, cancel <-chan struct{}) (packer.Communicator, error) { 84 var comm packer.Communicator 85 for { 86 select { 87 case <-cancel: 88 log.Println("[INFO] WinRM wait cancelled. Exiting loop.") 89 return nil, errors.New("WinRM wait cancelled") 90 case <-time.After(5 * time.Second): 91 } 92 93 host, err := s.Host(state) 94 if err != nil { 95 log.Printf("[DEBUG] Error getting WinRM host: %s", err) 96 continue 97 } 98 port := s.Config.WinRMPort 99 100 user := s.Config.WinRMUser 101 password := s.Config.WinRMPassword 102 if s.WinRMConfig != nil { 103 config, err := s.WinRMConfig(state) 104 if err != nil { 105 log.Printf("[DEBUG] Error getting WinRM config: %s", err) 106 continue 107 } 108 109 if config.Username != "" { 110 user = config.Username 111 } 112 if config.Password != "" { 113 password = config.Password 114 } 115 } 116 117 log.Println("[INFO] Attempting WinRM connection...") 118 comm, err = winrm.New(&winrm.Config{ 119 Host: host, 120 Port: port, 121 Username: user, 122 Password: password, 123 Timeout: s.Config.WinRMTimeout, 124 }) 125 if err != nil { 126 log.Printf("[ERROR] WinRM connection err: %s", err) 127 continue 128 } 129 130 break 131 } 132 133 return comm, nil 134 }