github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/utils/ssh/ssh_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // +build !windows 5 6 package ssh_test 7 8 import ( 9 "bytes" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "strings" 15 16 "github.com/juju/cmd" 17 "github.com/juju/testing" 18 jc "github.com/juju/testing/checkers" 19 gc "gopkg.in/check.v1" 20 21 "github.com/juju/juju/utils/ssh" 22 ) 23 24 const ( 25 echoCommand = "/bin/echo" 26 echoScript = "#!/bin/sh\n" + echoCommand + " $0 \"$@\" | /usr/bin/tee $0.args" 27 ) 28 29 type SSHCommandSuite struct { 30 testing.IsolationSuite 31 originalPath string 32 testbin string 33 fakessh string 34 fakescp string 35 client ssh.Client 36 } 37 38 var _ = gc.Suite(&SSHCommandSuite{}) 39 40 func (s *SSHCommandSuite) SetUpTest(c *gc.C) { 41 s.IsolationSuite.SetUpTest(c) 42 s.testbin = c.MkDir() 43 s.fakessh = filepath.Join(s.testbin, "ssh") 44 s.fakescp = filepath.Join(s.testbin, "scp") 45 err := ioutil.WriteFile(s.fakessh, []byte(echoScript), 0755) 46 c.Assert(err, jc.ErrorIsNil) 47 err = ioutil.WriteFile(s.fakescp, []byte(echoScript), 0755) 48 c.Assert(err, jc.ErrorIsNil) 49 s.PatchEnvPathPrepend(s.testbin) 50 s.client, err = ssh.NewOpenSSHClient() 51 c.Assert(err, jc.ErrorIsNil) 52 s.PatchValue(ssh.DefaultIdentities, nil) 53 } 54 55 func (s *SSHCommandSuite) command(args ...string) *ssh.Cmd { 56 return s.commandOptions(args, nil) 57 } 58 59 func (s *SSHCommandSuite) commandOptions(args []string, opts *ssh.Options) *ssh.Cmd { 60 return s.client.Command("localhost", args, opts) 61 } 62 63 func (s *SSHCommandSuite) assertCommandArgs(c *gc.C, cmd *ssh.Cmd, expected string) { 64 out, err := cmd.Output() 65 c.Assert(err, jc.ErrorIsNil) 66 c.Assert(strings.TrimSpace(string(out)), gc.Equals, expected) 67 } 68 69 func (s *SSHCommandSuite) TestDefaultClient(c *gc.C) { 70 ssh.InitDefaultClient() 71 c.Assert(ssh.DefaultClient, gc.FitsTypeOf, &ssh.OpenSSHClient{}) 72 s.PatchEnvironment("PATH", "") 73 ssh.InitDefaultClient() 74 c.Assert(ssh.DefaultClient, gc.FitsTypeOf, &ssh.GoCryptoClient{}) 75 } 76 77 func (s *SSHCommandSuite) TestCommandSSHPass(c *gc.C) { 78 // First create a fake sshpass, but don't set $SSHPASS 79 fakesshpass := filepath.Join(s.testbin, "sshpass") 80 err := ioutil.WriteFile(fakesshpass, []byte(echoScript), 0755) 81 s.assertCommandArgs(c, s.command(echoCommand, "123"), 82 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 localhost %s 123", 83 s.fakessh, echoCommand), 84 ) 85 // Now set $SSHPASS. 86 s.PatchEnvironment("SSHPASS", "anyoldthing") 87 s.assertCommandArgs(c, s.command(echoCommand, "123"), 88 fmt.Sprintf("%s -e ssh -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 localhost %s 123", 89 fakesshpass, echoCommand), 90 ) 91 // Finally, remove sshpass from $PATH. 92 err = os.Remove(fakesshpass) 93 c.Assert(err, jc.ErrorIsNil) 94 s.assertCommandArgs(c, s.command(echoCommand, "123"), 95 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 localhost %s 123", 96 s.fakessh, echoCommand), 97 ) 98 } 99 100 func (s *SSHCommandSuite) TestCommand(c *gc.C) { 101 s.assertCommandArgs(c, s.command(echoCommand, "123"), 102 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 localhost %s 123", 103 s.fakessh, echoCommand), 104 ) 105 } 106 107 func (s *SSHCommandSuite) TestCommandEnablePTY(c *gc.C) { 108 var opts ssh.Options 109 opts.EnablePTY() 110 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 111 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 -t -t localhost %s 123", 112 s.fakessh, echoCommand), 113 ) 114 } 115 116 func (s *SSHCommandSuite) TestCommandSetKnownHostsFile(c *gc.C) { 117 var opts ssh.Options 118 opts.SetKnownHostsFile("/tmp/known hosts") 119 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 120 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 -o UserKnownHostsFile \"/tmp/known hosts\" localhost %s 123", 121 s.fakessh, echoCommand), 122 ) 123 } 124 125 func (s *SSHCommandSuite) TestCommandAllowPasswordAuthentication(c *gc.C) { 126 var opts ssh.Options 127 opts.AllowPasswordAuthentication() 128 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 129 fmt.Sprintf("%s -o StrictHostKeyChecking no -o ServerAliveInterval 30 localhost %s 123", 130 s.fakessh, echoCommand), 131 ) 132 } 133 134 func (s *SSHCommandSuite) TestCommandIdentities(c *gc.C) { 135 var opts ssh.Options 136 opts.SetIdentities("x", "y") 137 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 138 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 -i x -i y localhost %s 123", 139 s.fakessh, echoCommand), 140 ) 141 } 142 143 func (s *SSHCommandSuite) TestCommandPort(c *gc.C) { 144 var opts ssh.Options 145 opts.SetPort(2022) 146 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 147 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 -p 2022 localhost %s 123", 148 s.fakessh, echoCommand), 149 ) 150 } 151 152 func (s *SSHCommandSuite) TestCopy(c *gc.C) { 153 var opts ssh.Options 154 opts.EnablePTY() 155 opts.AllowPasswordAuthentication() 156 opts.SetIdentities("x", "y") 157 opts.SetPort(2022) 158 err := s.client.Copy([]string{"/tmp/blah", "foo@bar.com:baz"}, &opts) 159 c.Assert(err, jc.ErrorIsNil) 160 out, err := ioutil.ReadFile(s.fakescp + ".args") 161 c.Assert(err, jc.ErrorIsNil) 162 // EnablePTY has no effect for Copy 163 c.Assert(string(out), gc.Equals, s.fakescp+" -o StrictHostKeyChecking no -o ServerAliveInterval 30 -i x -i y -P 2022 /tmp/blah foo@bar.com:baz\n") 164 165 // Try passing extra args 166 err = s.client.Copy([]string{"/tmp/blah", "foo@bar.com:baz", "-r", "-v"}, &opts) 167 c.Assert(err, jc.ErrorIsNil) 168 out, err = ioutil.ReadFile(s.fakescp + ".args") 169 c.Assert(err, jc.ErrorIsNil) 170 c.Assert(string(out), gc.Equals, s.fakescp+" -o StrictHostKeyChecking no -o ServerAliveInterval 30 -i x -i y -P 2022 /tmp/blah foo@bar.com:baz -r -v\n") 171 172 // Try interspersing extra args 173 err = s.client.Copy([]string{"-r", "/tmp/blah", "-v", "foo@bar.com:baz"}, &opts) 174 c.Assert(err, jc.ErrorIsNil) 175 out, err = ioutil.ReadFile(s.fakescp + ".args") 176 c.Assert(err, jc.ErrorIsNil) 177 c.Assert(string(out), gc.Equals, s.fakescp+" -o StrictHostKeyChecking no -o ServerAliveInterval 30 -i x -i y -P 2022 -r /tmp/blah -v foo@bar.com:baz\n") 178 } 179 180 func (s *SSHCommandSuite) TestCommandClientKeys(c *gc.C) { 181 defer overrideGenerateKey(c).Restore() 182 clientKeysDir := c.MkDir() 183 defer ssh.ClearClientKeys() 184 err := ssh.LoadClientKeys(clientKeysDir) 185 c.Assert(err, jc.ErrorIsNil) 186 ck := filepath.Join(clientKeysDir, "juju_id_rsa") 187 var opts ssh.Options 188 opts.SetIdentities("x", "y") 189 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 190 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 -i x -i y -i %s localhost %s 123", 191 s.fakessh, ck, echoCommand), 192 ) 193 } 194 195 func (s *SSHCommandSuite) TestCommandError(c *gc.C) { 196 var opts ssh.Options 197 err := ioutil.WriteFile(s.fakessh, []byte("#!/bin/sh\nexit 42"), 0755) 198 c.Assert(err, jc.ErrorIsNil) 199 command := s.client.Command("ignored", []string{echoCommand, "foo"}, &opts) 200 err = command.Run() 201 c.Assert(cmd.IsRcPassthroughError(err), jc.IsTrue) 202 } 203 204 func (s *SSHCommandSuite) TestCommandDefaultIdentities(c *gc.C) { 205 var opts ssh.Options 206 tempdir := c.MkDir() 207 def1 := filepath.Join(tempdir, "def1") 208 def2 := filepath.Join(tempdir, "def2") 209 s.PatchValue(ssh.DefaultIdentities, []string{def1, def2}) 210 // If no identities are specified, then the defaults aren't added. 211 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 212 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 localhost %s 123", 213 s.fakessh, echoCommand), 214 ) 215 // If identities are specified, then the defaults are must added. 216 // Only the defaults that exist on disk will be added. 217 err := ioutil.WriteFile(def2, nil, 0644) 218 c.Assert(err, jc.ErrorIsNil) 219 opts.SetIdentities("x", "y") 220 s.assertCommandArgs(c, s.commandOptions([]string{echoCommand, "123"}, &opts), 221 fmt.Sprintf("%s -o StrictHostKeyChecking no -o PasswordAuthentication no -o ServerAliveInterval 30 -i x -i y -i %s localhost %s 123", 222 s.fakessh, def2, echoCommand), 223 ) 224 } 225 226 func (s *SSHCommandSuite) TestCopyReader(c *gc.C) { 227 client := &fakeClient{} 228 r := bytes.NewBufferString("<data>") 229 230 err := ssh.TestCopyReader(client, "foo@bar.com:baz", "/tmp/blah", r, nil) 231 c.Assert(err, jc.ErrorIsNil) 232 233 client.checkCalls(c, "foo@bar.com:baz", []string{"cat - > /tmp/blah"}, nil, nil, "Command") 234 client.impl.checkCalls(c, r, nil, nil, "SetStdio", "Start", "Wait") 235 }