github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 "net" 8 "strings" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 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 source or destination arguments may either be a local path or a remote 22 location. The syntax for a remote location is: 23 24 [<user>@]<target>:[<path>] 25 26 If the user is not specified, "ubuntu" is used. If <path> is not specified, it 27 defaults to the home directory of the remote user account. 28 29 The <target> may be either a 'unit name' or a 'machine id'. These can be 30 obtained from the output of "juju status". 31 32 Options specific to scp can be provided after a "--". Refer to the scp(1) man 33 page for an explanation of those options. The "-r" option to recursively copy a 34 directory is particularly useful. 35 36 The SSH host keys of the target are verified. The --no-host-key-checks option 37 can be used to disable these checks. Use of this option is not recommended as 38 it opens up the possibility of a man-in-the-middle attack. 39 40 Examples: 41 42 Copy file /var/log/syslog from machine 2 to the client's current working 43 directory: 44 45 juju scp 2:/var/log/syslog . 46 47 Recursively copy the /var/log/mongodb directory from a mongodb unit to the 48 client's local remote-logs directory: 49 50 juju scp -- -r mongodb/0:/var/log/mongodb/ remote-logs 51 52 Copy foo.txt from the client's current working directory to an apache2 unit of 53 model "prod". Proxy the SSH connection through the controller and turn on scp 54 compression: 55 56 juju scp -m prod --proxy -- -C foo.txt apache2/1: 57 58 Copy multiple files from the client's current working directory to machine 2: 59 60 juju scp file1 file2 2: 61 62 Copy multiple files from the bob user account on machine 3 to the client's 63 current working directory: 64 65 juju scp bob@3:'file1 file2' . 66 67 Copy file.dat from machine 0 to the machine hosting unit foo/0 (-3 68 causes the transfer to be made via the client): 69 70 juju scp -- -3 0:file.dat foo/0: 71 72 See also: 73 ssh` 74 75 func newSCPCommand() cmd.Command { 76 return modelcmd.Wrap(&scpCommand{}) 77 } 78 79 // scpCommand is responsible for launching a scp command to copy files to/from remote machine(s) 80 type scpCommand struct { 81 SSHCommon 82 } 83 84 func (c *scpCommand) Info() *cmd.Info { 85 return &cmd.Info{ 86 Name: "scp", 87 Args: "<source> <destination>", 88 Purpose: usageSCPSummary, 89 Doc: usageSCPDetails, 90 } 91 } 92 93 func (c *scpCommand) Init(args []string) error { 94 if len(args) < 2 { 95 return errors.Errorf("at least two arguments required") 96 } 97 c.Args = args 98 return nil 99 } 100 101 // Run resolves c.Target to a machine, or host of a unit and 102 // forks ssh with c.Args, if provided. 103 func (c *scpCommand) Run(ctx *cmd.Context) error { 104 err := c.initRun() 105 if err != nil { 106 return errors.Trace(err) 107 } 108 defer c.cleanupRun() 109 110 args, targets, err := expandArgs(c.Args, c.resolveTarget) 111 if err != nil { 112 return err 113 } 114 115 options, err := c.getSSHOptions(false, targets...) 116 if err != nil { 117 return err 118 } 119 120 return ssh.Copy(args, options) 121 } 122 123 // expandArgs takes a list of arguments and looks for ones in the form of 124 // 0:some/path or application/0:some/path, and translates them into 125 // ubuntu@machine:some/path so they can be passed as arguments to scp, and pass 126 // the rest verbatim on to scp 127 func expandArgs(args []string, resolveTarget func(string) (*resolvedTarget, error)) ( 128 []string, []*resolvedTarget, error, 129 ) { 130 outArgs := make([]string, len(args)) 131 var targets []*resolvedTarget 132 for i, arg := range args { 133 v := strings.SplitN(arg, ":", 2) 134 if strings.HasPrefix(arg, "-") || len(v) <= 1 { 135 // Can't be an interesting target, so just pass it along 136 outArgs[i] = arg 137 continue 138 } 139 140 target, err := resolveTarget(v[0]) 141 if err != nil { 142 return nil, nil, err 143 } 144 arg := net.JoinHostPort(target.host, v[1]) 145 if target.user != "" { 146 arg = target.user + "@" + arg 147 } 148 outArgs[i] = arg 149 150 targets = append(targets, target) 151 } 152 return outArgs, targets, nil 153 }