github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/commands/scp.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package commands
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"strings"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/utils/ssh"
    13  
    14  	"github.com/juju/juju/cmd/modelcmd"
    15  )
    16  
    17  var usageSCPSummary = `
    18  Transfers files to/from a Juju machine.`[1:]
    19  
    20  var usageSCPDetails = `
    21  The usage is for transferring files from the client to a Juju machine. To
    22  do the reverse:
    23  juju scp [options] [<user>@]<target>:<file> <path>
    24  and use quotes when multiple files are involved.
    25  The machine is identified by the <target> argument which is either a 'unit
    26  name' or a 'machine id'. Both are obtained in the output from `[1:] + "`juju \nstatus`" + `: unit name in the [Units] section and machine id in the [Machines]
    27  section.
    28  If 'user' is specified then the connection is made to that user account;
    29  otherwise, the 'ubuntu' account is used.
    30  'file' can be single or multiple files or directories. For directories,
    31  you must use the scp option of '-r'.
    32  Options specific to scp can be inserted between 'scp' and '[options]' with
    33  '-- <scp-options>'. Refer to the scp(1) man page for an explanation of
    34  those options.
    35  
    36  Examples:
    37  Copy file /var/log/syslog from machine 2 to the client's current working
    38  directory:
    39  
    40      juju scp 2:/var/log/syslog .
    41  
    42  Copy directory /var/log/mongodb, recursively, from a mongodb unit
    43  to the client's local directory remote-logs:
    44  
    45      juju scp -- -r mongodb/0:/var/log/mongodb/ remote-logs
    46  
    47  Copy file foo.txt, in verbose mode, from the client's current working
    48  directory to an apache2 unit of model "mymodel":
    49  
    50      juju scp -- -v -m mymodel foo.txt apache2/1:
    51  
    52  Copy multiple files from the client's current working directory to machine
    53  2:
    54  
    55      juju scp file1 file2 2:
    56  
    57  Copy multiple files from the bob user account on machine 3 to the client's
    58  current working directory:
    59  
    60      juju scp bob@3:'file1 file2' .
    61  
    62  See also: 
    63      ssh`
    64  
    65  func newSCPCommand() cmd.Command {
    66  	return modelcmd.Wrap(&scpCommand{})
    67  }
    68  
    69  // scpCommand is responsible for launching a scp command to copy files to/from remote machine(s)
    70  type scpCommand struct {
    71  	SSHCommon
    72  }
    73  
    74  func (c *scpCommand) Info() *cmd.Info {
    75  	return &cmd.Info{
    76  		Name:    "scp",
    77  		Args:    "<file> [<user>@]<target>:[<path>]",
    78  		Purpose: usageSCPSummary,
    79  		Doc:     usageSCPDetails,
    80  	}
    81  }
    82  
    83  func (c *scpCommand) Init(args []string) error {
    84  	if len(args) < 2 {
    85  		return fmt.Errorf("at least two arguments required")
    86  	}
    87  	c.Args = args
    88  	return nil
    89  }
    90  
    91  // expandArgs takes a list of arguments and looks for ones in the form of
    92  // 0:some/path or service/0:some/path, and translates them into
    93  // ubuntu@machine:some/path so they can be passed as arguments to scp, and pass
    94  // the rest verbatim on to scp
    95  func expandArgs(args []string, userHostFromTarget func(string) (string, string, error)) ([]string, error) {
    96  	outArgs := make([]string, len(args))
    97  	for i, arg := range args {
    98  		v := strings.SplitN(arg, ":", 2)
    99  		if strings.HasPrefix(arg, "-") || len(v) <= 1 {
   100  			// Can't be an interesting target, so just pass it along
   101  			outArgs[i] = arg
   102  			continue
   103  		}
   104  		user, host, err := userHostFromTarget(v[0])
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		outArgs[i] = user + "@" + net.JoinHostPort(host, v[1])
   109  	}
   110  	return outArgs, nil
   111  }
   112  
   113  // Run resolves c.Target to a machine, or host of a unit and
   114  // forks ssh with c.Args, if provided.
   115  func (c *scpCommand) Run(ctx *cmd.Context) error {
   116  	var err error
   117  	c.apiClient, err = c.initAPIClient()
   118  	if err != nil {
   119  		return err
   120  	}
   121  	defer c.apiClient.Close()
   122  
   123  	options, err := c.getSSHOptions(false)
   124  	if err != nil {
   125  		return err
   126  	}
   127  	args, err := expandArgs(c.Args, c.userHostFromTarget)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	return ssh.Copy(args, options)
   132  }