github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/utils/ssh/ssh_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package ssh_test 5 6 import ( 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strings" 11 12 gc "launchpad.net/gocheck" 13 14 "launchpad.net/juju-core/cmd" 15 "launchpad.net/juju-core/testing/testbase" 16 "launchpad.net/juju-core/utils/ssh" 17 ) 18 19 type SSHCommandSuite struct { 20 testbase.LoggingSuite 21 testbin string 22 fakessh string 23 fakescp string 24 client ssh.Client 25 } 26 27 var _ = gc.Suite(&SSHCommandSuite{}) 28 29 const echoCommandScript = "#!/bin/sh\necho $0 \"$@\" | tee $0.args" 30 31 func (s *SSHCommandSuite) SetUpTest(c *gc.C) { 32 s.LoggingSuite.SetUpTest(c) 33 s.testbin = c.MkDir() 34 s.fakessh = filepath.Join(s.testbin, "ssh") 35 s.fakescp = filepath.Join(s.testbin, "scp") 36 err := ioutil.WriteFile(s.fakessh, []byte(echoCommandScript), 0755) 37 c.Assert(err, gc.IsNil) 38 err = ioutil.WriteFile(s.fakescp, []byte(echoCommandScript), 0755) 39 c.Assert(err, gc.IsNil) 40 s.PatchEnvPathPrepend(s.testbin) 41 s.client, err = ssh.NewOpenSSHClient() 42 c.Assert(err, gc.IsNil) 43 s.PatchValue(ssh.DefaultIdentities, nil) 44 } 45 46 func (s *SSHCommandSuite) command(args ...string) *ssh.Cmd { 47 return s.commandOptions(args, nil) 48 } 49 50 func (s *SSHCommandSuite) commandOptions(args []string, opts *ssh.Options) *ssh.Cmd { 51 return s.client.Command("localhost", args, opts) 52 } 53 54 func (s *SSHCommandSuite) assertCommandArgs(c *gc.C, cmd *ssh.Cmd, expected string) { 55 out, err := cmd.Output() 56 c.Assert(err, gc.IsNil) 57 c.Assert(strings.TrimSpace(string(out)), gc.Equals, expected) 58 } 59 60 func (s *SSHCommandSuite) TestDefaultClient(c *gc.C) { 61 ssh.InitDefaultClient() 62 c.Assert(ssh.DefaultClient, gc.FitsTypeOf, &ssh.OpenSSHClient{}) 63 s.PatchEnvironment("PATH", "") 64 ssh.InitDefaultClient() 65 c.Assert(ssh.DefaultClient, gc.FitsTypeOf, &ssh.GoCryptoClient{}) 66 } 67 68 func (s *SSHCommandSuite) TestCommandSSHPass(c *gc.C) { 69 // First create a fake sshpass, but don't set $SSHPASS 70 fakesshpass := filepath.Join(s.testbin, "sshpass") 71 err := ioutil.WriteFile(fakesshpass, []byte(echoCommandScript), 0755) 72 s.assertCommandArgs(c, s.command("echo", "123"), 73 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no localhost echo 123", 74 ) 75 // Now set $SSHPASS. 76 s.PatchEnvironment("SSHPASS", "anyoldthing") 77 s.assertCommandArgs(c, s.command("echo", "123"), 78 fakesshpass+" -e ssh -o StrictHostKeyChecking no -o PasswordAuthentication no localhost echo 123", 79 ) 80 // Finally, remove sshpass from $PATH. 81 err = os.Remove(fakesshpass) 82 c.Assert(err, gc.IsNil) 83 s.assertCommandArgs(c, s.command("echo", "123"), 84 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no localhost echo 123", 85 ) 86 } 87 88 func (s *SSHCommandSuite) TestCommand(c *gc.C) { 89 s.assertCommandArgs(c, s.command("echo", "123"), 90 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no localhost echo 123", 91 ) 92 } 93 94 func (s *SSHCommandSuite) TestCommandEnablePTY(c *gc.C) { 95 var opts ssh.Options 96 opts.EnablePTY() 97 s.assertCommandArgs(c, s.commandOptions([]string{"echo", "123"}, &opts), 98 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no -t -t localhost echo 123", 99 ) 100 } 101 102 func (s *SSHCommandSuite) TestCommandAllowPasswordAuthentication(c *gc.C) { 103 var opts ssh.Options 104 opts.AllowPasswordAuthentication() 105 s.assertCommandArgs(c, s.commandOptions([]string{"echo", "123"}, &opts), 106 s.fakessh+" -o StrictHostKeyChecking no localhost echo 123", 107 ) 108 } 109 110 func (s *SSHCommandSuite) TestCommandIdentities(c *gc.C) { 111 var opts ssh.Options 112 opts.SetIdentities("x", "y") 113 s.assertCommandArgs(c, s.commandOptions([]string{"echo", "123"}, &opts), 114 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no -i x -i y localhost echo 123", 115 ) 116 } 117 118 func (s *SSHCommandSuite) TestCommandPort(c *gc.C) { 119 var opts ssh.Options 120 opts.SetPort(2022) 121 s.assertCommandArgs(c, s.commandOptions([]string{"echo", "123"}, &opts), 122 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no -p 2022 localhost echo 123", 123 ) 124 } 125 126 func (s *SSHCommandSuite) TestCopy(c *gc.C) { 127 var opts ssh.Options 128 opts.EnablePTY() 129 opts.AllowPasswordAuthentication() 130 opts.SetIdentities("x", "y") 131 opts.SetPort(2022) 132 err := s.client.Copy([]string{"/tmp/blah", "foo@bar.com:baz"}, nil, &opts) 133 c.Assert(err, gc.IsNil) 134 out, err := ioutil.ReadFile(s.fakescp + ".args") 135 c.Assert(err, gc.IsNil) 136 // EnablePTY has no effect for Copy 137 c.Assert(string(out), gc.Equals, s.fakescp+" -o StrictHostKeyChecking no -i x -i y -P 2022 /tmp/blah foo@bar.com:baz\n") 138 139 // Try passing extra args 140 err = s.client.Copy([]string{"/tmp/blah", "foo@bar.com:baz"}, []string{"-r", "-v"}, &opts) 141 c.Assert(err, gc.IsNil) 142 out, err = ioutil.ReadFile(s.fakescp + ".args") 143 c.Assert(err, gc.IsNil) 144 c.Assert(string(out), gc.Equals, s.fakescp+" -o StrictHostKeyChecking no -i x -i y -P 2022 -r -v /tmp/blah foo@bar.com:baz\n") 145 } 146 147 func (s *SSHCommandSuite) TestCommandClientKeys(c *gc.C) { 148 clientKeysDir := c.MkDir() 149 defer ssh.ClearClientKeys() 150 err := ssh.LoadClientKeys(clientKeysDir) 151 c.Assert(err, gc.IsNil) 152 ck := filepath.Join(clientKeysDir, "juju_id_rsa") 153 var opts ssh.Options 154 opts.SetIdentities("x", "y") 155 s.assertCommandArgs(c, s.commandOptions([]string{"echo", "123"}, &opts), 156 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no -i x -i y -i "+ck+" localhost echo 123", 157 ) 158 } 159 160 func (s *SSHCommandSuite) TestCommandError(c *gc.C) { 161 var opts ssh.Options 162 err := ioutil.WriteFile(s.fakessh, []byte("#!/bin/sh\nexit 42"), 0755) 163 c.Assert(err, gc.IsNil) 164 command := s.client.Command("ignored", []string{"echo", "foo"}, &opts) 165 err = command.Run() 166 c.Assert(cmd.IsRcPassthroughError(err), gc.Equals, true) 167 } 168 169 func (s *SSHCommandSuite) TestCommandDefaultIdentities(c *gc.C) { 170 var opts ssh.Options 171 tempdir := c.MkDir() 172 def1 := filepath.Join(tempdir, "def1") 173 def2 := filepath.Join(tempdir, "def2") 174 s.PatchValue(ssh.DefaultIdentities, []string{def1, def2}) 175 // If no identities are specified, then the defaults aren't added. 176 s.assertCommandArgs(c, s.commandOptions([]string{"echo", "123"}, &opts), 177 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no localhost echo 123", 178 ) 179 // If identities are specified, then the defaults are must added. 180 // Only the defaults that exist on disk will be added. 181 err := ioutil.WriteFile(def2, nil, 0644) 182 c.Assert(err, gc.IsNil) 183 opts.SetIdentities("x", "y") 184 s.assertCommandArgs(c, s.commandOptions([]string{"echo", "123"}, &opts), 185 s.fakessh+" -o StrictHostKeyChecking no -o PasswordAuthentication no -i x -i y -i "+def2+" localhost echo 123", 186 ) 187 }