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