コード例 #1
0
ファイル: k-installer.go プロジェクト: alesr/k-env-setup
func (p *Project) installOnRemote(step int, conn *ssh.Client) {

	// Git and some other programs can send us an unsuccessful exit (< 0)
	// even if the command was successfully executed on the remote shell.
	// On these cases, we want to ignore those errors and move onto the next step.
	ignoredError := "Reason was:  ()"

	// Creates a session over the ssh connection to execute the commands
	session, err := conn.NewSession()
	if err != nil {
		log.Fatal("Failed to build session: ", err)
	}

	defer session.Close()

	var stdoutBuf bytes.Buffer
	session.Stdout = &stdoutBuf

	fmt.Println(p.typ.program.setup[step])

	err = session.Run(p.typ.program.setup[step])

	if err != nil && !strings.Contains(err.Error(), ignoredError) {
		log.Printf("Command '%s' failed on execution", p.typ.program.setup[step])
		log.Fatal("Error on command execution: ", err.Error())
	}
}
コード例 #2
0
ファイル: main.go プロジェクト: aybabtme/multisshtail
func tailFilesOnClient(client *ssh.Client, files []string, sudo bool, linec chan<- string, errc chan<- error) {
	var sessions []*ssh.Session
	closeSessions := func() {
		for _, session := range sessions {
			_ = session.Signal(ssh.SIGKILL)
			_ = session.Close()
		}
	}

	var wg sync.WaitGroup
	for _, file := range files {
		session, err := client.NewSession()
		if err != nil {
			closeSessions()
			errc <- fmt.Errorf("can't open session: %v", err)
			return
		}
		sessions = append(sessions, session)

		wg.Add(1)
		go func(file string) {
			defer wg.Done()
			err := tailFile(session, file, sudo, linec)
			if err != nil {
				errc <- err
			}
		}(file)

	}

	wg.Wait()
}
コード例 #3
0
ファイル: client.go プロジェクト: newxan/gopistrano
func ExecuteCmd(client *ssh.Client, command string, stdout *string, stderr *string) error {
	session, err := client.NewSession()
	if err != nil {
		panic("Failed to create session: " + err.Error())
	}
	defer session.Close()
	//session.Setenv("PATH", "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin") //apparently needs serverside support
	// Once a Session is created, you can execute a single command on
	// the remote side using the Run method.
	var b bytes.Buffer
	var a bytes.Buffer
	session.Stdout = &b
	session.Stderr = &a
	log.Printf("CMD: %s\n", command)
	if err := session.Run(command); err != nil {
		return err
	}

	if stdout != nil {
		*stdout = b.String()
	}
	if stderr != nil {
		*stderr = a.String()
	}

	return err
}
コード例 #4
0
ファイル: shell.go プロジェクト: rosenhouse/proctor
func scpAndRun(client ssh.Client) {
	scpSession, err := client.NewSession()
	if err != nil {
		panic("Failed to create SCP session: " + err.Error())
	}
	defer scpSession.Close()

	scriptContents := `#!/bin/bash

echo "this script is located at $dirname $0"
`
	scriptReader := strings.NewReader(scriptContents)
	scpError := copy(int64(len(scriptContents)), os.FileMode(0777), "test-script", scriptReader, "/tmp/scripts/", scpSession)
	if scpError != nil {
		panic(scpError)
	}

	execSession, err := client.NewSession()
	if err != nil {
		panic("Failed to create session: " + err.Error())
	}
	defer execSession.Close()

	var stdoutBytes bytes.Buffer
	execSession.Stdout = &stdoutBytes
	if err := execSession.Run("/tmp/scripts/test-script"); err != nil {
		panic("Failed to run: " + err.Error())
	}
}
コード例 #5
0
ファイル: addon_update.go プロジェクト: nak3/kubernetes
func sshExec(client *ssh.Client, cmd string) (string, string, int, error) {
	framework.Logf("Executing '%s' on %v", cmd, client.RemoteAddr())
	session, err := client.NewSession()
	if err != nil {
		return "", "", 0, fmt.Errorf("error creating session to host %s: '%v'", client.RemoteAddr(), err)
	}
	defer session.Close()

	// Run the command.
	code := 0
	var bout, berr bytes.Buffer

	session.Stdout, session.Stderr = &bout, &berr
	err = session.Run(cmd)
	if err != nil {
		// Check whether the command failed to run or didn't complete.
		if exiterr, ok := err.(*ssh.ExitError); ok {
			// If we got an ExitError and the exit code is nonzero, we'll
			// consider the SSH itself successful (just that the command run
			// errored on the host).
			if code = exiterr.ExitStatus(); code != 0 {
				err = nil
			}
		} else {
			// Some other kind of error happened (e.g. an IOError); consider the
			// SSH unsuccessful.
			err = fmt.Errorf("failed running `%s` on %s: '%v'", cmd, client.RemoteAddr(), err)
		}
	}
	return bout.String(), berr.String(), code, err
}
コード例 #6
0
ファイル: main.go プロジェクト: ZacharyJacobCollins/GO-SSH
//Execute ssh commands until "exit" is entered
func runCommands(client *ssh.Client) {
	var cmd string
	for strings.ToLower(cmd) != "exit" {
		//Creates a new session.  Only one command per session
		session, err := client.NewSession()
		if err != nil {
			panic("Failed to create session: " + err.Error())
		}

		defer session.Close()

		fmt.Scanf("%s", &cmd)

		var b bytes.Buffer
		session.Stdout = &b
		err1 := session.Run(cmd)
		if err1 != nil {
			fmt.Print("You used an invalid command.")
			err1 = nil
		}
		fmt.Println(b.String())
	}
	//clear the terminal and display conn closed
	clear := exec.Command("clear")
	clear.Stdout = os.Stdout
	clear.Run()
	fmt.Println("\n\nConnection Closed")
}
コード例 #7
0
ファイル: sshnode.go プロジェクト: karamsivia/netplugin
func (n *SSHNode) getClientAndSession() (*ssh.Client, *ssh.Session, error) {
	var client *ssh.Client
	var s *ssh.Session
	var err error

	// Retry few times if ssh connection fails
	for i := 0; i < MaxSSHRetries; i++ {
		client, err = n.dial()
		if err != nil {
			time.Sleep(SSHRetryDelay)
			continue
		}

		s, err = client.NewSession()
		if err != nil {
			client.Close()
			time.Sleep(SSHRetryDelay)
			continue
		}

		return client, s, nil
	}

	return nil, nil, err
}
コード例 #8
0
ファイル: sshClient.go プロジェクト: kkirsche/go-scp
func CopyLocalFileToRemote(client *ssh.Client, localFilePath string, filename string) error {
	// Each ClientConn can support multiple interactive sessions,
	// represented by a Session.
	session, err := client.NewSession()
	if err != nil {
		log.Fatal("Failed to create session: " + err.Error())
	}
	defer session.Close()

	writer, err := session.StdinPipe()
	if err != nil {
		return err
	}
	defer writer.Close()

	go func() {
		fileContents, _ := ioutil.ReadFile(localFilePath + "/" + filename)
		content := string(fileContents)
		fmt.Fprintln(writer, "C0644", len(content), filename)
		fmt.Fprint(writer, content)
		fmt.Fprintln(writer, "\x00") // transfer end with \x00\
	}()

	session.Run("/usr/bin/scp -t ./")
	return nil
}
コード例 #9
0
ファイル: client.go プロジェクト: hnakamur/rate_limited_sftp
func NewClient(conn *ssh.Client, readLimitBytesPerSecond, writeLimitBytesPerSecond int64, opts ...func(*sftp.Client) error) (*sftp.Client, error) {
	s, err := conn.NewSession()
	if err != nil {
		return nil, err
	}
	if err := s.RequestSubsystem("sftp"); err != nil {
		return nil, err
	}
	pw, err := s.StdinPipe()
	if err != nil {
		return nil, err
	}
	pr, err := s.StdoutPipe()
	if err != nil {
		return nil, err
	}

	if readLimitBytesPerSecond > 0 {
		pr = flowrate.NewReader(pr, readLimitBytesPerSecond)
	}
	if writeLimitBytesPerSecond > 0 {
		pw = flowrate.NewWriter(pw, writeLimitBytesPerSecond)
	}
	return sftp.NewClientPipe(pr, pw, opts...)
}
コード例 #10
0
ファイル: sshnode.go プロジェクト: contiv/remotessh
func (n *SSHNode) getClientAndSession() (*ssh.Client, *ssh.Session, error) {
	var client *ssh.Client
	var s *ssh.Session
	var err error

	// Retry few times if ssh connection fails
	for i := 0; i < MaxSSHRetries; i++ {
		client, err = n.dial()
		if err != nil {
			time.Sleep(SSHRetryDelay)
			continue
		}

		s, err = client.NewSession()
		if err != nil {
			client.Close()
			time.Sleep(SSHRetryDelay)
			continue
		}
		modes := ssh.TerminalModes{
			ssh.ECHO:          0,
			ssh.TTY_OP_ISPEED: 14400,
			ssh.TTY_OP_OSPEED: 14400,
		}
		// Request pseudo terminal
		if err := s.RequestPty("xterm", 40, 80, modes); err != nil {
			return nil, nil, fmt.Errorf("failed to get pseudo-terminal: %v", err)
		}

		return client, s, nil
	}

	return nil, nil, err
}
コード例 #11
0
ファイル: sshutil.go プロジェクト: ymomoi/vuls
func sshExecNative(c conf.ServerInfo, cmd string, sudo bool) (result execResult) {
	result.Servername = c.ServerName
	result.Host = c.Host
	result.Port = c.Port

	var client *ssh.Client
	var err error
	if client, err = sshConnect(c); err != nil {
		result.Error = err
		result.ExitStatus = 999
		return
	}
	defer client.Close()

	var session *ssh.Session
	if session, err = client.NewSession(); err != nil {
		result.Error = fmt.Errorf(
			"Failed to create a new session. servername: %s, err: %s",
			c.ServerName, err)
		result.ExitStatus = 999
		return
	}
	defer session.Close()

	// http://blog.ralch.com/tutorial/golang-ssh-connection/
	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	if err = session.RequestPty("xterm", 400, 256, modes); err != nil {
		result.Error = fmt.Errorf(
			"Failed to request for pseudo terminal. servername: %s, err: %s",
			c.ServerName, err)
		result.ExitStatus = 999
		return
	}

	var stdoutBuf, stderrBuf bytes.Buffer
	session.Stdout = &stdoutBuf
	session.Stderr = &stderrBuf

	cmd = decolateCmd(c, cmd, sudo)
	if err := session.Run(cmd); err != nil {
		if exitErr, ok := err.(*ssh.ExitError); ok {
			result.ExitStatus = exitErr.ExitStatus()
		} else {
			result.ExitStatus = 999
		}
	} else {
		result.ExitStatus = 0
	}

	result.Stdout = stdoutBuf.String()
	result.Stderr = stderrBuf.String()
	result.Cmd = strings.Replace(cmd, "\n", "", -1)
	return
}
コード例 #12
0
ファイル: sshutil.go プロジェクト: gashcrumb/gofabric8
func RunCommand(c *ssh.Client, cmd string) error {
	s, err := c.NewSession()
	defer s.Close()
	if err != nil {
		return errors.Wrap(err, "Error creating new session for ssh client")
	}

	return s.Run(cmd)
}
コード例 #13
0
ファイル: sshutil.go プロジェクト: rawlingsj/gofabric8
func RunCommand(c *ssh.Client, cmd string) error {
	s, err := c.NewSession()
	defer s.Close()
	if err != nil {
		return err
	}

	return s.Run(cmd)
}
コード例 #14
0
ファイル: condorbots.go プロジェクト: rwcarlsen/cloudlus
func combined(c *ssh.Client, cmd string) ([]byte, error) {
	s, err := c.NewSession()
	if err != nil {
		return nil, err
	}
	defer s.Close()

	return s.CombinedOutput(cmd)
}
コード例 #15
0
ファイル: executor.go プロジェクト: abhigupta912/learngo
func createSession(client *ssh.Client) (*ssh.Session, error) {
	fmt.Println("Creating new session")
	session, err := client.NewSession()
	if err != nil {
		fmt.Println("Failed to create session")
		fmt.Println("Error : ", err.Error())
		return nil, err
	}

	return session, nil
}
コード例 #16
0
ファイル: shell.go プロジェクト: juztin/shelli
// NewPty creates a new SSH session to the client using inCh as stdin, and quiting on a receive to quit.
// Returns stdout, stderr channels and error channel
func NewPty(client *ssh.Client, inCh <-chan []byte, quit <-chan struct{}) (<-chan []byte, <-chan []byte, <-chan error) {
	errCh := make(chan error, 1)
	// Create a new session from the given configuration func.
	session, err := client.NewSession()
	if err != nil {
		errCh <- err
		return nil, nil, nil
	}
	// Get session std in/out/err
	stdin, stdout, stderr, err := sessionStreams(session)
	if err != nil {
		errCh <- err
		return nil, nil, nil
	}
	// Stream from readers to channels
	stdoutCh := make(chan []byte)
	stderrCh := make(chan []byte)
	go streamToChan(stdout, stdoutCh, errCh)
	go streamToChan(stderr, stderrCh, errCh)
	// Set terminal modes
	modes := ssh.TerminalModes{
		ssh.VREPRINT: 0,
		ssh.CS8:      1,
		ssh.ECHOE:    1,
		ssh.ECHOCTL:  0,
	}
	// Request pseudo terminal
	err = session.RequestPty("xterm", 24, 80, modes)
	//err = session.RequestPty("vt100", 24, 80, modes)
	if err != nil {
		errCh <- err
		return nil, nil, nil
	}
	// Invoke SSH shell
	err = session.Shell()
	if err != nil {
		errCh <- err
		return nil, nil, nil
	}
	// Listen for input/quit
	go func() {
		for {
			select {
			case b := <-inCh:
				stdin.Write(b)
			case <-quit:
				session.Close()
				return
			}
		}
	}()
	return stdoutCh, stderrCh, errCh
}
コード例 #17
0
ファイル: ssh.go プロジェクト: ahjdzx/dis
func Mkdir(client *ssh.Client, destDir string) error {
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()

	err = session.Run(`bash -c "mkdir -p ` + destDir + `"`)
	if err != nil {
		return err
	}
	return nil
}
コード例 #18
0
ファイル: ssh.go プロジェクト: ahjdzx/dis
func ChangeDir(client *ssh.Client, dir string) error {
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()

	err = session.Run(`bash -c "cd ` + dir + `"`)
	if err != nil {
		return err
	}
	return nil
}
コード例 #19
0
ファイル: ssh.go プロジェクト: ahjdzx/dis
func Pwd(client *ssh.Client) (string, error) {
	session, err := client.NewSession()
	if err != nil {
		return "", err
	}
	defer session.Close()

	output, err := session.CombinedOutput(`bash -c "pwd"`)
	if err != nil {
		return "", err
	}

	return string(output), nil
}
コード例 #20
0
ファイル: session.go プロジェクト: Gooooodman/gosshtool
func NewSession(conn *ssh.Client, deadline *time.Time, idleTimeout int) (ss *SshSession, err error) {
	session, err := conn.NewSession()
	if err != nil {
		return nil, err
	}
	sshSession := new(SshSession)
	sshSession.session = session
	sshSession.deadline = deadline
	sshSession.idleTimeout = idleTimeout
	sshSession.id = Rand().Hex()
	//check session timeout
	go sshSession.checkSessionTimeout()
	return sshSession, nil
}
コード例 #21
0
ファイル: secret.go プロジェクト: xperimental/yovpn
func readSecret(client *ssh.Client) (string, error) {
	session, err := client.NewSession()
	if err != nil {
		return "", err
	}
	defer session.Close()

	var b bytes.Buffer
	session.Stdout = &b
	if err := session.Run("cat /etc/openvpn/secret.key"); err != nil {
		return "", err
	}

	return b.String(), nil
}
コード例 #22
0
ファイル: remote.go プロジェクト: rainycape/browser
func runRemoteCmd(client *ssh.Client, cmd string, args ...string) (string, error) {
	session, err := client.NewSession()
	if err != nil {
		return "", fmt.Errorf("failed to create session: %s", err)
	}
	defer session.Close()
	var out bytes.Buffer
	session.Stdout = &out
	session.Stderr = &out
	fullCmd := shellJoin(cmd, args)
	if err := session.Run(fullCmd); err != nil {
		return "", fmt.Errorf("failed to run %s: %s", fullCmd, err)
	}
	return out.String(), nil
}
コード例 #23
0
ファイル: main.go プロジェクト: gooops/goscp
func sendFileToRemoteHost(client *ssh.Client, limit int64, sourceFile, targetUser, targetHost, targetFile string) {
	session, err := client.NewSession()
	if err != nil {
		log.Fatalln("Failed to create session: " + err.Error())
	}
	defer session.Close()

	go func() {
		iw, err := session.StdinPipe()
		if err != nil {
			log.Fatalln("Failed to create input pipe: " + err.Error())
		}

		w := flowrate.NewWriter(iw, limit)
		src, srcErr := os.Open(sourceFile)
		if srcErr != nil {
			log.Fatalln("Failed to open source file: " + srcErr.Error())
		}
		srcStat, statErr := src.Stat()
		if statErr != nil {
			log.Fatalln("Failed to stat file: " + statErr.Error())
		}

		fmt.Fprintln(w, "C0644", srcStat.Size(), filepath.Base(sourceFile))
		if srcStat.Size() > 0 {
			bar := pb.New(int(srcStat.Size()))
			bar.Units = pb.U_BYTES
			bar.ShowSpeed = true
			bar.Start()
			wp := io.MultiWriter(w, bar)

			fmt.Printf("Transferring %s to %s@%s:%s\n", sourceFile, targetUser, targetHost, targetFile)
			fmt.Printf("Speed limited to %d bytes/sec\n", limit)

			io.Copy(wp, src)
			bar.Finish()
			fmt.Fprint(w, "\x00")
			w.Close()
		} else {
			fmt.Printf("Transferred empty file %s to %s@%s:%s\n", sourceFile, targetUser, targetHost, targetFile)
			fmt.Fprint(w, "\x00")
			w.Close()
		}
	}()
	if err := session.Run(fmt.Sprintf("scp -t %s", targetFile)); err != nil {
		log.Fatalln("Failed to run: " + err.Error())
	}
}
コード例 #24
0
ファイル: sshtunnel.go プロジェクト: ivanilves/gopack
func executeCommand(client *ssh.Client, command string) (string, string, error) {
	session, err := client.NewSession()
	if err != nil {
		return "", "", err
	}
	defer session.Close()

	var outBuf bytes.Buffer
	var errBuf bytes.Buffer
	session.Stdout = &outBuf
	session.Stderr = &errBuf

	session.Run(command)

	return outBuf.String(), errBuf.String(), nil
}
コード例 #25
0
ファイル: bootstrap.go プロジェクト: boivie/undergang
func runBootstrap(ssh *ssh.Client, info PathInfo, progress chan<- ProgressCmd) {
	type BootstrapStep struct {
		Description string `json:"description"`
		Status      string `json:"status"`
	}
	status := struct {
		Steps []BootstrapStep `json:"steps"`
	}{make([]BootstrapStep, 0)}

	for _, cmd := range info.SSHTunnel.Bootstrap {
		status.Steps = append(status.Steps, BootstrapStep{cmd.Description, ""})
	}

	for idx, cmd := range info.SSHTunnel.Bootstrap {
		log.Printf("Started running bootstrap '%s'", cmd.Command)
		status.Steps[idx].Status = "started"
		progress <- ProgressCmd{"bootstrap_status", status}
		session, _ := ssh.NewSession()
		defer session.Close()
		session.Stdout = os.Stdout
		session.Stderr = os.Stderr
		session.Run(cmd.Command)
		status.Steps[idx].Status = "done"
		progress <- ProgressCmd{"bootstrap_status", status}
		log.Printf("Finished running bootstrap '%s'", cmd.Command)
	}
}
コード例 #26
0
ファイル: ssh.go プロジェクト: ahjdzx/dis
func RunCommand(client *ssh.Client, cmd string) (output string, err error) {
	session, err := client.NewSession()
	if err != nil {
		return "", err
	}
	defer session.Close()

	var b bytes.Buffer
	session.Stdout = &b
	err = session.Run(cmd)
	if err != nil {
		return "", err
	}

	return b.String(), nil
}
コード例 #27
0
ファイル: main.go プロジェクト: gooops/goscp
func getFileFromRemoteHost(client *ssh.Client, localFile, targetUser, targetHost, targetFile string) {
	session, err := client.NewSession()
	if err != nil {
		log.Fatalln("Failed to create session: " + err.Error())
	}
	defer session.Close()

	go func() {
		iw, err := session.StdinPipe()
		if err != nil {
			log.Fatalln("Failed to create input pipe: " + err.Error())
		}
		or, err := session.StdoutPipe()
		if err != nil {
			log.Fatalln("Failed to create output pipe: " + err.Error())
		}
		fmt.Fprint(iw, "\x00")

		sr := bufio.NewReader(or)

		src, srcErr := os.Create(localFile)
		if srcErr != nil {
			log.Fatalln("Failed to create source file: " + srcErr.Error())
		}
		if controlString, ok := sr.ReadString('\n'); ok == nil && strings.HasPrefix(controlString, "C") {
			fmt.Fprint(iw, "\x00")
			controlParts := strings.Split(controlString, " ")
			size, _ := strconv.ParseInt(controlParts[1], 10, 64)
			bar := pb.New(int(size))
			bar.Units = pb.U_BYTES
			bar.ShowSpeed = true
			bar.Start()
			rp := io.MultiReader(sr, bar)
			if n, ok := io.CopyN(src, rp, size); ok != nil || n < size {
				fmt.Println(n)
				fmt.Fprint(iw, "\x02")
				return
			}
			bar.Finish()
			sr.Read(make([]byte, 1))
		}
		fmt.Fprint(iw, "\x00")
	}()
	if err := session.Run(fmt.Sprintf("scp -f %s", targetFile)); err != nil {
		log.Fatalln("Failed to run: " + err.Error())
	}
}
コード例 #28
0
ファイル: runcmd.go プロジェクト: czxichen/Goprograme
func Run(Con *ssh.Client, cmd string) {
	defer Con.Close()
	s, err := Con.NewSession()
	if err != nil {
		color.Red("%s:新建会话失败.命令未执行.", Con.RemoteAddr())
		return
	}
	fmt.Printf("成功连接:%s\n", Con.RemoteAddr())
	buf, err := s.Output(cmd)
	if err != nil {
		color.Red("%s:命令执行失败.", Con.RemoteAddr())
		return
	}
	str := fmt.Sprintf("%s 的执行结果:\n%s\n", Con.RemoteAddr().String(), string(buf))
	fmt.Println(str)
	Result <- str
}
コード例 #29
0
ファイル: 00_ssh.go プロジェクト: xqbumu/learn
func runCommand(
	sshClient *ssh.Client,
	cmd string,
	execTimeout time.Duration,
) (string, error) {

	session, err := sshClient.NewSession()
	if err != nil {
		return "", err
	}
	defer session.Close()

	termModes := ssh.TerminalModes{
		ssh.ECHO:          0,     // do not echo
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}
	if err := session.RequestPty("xterm", 80, 40, termModes); err != nil {
		return "", err
	}

	stdinBuf, stdoutBuf, stderrBuf := new(bytes.Buffer), new(bytes.Buffer), new(bytes.Buffer)
	session.Stdin = stdinBuf
	session.Stdout = stdoutBuf
	session.Stderr = stderrBuf

	outputChan := make(chan string)
	errChan := make(chan error)
	go func() {
		if err := session.Run(cmd); err != nil {
			errChan <- fmt.Errorf("%v, %s", err, stderrBuf.String())
			return
		}
		outputChan <- stdoutBuf.String()
	}()
	select {
	case output := <-outputChan:
		return output, nil

	case err := <-errChan:
		return "", err

	case <-time.After(execTimeout):
		return "", fmt.Errorf("execution timeout.")
	}
}
コード例 #30
0
ファイル: client.go プロジェクト: kubernetes/kubernetes
// NewClient creates a new SFTP client on conn, using zero or more option
// functions.
func NewClient(conn *ssh.Client, opts ...func(*Client) error) (*Client, error) {
	s, err := conn.NewSession()
	if err != nil {
		return nil, err
	}
	if err := s.RequestSubsystem("sftp"); err != nil {
		return nil, err
	}
	pw, err := s.StdinPipe()
	if err != nil {
		return nil, err
	}
	pr, err := s.StdoutPipe()
	if err != nil {
		return nil, err
	}

	return NewClientPipe(pr, pw, opts...)
}