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  }