22
23
jc "launchpad.net/juju-core/testing/checkers"
23
24
"launchpad.net/juju-core/testing/testbase"
24
25
"launchpad.net/juju-core/utils"
26
"launchpad.net/juju-core/utils/ssh"
27
29
type storageSuite struct {
28
30
testbase.LoggingSuite
31
34
var _ = gc.Suite(&storageSuite{})
33
func sshCommandTesting(host string, tty bool, command string) *exec.Cmd {
34
cmd := exec.Command("bash", "-c", command)
35
uid := fmt.Sprint(os.Getuid())
36
gid := fmt.Sprint(os.Getgid())
37
defer testbase.PatchEnvironment("SUDO_UID", uid)()
38
defer testbase.PatchEnvironment("SUDO_GID", gid)()
39
cmd.Env = os.Environ()
36
func (s *storageSuite) sshCommand(c *gc.C, host string, command ...string) *ssh.Cmd {
37
script := []byte("#!/bin/bash\n" + strings.Join(command, " "))
38
err := ioutil.WriteFile(filepath.Join(s.bin, "ssh"), script, 0755)
39
c.Assert(err, gc.IsNil)
40
client, err := ssh.NewOpenSSHClient()
41
c.Assert(err, gc.IsNil)
42
return client.Command(host, command, nil)
43
45
func newSSHStorage(host, storageDir, tmpDir string) (*SSHStorage, error) {
61
61
flockBin, err = exec.LookPath("flock")
62
62
c.Assert(err, gc.IsNil)
65
restoreEnv := testbase.PatchEnvironment("PATH", bin+":"+os.Getenv("PATH"))
65
restoreEnv := testbase.PatchEnvironment("PATH", s.bin+":"+os.Getenv("PATH"))
66
66
s.AddSuiteCleanup(func(*gc.C) { restoreEnv() })
68
// Create a "sudo" command which just executes its args.
69
err = os.Symlink("/usr/bin/env", filepath.Join(bin, "sudo"))
68
// Create a "sudo" command which shifts away the "-n", sets
69
// SUDO_UID/SUDO_GID, and executes the remaining args.
70
err = ioutil.WriteFile(filepath.Join(s.bin, "sudo"), []byte(
71
"#!/bin/sh\nshift; export SUDO_UID=`id -u` SUDO_GID=`id -g`; exec \"$@\"",
70
73
c.Assert(err, gc.IsNil)
71
restoreSshCommand := testbase.PatchValue(&sshCommand, sshCommandTesting)
74
restoreSshCommand := testbase.PatchValue(&sshCommand, func(host string, command ...string) *ssh.Cmd {
75
return s.sshCommand(c, host, command...)
72
77
s.AddSuiteCleanup(func(*gc.C) { restoreSshCommand() })
74
79
// Create a new "flock" which calls the original, but in non-blocking mode.
75
80
data := []byte(fmt.Sprintf("#!/bin/sh\nexec %s --nonblock \"$@\"", flockBin))
76
err = ioutil.WriteFile(filepath.Join(bin, "flock"), data, 0755)
81
err = ioutil.WriteFile(filepath.Join(s.bin, "flock"), data, 0755)
77
82
c.Assert(err, gc.IsNil)
169
174
// 3: second "install"
171
176
var invocations int
172
badSshCommand := func(host string, tty bool, command string) *exec.Cmd {
177
badSshCommand := func(host string, command ...string) *ssh.Cmd {
174
179
switch invocations {
176
return exec.Command("true")
181
return s.sshCommand(c, host, "true")
178
183
// Note: must close stdin before responding the first time, or
179
184
// the second command will race with closing stdin, and may
181
return exec.Command("bash", "-c", "head -n 1 > /dev/null; exec 0<&-; echo JUJU-RC: 0; echo blah blah; echo more")
186
return s.sshCommand(c, host, "head -n 1 > /dev/null; exec 0<&-; echo JUJU-RC: 0; echo blah blah; echo more")
183
return exec.Command("bash", "-c", `head -n 1 > /dev/null; echo "Hey it's JUJU-RC: , but not at the beginning of the line"; echo more`)
188
return s.sshCommand(c, host, `head -n 1 > /dev/null; echo "Hey it's JUJU-RC: , but not at the beginning of the line"; echo more`)
185
190
c.Errorf("unexpected invocation: #%d, %s", invocations, command)