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  }