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 }