github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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  
    13  	"github.com/juju/juju/utils/ssh"
    14  )
    15  
    16  // SCPCommand is responsible for launching a scp command to copy files to/from remote machine(s)
    17  type SCPCommand struct {
    18  	SSHCommon
    19  }
    20  
    21  const scpDoc = `
    22  Launch an scp command to copy files. Each argument <file1> ... <file2>
    23  is either local file path or remote locations of the form [<user>@]<target>:<path>,
    24  where <target> can be either a machine id as listed by "juju status" in the
    25  "machines" section or a unit name as listed in the "services" section. If a
    26  username is not specified, the username "ubuntu" will be used.
    27  
    28  To pass additional flags to "scp", separate "juju scp" from the options with
    29  "--" to prevent Juju from attempting to interpret the flags. This is only
    30  supported if the scp command can be found in the system PATH. Please refer to
    31  the man page of scp(1) for the supported extra arguments.
    32  
    33  Examples:
    34  
    35  Copy a single file from machine 2 to the local machine:
    36  
    37      juju scp 2:/var/log/syslog .
    38  
    39  Copy 2 files from two units to the local backup/ directory, passing -v
    40  to scp as an extra argument:
    41  
    42      juju scp -- -v ubuntu/0:/path/file1 ubuntu/1:/path/file2 backup/
    43  
    44  Recursively copy the directory /var/log/mongodb/ on the first mongodb
    45  server to the local directory remote-logs:
    46  
    47      juju scp -- -r mongodb/0:/var/log/mongodb/ remote-logs/
    48  
    49  Copy a local file to the second apache unit of the environment "testing":
    50  
    51      juju scp -e testing foo.txt apache2/1:
    52  `
    53  
    54  func (c *SCPCommand) Info() *cmd.Info {
    55  	return &cmd.Info{
    56  		Name:    "scp",
    57  		Args:    "<file1> ... <file2> [scp-option...]",
    58  		Purpose: "launch a scp command to copy files to/from remote machine(s)",
    59  		Doc:     scpDoc,
    60  	}
    61  }
    62  
    63  func (c *SCPCommand) Init(args []string) error {
    64  	if len(args) < 2 {
    65  		return fmt.Errorf("at least two arguments required")
    66  	}
    67  	c.Args = args
    68  	return nil
    69  }
    70  
    71  // expandArgs takes a list of arguments and looks for ones in the form of
    72  // 0:some/path or service/0:some/path, and translates them into
    73  // ubuntu@machine:some/path so they can be passed as arguments to scp, and pass
    74  // the rest verbatim on to scp
    75  func expandArgs(args []string, userHostFromTarget func(string) (string, string, error)) ([]string, error) {
    76  	outArgs := make([]string, len(args))
    77  	for i, arg := range args {
    78  		v := strings.SplitN(arg, ":", 2)
    79  		if strings.HasPrefix(arg, "-") || len(v) <= 1 {
    80  			// Can't be an interesting target, so just pass it along
    81  			outArgs[i] = arg
    82  			continue
    83  		}
    84  		user, host, err := userHostFromTarget(v[0])
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  		outArgs[i] = user + "@" + net.JoinHostPort(host, v[1])
    89  	}
    90  	return outArgs, nil
    91  }
    92  
    93  // Run resolves c.Target to a machine, or host of a unit and
    94  // forks ssh with c.Args, if provided.
    95  func (c *SCPCommand) Run(ctx *cmd.Context) error {
    96  	var err error
    97  	c.apiClient, err = c.initAPIClient()
    98  	if err != nil {
    99  		return err
   100  	}
   101  	defer c.apiClient.Close()
   102  
   103  	options, err := c.getSSHOptions(false)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	args, err := expandArgs(c.Args, c.userHostFromTarget)
   108  	if err != nil {
   109  		return err
   110  	}
   111  	return ssh.Copy(args, options)
   112  }