github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/scp_unix_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // +build !windows 5 6 package main 7 8 import ( 9 "bytes" 10 "fmt" 11 "io/ioutil" 12 "path/filepath" 13 "strings" 14 15 jc "github.com/juju/testing/checkers" 16 gc "gopkg.in/check.v1" 17 "gopkg.in/juju/charm.v4" 18 19 "github.com/juju/juju/cmd/envcmd" 20 "github.com/juju/juju/network" 21 "github.com/juju/juju/testcharms" 22 coretesting "github.com/juju/juju/testing" 23 ) 24 25 var _ = gc.Suite(&SCPSuite{}) 26 var _ = gc.Suite(&expandArgsSuite{}) 27 28 type SCPSuite struct { 29 SSHCommonSuite 30 } 31 32 type expandArgsSuite struct{} 33 34 var scpTests = []struct { 35 about string 36 args []string 37 result string 38 proxy bool 39 error string 40 }{ 41 { 42 about: "scp from machine 0 to current dir", 43 args: []string{"0:foo", "."}, 44 result: commonArgsNoProxy + "ubuntu@dummyenv-0.dns:foo .\n", 45 }, { 46 about: "scp from machine 0 to current dir with extra args", 47 args: []string{"0:foo", ".", "-rv", "-o", "SomeOption"}, 48 result: commonArgsNoProxy + "ubuntu@dummyenv-0.dns:foo . -rv -o SomeOption\n", 49 }, { 50 about: "scp from current dir to machine 0", 51 args: []string{"foo", "0:"}, 52 result: commonArgsNoProxy + "foo ubuntu@dummyenv-0.dns:\n", 53 }, { 54 about: "scp from current dir to machine 0 with extra args", 55 args: []string{"foo", "0:", "-r", "-v"}, 56 result: commonArgsNoProxy + "foo ubuntu@dummyenv-0.dns: -r -v\n", 57 }, { 58 about: "scp from machine 0 to unit mysql/0", 59 args: []string{"0:foo", "mysql/0:/foo"}, 60 result: commonArgsNoProxy + "ubuntu@dummyenv-0.dns:foo ubuntu@dummyenv-0.dns:/foo\n", 61 }, { 62 about: "scp from machine 0 to unit mysql/0 and extra args", 63 args: []string{"0:foo", "mysql/0:/foo", "-q"}, 64 result: commonArgsNoProxy + "ubuntu@dummyenv-0.dns:foo ubuntu@dummyenv-0.dns:/foo -q\n", 65 }, { 66 about: "scp from machine 0 to unit mysql/0 and extra args before", 67 args: []string{"-q", "-r", "0:foo", "mysql/0:/foo"}, 68 result: commonArgsNoProxy + "-q -r ubuntu@dummyenv-0.dns:foo ubuntu@dummyenv-0.dns:/foo\n", 69 }, { 70 about: "scp two local files to unit mysql/0", 71 args: []string{"file1", "file2", "mysql/0:/foo/"}, 72 result: commonArgsNoProxy + "file1 file2 ubuntu@dummyenv-0.dns:/foo/\n", 73 }, { 74 about: "scp from unit mongodb/1 to unit mongodb/0 and multiple extra args", 75 args: []string{"mongodb/1:foo", "mongodb/0:", "-r", "-v", "-q", "-l5"}, 76 result: commonArgsNoProxy + "ubuntu@dummyenv-2.dns:foo ubuntu@dummyenv-1.dns: -r -v -q -l5\n", 77 }, { 78 about: "scp works with IPv6 addresses", 79 args: []string{"ipv6-svc/0:foo", "bar"}, 80 result: commonArgsNoProxy + `ubuntu@[2001:db8::1]:foo bar` + "\n", 81 }, { 82 about: "scp from machine 0 to unit mysql/0 with proxy", 83 args: []string{"0:foo", "mysql/0:/foo"}, 84 result: commonArgs + "ubuntu@dummyenv-0.internal:foo ubuntu@dummyenv-0.internal:/foo\n", 85 proxy: true, 86 }, { 87 args: []string{"0:foo", ".", "-rv", "-o", "SomeOption"}, 88 result: commonArgsNoProxy + "ubuntu@dummyenv-0.dns:foo . -rv -o SomeOption\n", 89 }, { 90 args: []string{"foo", "0:", "-r", "-v"}, 91 result: commonArgsNoProxy + "foo ubuntu@dummyenv-0.dns: -r -v\n", 92 }, { 93 args: []string{"mongodb/1:foo", "mongodb/0:", "-r", "-v", "-q", "-l5"}, 94 result: commonArgsNoProxy + "ubuntu@dummyenv-2.dns:foo ubuntu@dummyenv-1.dns: -r -v -q -l5\n", 95 }, { 96 about: "scp from unit mongodb/1 to unit mongodb/0 with a --", 97 args: []string{"--", "-r", "-v", "mongodb/1:foo", "mongodb/0:", "-q", "-l5"}, 98 result: commonArgsNoProxy + "-- -r -v ubuntu@dummyenv-2.dns:foo ubuntu@dummyenv-1.dns: -q -l5\n", 99 }, { 100 about: "scp from unit mongodb/1 to current dir as 'mongo' user", 101 args: []string{"mongo@mongodb/1:foo", "."}, 102 result: commonArgsNoProxy + "mongo@dummyenv-2.dns:foo .\n", 103 }, { 104 about: "scp with no such machine", 105 args: []string{"5:foo", "bar"}, 106 error: "machine 5 not found", 107 }, 108 } 109 110 func (s *SCPSuite) TestSCPCommand(c *gc.C) { 111 m := s.makeMachines(4, c, true) 112 ch := testcharms.Repo.CharmDir("dummy") 113 curl := charm.MustParseURL( 114 fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()), 115 ) 116 dummyCharm, err := s.State.AddCharm(ch, curl, "dummy-path", "dummy-1-sha256") 117 c.Assert(err, jc.ErrorIsNil) 118 srv := s.AddTestingService(c, "mysql", dummyCharm) 119 s.addUnit(srv, m[0], c) 120 121 srv = s.AddTestingService(c, "mongodb", dummyCharm) 122 s.addUnit(srv, m[1], c) 123 s.addUnit(srv, m[2], c) 124 srv = s.AddTestingService(c, "ipv6-svc", dummyCharm) 125 s.addUnit(srv, m[3], c) 126 // Simulate machine 3 has a public IPv6 address. 127 ipv6Addr := network.NewAddress("2001:db8::1", network.ScopePublic) 128 err = m[3].SetAddresses(ipv6Addr) 129 c.Assert(err, jc.ErrorIsNil) 130 131 for i, t := range scpTests { 132 c.Logf("test %d: %s -> %s\n", i, t.about, t.args) 133 ctx := coretesting.Context(c) 134 scpcmd := &SCPCommand{} 135 scpcmd.proxy = t.proxy 136 137 err := envcmd.Wrap(scpcmd).Init(t.args) 138 c.Check(err, jc.ErrorIsNil) 139 err = scpcmd.Run(ctx) 140 if t.error != "" { 141 c.Check(err, gc.ErrorMatches, t.error) 142 c.Check(t.result, gc.Equals, "") 143 } else { 144 c.Check(err, jc.ErrorIsNil) 145 // we suppress stdout from scp 146 c.Check(ctx.Stderr.(*bytes.Buffer).String(), gc.Equals, "") 147 c.Check(ctx.Stdout.(*bytes.Buffer).String(), gc.Equals, "") 148 data, err := ioutil.ReadFile(filepath.Join(s.bin, "scp.args")) 149 c.Check(err, jc.ErrorIsNil) 150 actual := string(data) 151 if t.proxy { 152 actual = strings.Replace(actual, ".dns", ".internal", 2) 153 } 154 c.Check(actual, gc.Equals, t.result) 155 } 156 } 157 } 158 159 type userHost struct { 160 user string 161 host string 162 } 163 164 var userHostsFromTargets = map[string]userHost{ 165 "0": {"ubuntu", "dummyenv-0.dns"}, 166 "mysql/0": {"ubuntu", "dummyenv-0.dns"}, 167 "mongodb/0": {"ubuntu", "dummyenv-1.dns"}, 168 "mongodb/1": {"ubuntu", "dummyenv-2.dns"}, 169 "mongo@mongodb/1": {"mongo", "dummyenv-2.dns"}, 170 "ipv6-svc/0": {"ubuntu", "2001:db8::1"}, 171 } 172 173 func dummyHostsFromTarget(target string) (string, string, error) { 174 if res, ok := userHostsFromTargets[target]; ok { 175 return res.user, res.host, nil 176 } 177 return "ubuntu", target, nil 178 } 179 180 func (s *expandArgsSuite) TestSCPExpandArgs(c *gc.C) { 181 for i, t := range scpTests { 182 if t.error != "" { 183 // We are just running a focused set of tests on 184 // expandArgs, we aren't implementing the full 185 // userHostsFromTargets to actually trigger errors 186 continue 187 } 188 c.Logf("test %d: %s -> %s\n", i, t.about, t.args) 189 // expandArgs doesn't add the commonArgs prefix, so strip it 190 // off, along with the trailing '\n' 191 var argString string 192 if t.proxy { 193 c.Check(strings.HasPrefix(t.result, commonArgs), jc.IsTrue) 194 argString = t.result[len(commonArgs):] 195 } else { 196 c.Check(strings.HasPrefix(t.result, commonArgsNoProxy), jc.IsTrue) 197 argString = t.result[len(commonArgsNoProxy):] 198 } 199 c.Check(strings.HasSuffix(argString, "\n"), jc.IsTrue) 200 argString = argString[:len(argString)-1] 201 args := strings.Split(argString, " ") 202 expanded, err := expandArgs(t.args, func(target string) (string, string, error) { 203 if res, ok := userHostsFromTargets[target]; ok { 204 if t.proxy { 205 res.host = strings.Replace(res.host, ".dns", ".internal", 1) 206 } 207 return res.user, res.host, nil 208 } 209 return "ubuntu", target, nil 210 }) 211 c.Check(err, jc.ErrorIsNil) 212 c.Check(expanded, gc.DeepEquals, args) 213 } 214 } 215 216 var expandTests = []struct { 217 about string 218 args []string 219 result []string 220 }{ 221 { 222 "don't expand params that start with '-'", 223 []string{"-0:stuff", "0:foo", "."}, 224 []string{"-0:stuff", "ubuntu@dummyenv-0.dns:foo", "."}, 225 }, 226 } 227 228 func (s *expandArgsSuite) TestExpandArgs(c *gc.C) { 229 for i, t := range expandTests { 230 c.Logf("test %d: %s -> %s\n", i, t.about, t.args) 231 expanded, err := expandArgs(t.args, dummyHostsFromTarget) 232 c.Check(err, jc.ErrorIsNil) 233 c.Check(expanded, gc.DeepEquals, t.result) 234 } 235 } 236 237 func (s *expandArgsSuite) TestExpandArgsPropagatesErrors(c *gc.C) { 238 erroringUserHostFromTargets := func(string) (string, string, error) { 239 return "", "", fmt.Errorf("this is my error") 240 } 241 expanded, err := expandArgs([]string{"foo:1", "bar"}, erroringUserHostFromTargets) 242 c.Assert(err, gc.ErrorMatches, "this is my error") 243 c.Check(expanded, gc.IsNil) 244 }