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  }