github.com/dahs81/otto@v0.2.1-0.20160126165905-6400716cf085/helper/vagrant/ssh.go (about) 1 package vagrant 2 3 import ( 4 "fmt" 5 "io" 6 "log" 7 "os" 8 "os/exec" 9 "strings" 10 ) 11 12 // SSHCache is a helper to cache the SSH connection info from Vagrant 13 // and use that for executing to avoid the overhead of loading Vagrant. 14 type SSHCache struct { 15 // Path is the path to where the SSH cache file should go 16 Path string 17 18 // Vagrant is the Vagrant instance we'll use to execute Vagrant commands. 19 Vagrant *Vagrant 20 } 21 22 // Exec executes SSH and opens a console. 23 // 24 // This will use the cached SSH info if it exists, or will otherwise 25 // drop into `vagrant ssh`. If cacheOkay is false, then it'll always go 26 // straight to `vagrant ssh`. 27 func (c *SSHCache) Exec(cacheOkay bool) error { 28 // If we have the cache file, use that 29 if _, err := os.Stat(c.Path); err == nil { 30 log.Printf("[DEBUG] ssh command: ssh -F " + c.Path + " default") 31 cmd := exec.Command("ssh", "-t", "-t", "-F", c.Path, "default") 32 cmd.Stdin = os.Stdin 33 cmd.Stdout = os.Stdout 34 cmd.Stderr = os.Stderr 35 if err := cmd.Start(); err != nil { 36 return err 37 } 38 if err := cmd.Wait(); err != nil { 39 return err 40 } 41 return nil 42 } 43 44 // Otherwise raw SSH 45 return c.Vagrant.Execute("ssh") 46 } 47 48 // Cache will execute "ssh-config" and cache the SSH info. 49 func (c *SSHCache) Cache() error { 50 // Callback that records the output 51 var result string 52 callback := func(o *Output) { 53 result = o.Data[0] 54 } 55 56 // We just copy the Vagrant instance so we can modify it without 57 // worrying about restoring stuff. We set the UI to nil so nothing 58 // goes to the UI, and we set a callback to read the SSH config from 59 // the machine-readable output. 60 vagrant := *c.Vagrant 61 vagrant.Ui = nil 62 vagrant.Callbacks = map[string]OutputCallback{ 63 "ssh-config": callback, 64 } 65 if err := vagrant.Execute("ssh-config"); err != nil { 66 return err 67 } 68 69 // If we have no output, it is an error 70 if result == "" { 71 return fmt.Errorf( 72 "No SSH info found in the output of Vagrant. This is a bug somewhere.\n" + 73 "Please re-run the command with OTTO_LOG=1 and report this as a bug.") 74 } 75 76 // Write the output to the cache 77 f, err := os.Create(c.Path) 78 if err != nil { 79 return err 80 } 81 defer f.Close() 82 if _, err := io.Copy(f, strings.NewReader(result)); err != nil { 83 return err 84 } 85 86 return nil 87 } 88 89 // Delete clears the cache. 90 func (c *SSHCache) Delete() error { 91 // We ignore the return value here because it'll happen if the 92 // file doesn't exist and we just don't care. 93 os.Remove(c.Path) 94 return nil 95 }