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