// UntarToDest writes to user destination the streamed tarball in input func UntarToDest(api *api.ScalewayAPI, sourceStream *io.ReadCloser, destination string) error { // destination is a server address + path (scp-like uri) if strings.Index(destination, ":") > -1 { log.Debugf("Streaming using ssh and untaring remotely") serverParts := strings.Split(destination, ":") if len(serverParts) != 2 { return fmt.Errorf("invalid destination uri, see 'scw cp -h' for usage") } serverID := api.GetServerID(serverParts[0]) server, err := api.GetServer(serverID) if err != nil { return err } // remoteCommand is executed on the remote server // it streams a tarball raw content remoteCommand := []string{"tar"} remoteCommand = append(remoteCommand, "-C", serverParts[1]) if os.Getenv("DEBUG") == "1" { remoteCommand = append(remoteCommand, "-v") } remoteCommand = append(remoteCommand, "-xf", "-") // execCmd contains the ssh connection + the remoteCommand execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, false, remoteCommand)) log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) spawnDst := exec.Command("ssh", execCmd...) untarInputStream, err := spawnDst.StdinPipe() if err != nil { return err } defer untarInputStream.Close() // spawnDst.Stderr = os.Stderr // spawnDst.Stdout = os.Stdout err = spawnDst.Start() if err != nil { return err } _, err = io.Copy(untarInputStream, *sourceStream) return err } // destination is stdout if destination == "-" { // stdout log.Debugf("Writing sourceStream(%v) to os.Stdout(%v)", sourceStream, os.Stdout) _, err := io.Copy(os.Stdout, *sourceStream) return err } // destination is a path on localhost log.Debugf("Untaring to local path: %s", destination) err := archive.Untar(*sourceStream, destination, &archive.TarOptions{NoLchown: true}) return err }
// TarFromSource creates a stream buffer with the tarballed content of the user source func TarFromSource(api *api.ScalewayAPI, source string) (*io.ReadCloser, error) { var tarOutputStream io.ReadCloser // source is a server address + path (scp-like uri) if strings.Index(source, ":") > -1 { log.Debugf("Creating a tarball remotely and streaming it using SSH") serverParts := strings.Split(source, ":") if len(serverParts) != 2 { return nil, fmt.Errorf("invalid source uri, see 'scw cp -h' for usage") } serverID := api.GetServerID(serverParts[0]) server, err := api.GetServer(serverID) if err != nil { return nil, err } dir, base := utils.PathToTARPathparts(serverParts[1]) log.Debugf("Equivalent to 'scp root@%s:%s/%s ...'", server.PublicAddress.IP, dir, base) // remoteCommand is executed on the remote server // it streams a tarball raw content remoteCommand := []string{"tar"} remoteCommand = append(remoteCommand, "-C", dir) if os.Getenv("DEBUG") == "1" { remoteCommand = append(remoteCommand, "-v") } remoteCommand = append(remoteCommand, "-cf", "-") remoteCommand = append(remoteCommand, base) // execCmd contains the ssh connection + the remoteCommand execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, false, remoteCommand)) log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) spawnSrc := exec.Command("ssh", execCmd...) tarOutputStream, err = spawnSrc.StdoutPipe() if err != nil { return nil, err } tarErrorStream, err := spawnSrc.StderrPipe() if err != nil { return nil, err } defer tarErrorStream.Close() io.Copy(os.Stderr, tarErrorStream) err = spawnSrc.Start() if err != nil { return nil, err } defer spawnSrc.Wait() return &tarOutputStream, nil } // source is stdin if source == "-" { log.Debugf("Streaming tarball from stdin") tarOutputStream = os.Stdin return &tarOutputStream, nil } // source is a path on localhost log.Debugf("Taring local path %s", source) path, err := filepath.Abs(source) if err != nil { return nil, err } path, err = filepath.EvalSymlinks(path) if err != nil { return nil, err } log.Debugf("Real local path is %s", path) dir, base := utils.PathToTARPathparts(path) tarOutputStream, err = archive.TarWithOptions(dir, &archive.TarOptions{ Compression: archive.Uncompressed, IncludeFiles: []string{base}, }) if err != nil { return nil, err } return &tarOutputStream, nil }