我正在尝试自动调试coreos上的docker容器。我想有一个脚本,连接到主机通过ssh和exectues nsenter。这将是非常方便的直接跳入一个容器从我的OSX机器,而不是手动做很多事情。我知道以这种方式进入容器可能很麻烦,但如果事情变得困难,我想使用这样的工具。这是我到目前为止在golang所做的。
我可以创建一个交互式的shell。在这里,我遇到了问题,比如使用ctrl+R反向搜索bash历史记录会中断会话。该代码在下面进行了注释,因此不会执行。
但是,我也可以执行一条命令,这里是nsenter,但是我收到了错误stdin: is not a tty,没有其他事情发生。我很想知道为什么我的程序中的stdin不是tty,以及我如何实现这一点。
谢谢
package main
import (
"code.google.com/p/go.crypto/ssh"
"io/ioutil"
"log"
"os"
)
func privateKey() ssh.Signer {
buf, err := ioutil.ReadFile("./id_rsa")
if err != nil {
panic(err)
}
key, err := ssh.ParsePrivateKey(buf)
if err != nil {
panic(err)
}
return key
}
func main() {
privateKey := privateKey()
// Create client config
config := &ssh.ClientConfig{
User: "core",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(privateKey),
},
}
// Connect to ssh server
conn, err := ssh.Dial("tcp", "myhost.com:22", config)
if err != nil {
log.Fatalf("unable to connect: %s", err)
}
defer conn.Close()
// Create a session
session, err := conn.NewSession()
if err != nil {
log.Fatalf("unable to create session: %s", err)
}
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin // How can session.Stdin be a tty?
//////////////////////////////////////////////////////////////////////
// Stuff for interactive shell
// Set up terminal modes
//modes := ssh.TerminalModes{
// ssh.ECHO: 1, // enable echoing
// ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
// ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
//}
// Request pseudo terminal
//if err := session.RequestPty("xterm-256color", 80, 40, modes); err != nil {
// log.Fatalf("request for pseudo terminal failed: %s", err)
//}
// Start remote shell
//if err := session.Shell(); err != nil {
// log.Fatalf("failed to start shell: %s", err)
//}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Stuff for executing remote command
// 2202 in my example is actually the pid of a running container
if err := session.Run("sudo nsenter --target 2202 --mount --uts --ipc --net --pid"); err != nil {
panic("Failed to run: " + err.Error())
}
//////////////////////////////////////////////////////////////////////
session.Wait()
}发布于 2014-10-13 01:08:52
超酷,我让它工作了,但仍然有一种魔力我无法理解。但是,我更改了代码,如下所示。导致正确的pty行为的基本变化是包"code.google.com/p/go.crypto/ssh/terminal"的使用。使用它的MakeRaw(fd)似乎会导致支持正确的pty行为的副作用。也要感谢舰队项目,在那里我找到了工作示例https://github.com/coreos/fleet/blob/master/ssh/ssh.go。
// The following two lines makes the terminal work properly because of
// side-effects I don't understand.
fd := int(os.Stdin.Fd())
oldState, err := terminal.MakeRaw(fd)
if err != nil {
panic(err)
}
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
termWidth, termHeight, err := terminal.GetSize(fd)
if err != nil {
panic(err)
}
// Set up terminal modes
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
log.Fatalf("request for pseudo terminal failed: %s", err)
}
if err := session.Run("sudo nsenter --target 2202 --mount --uts --ipc --net --pid"); err != nil {
// if the session terminated normally, err should be ExitError; in that
// case, return nil error and actual exit status of command
if exitErr, ok := err.(*ssh.ExitError); ok {
fmt.Printf("exit code: %#v\n", exitErr.ExitStatus())
} else {
panic("Failed to run: " + err.Error())
}
}
session.Close()
terminal.Restore(fd, oldState)https://stackoverflow.com/questions/26315572
复制相似问题