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  }