github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/commands/ssh.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package commands 5 6 import ( 7 "fmt" 8 "strconv" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 "github.com/juju/gnuflag" 13 "github.com/juju/utils/ssh" 14 15 jujucmd "github.com/juju/juju/cmd" 16 "github.com/juju/juju/cmd/modelcmd" 17 jujussh "github.com/juju/juju/network/ssh" 18 ) 19 20 var usageSSHSummary = ` 21 Initiates an SSH session or executes a command on a Juju machine.`[1:] 22 23 var usageSSHDetails = ` 24 The machine is identified by the <target> argument which is either a 'unit 25 name' or a 'machine id'. Both are obtained in the output to "juju status". If 26 'user' is specified then the connection is made to that user account; 27 otherwise, the default 'ubuntu' account, created by Juju, is used. 28 29 The optional command is executed on the remote machine, and any output is sent 30 back to the user. If no command is specified, then an interactive shell session 31 will be initiated. 32 33 When "juju ssh" is executed without a terminal attached, e.g. when piping the 34 output of another command into it, then the default behavior is to not allocate 35 a pseudo-terminal (pty) for the ssh session; otherwise a pty is allocated. This 36 behavior can be overridden by explicitly specifying the behavior with 37 "--pty=true" or "--pty=false". 38 39 The SSH host keys of the target are verified. The --no-host-key-checks option 40 can be used to disable these checks. Use of this option is not recommended as 41 it opens up the possibility of a man-in-the-middle attack. 42 43 The default identity known to Juju and used by this command is ~/.ssh/id_rsa 44 45 Options can be passed to the local OpenSSH client (ssh) on platforms 46 where it is available. This is done by inserting them between the target and 47 a possible remote command. Refer to the ssh man page for an explanation 48 of those options. 49 50 Examples: 51 Connect to machine 0: 52 53 juju ssh 0 54 55 Connect to machine 1 and run command 'uname -a': 56 57 juju ssh 1 uname -a 58 59 Connect to a mysql unit: 60 61 juju ssh mysql/0 62 63 Connect to a jenkins unit as user jenkins: 64 65 juju ssh jenkins@jenkins/0 66 67 Connect to a mysql unit with an identity not known to juju (ssh option -i): 68 69 juju ssh mysql/0 -i ~/.ssh/my_private_key echo hello 70 71 See also: 72 scp` 73 74 func newSSHCommand( 75 hostChecker jujussh.ReachableChecker, 76 isTerminal func(interface{}) bool, 77 ) cmd.Command { 78 c := new(sshCommand) 79 c.setHostChecker(hostChecker) 80 c.isTerminal = isTerminal 81 return modelcmd.Wrap(c) 82 } 83 84 // sshCommand is responsible for launching a ssh shell on a given unit or machine. 85 type sshCommand struct { 86 SSHCommon 87 isTerminal func(interface{}) bool 88 pty autoBoolValue 89 } 90 91 func (c *sshCommand) SetFlags(f *gnuflag.FlagSet) { 92 c.SSHCommon.SetFlags(f) 93 f.Var(&c.pty, "pty", "Enable pseudo-tty allocation") 94 } 95 96 func (c *sshCommand) Info() *cmd.Info { 97 return jujucmd.Info(&cmd.Info{ 98 Name: "ssh", 99 Args: "<[user@]target> [openssh options] [command]", 100 Purpose: usageSSHSummary, 101 Doc: usageSSHDetails, 102 }) 103 } 104 105 func (c *sshCommand) Init(args []string) error { 106 if len(args) == 0 { 107 return errors.Errorf("no target name specified") 108 } 109 c.Target, c.Args = args[0], args[1:] 110 return nil 111 } 112 113 // Run resolves c.Target to a machine, to the address of a i 114 // machine or unit forks ssh passing any arguments provided. 115 func (c *sshCommand) Run(ctx *cmd.Context) error { 116 err := c.initRun() 117 if err != nil { 118 return errors.Trace(err) 119 } 120 defer c.cleanupRun() 121 122 target, err := c.resolveTarget(c.Target) 123 if err != nil { 124 return err 125 } 126 127 var pty bool 128 if c.pty.b != nil { 129 pty = *c.pty.b 130 } else { 131 // Flag was not specified: create a pty 132 // on the remote side iff this process 133 // has a terminal. 134 isTerminal := isTerminal 135 if c.isTerminal != nil { 136 isTerminal = c.isTerminal 137 } 138 pty = isTerminal(ctx.Stdin) 139 } 140 141 options, err := c.getSSHOptions(pty, target) 142 if err != nil { 143 return err 144 } 145 146 cmd := ssh.Command(target.userHost(), c.Args, options) 147 cmd.Stdin = ctx.Stdin 148 cmd.Stdout = ctx.Stdout 149 cmd.Stderr = ctx.Stderr 150 return cmd.Run() 151 } 152 153 // autoBoolValue is like gnuflag.boolValue, but remembers 154 // whether or not a value has been set, so its behaviour 155 // can be determined dynamically, during command execution. 156 type autoBoolValue struct { 157 b *bool 158 } 159 160 func (b *autoBoolValue) Set(s string) error { 161 v, err := strconv.ParseBool(s) 162 if err != nil { 163 return err 164 } 165 b.b = &v 166 return nil 167 } 168 169 func (b *autoBoolValue) Get() interface{} { 170 if b.b != nil { 171 return *b.b 172 } 173 return b.b // nil 174 } 175 176 func (b *autoBoolValue) String() string { 177 if b.b != nil { 178 return fmt.Sprint(*b.b) 179 } 180 return "<auto>" 181 } 182 183 func (b *autoBoolValue) IsBoolFlag() bool { return true }