How to use go language to realize remote command execution

Time:2020-5-28

preface

What is the use of remote command execution? Why remote command execution? If you only have 2 or 3 servers to manage, remote command execution does not have much effect. You can log in to each server to complete various operations. When you have more than three servers, the remote command can greatly improve your productivity.

If you have a tool that can execute commands remotely, you can operate multiple machines like a single machine. The more machines you have, the more efficiency you can improve. The most common way to execute commands remotely is to use SSH protocol to send the commands to the remote machine for execution and get the returned results.

General order

The so-called general command is the command that will be executed in a certain period of time. For example, grep, cat and so on. The steps to execute the command are: connect, execute and get the result

connect

The connection contains authentication. You can use password or SSH key to authenticate. For simplicity, the following example uses password authentication to complete the connection.


import ( 
 "fmt"
 "time"

 "golang.org/x/crypto/ssh"
)

func connect(user, password, host string, port int) (*ssh.Session, error) { 
 var (
 auth  []ssh.AuthMethod
 addr  string
 clientConfig *ssh.ClientConfig
 client *ssh.Client
 session *ssh.Session
 err  error
 )
 // get auth method
 auth = make([]ssh.AuthMethod, 0)
 auth = append(auth, ssh.Password(password))

 clientConfig = &ssh.ClientConfig{
 User: user,
 Auth: auth,
 Timeout: 30 * time.Second,
 }

 // connet to ssh
 addr = fmt.Sprintf("%s:%d", host, port)

 if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
 return nil, err
 }

 // create session
 if session, err = client.NewSession(); err != nil {
 return nil, err
 }

 return session, nil
}

The connection method is very simple, as long as the login user *, * password *, * host name or IP *, * SSH port is provided

Execute, command get results

When the connection is successful, it is easy to execute the command


import ( 
 "fmt"
 "log"
 "os"
 "time"

 "golang.org/x/crypto/ssh"
)

func main() { 
 session, err := connect("root", "xxxxx", "127.0.0.1", 22)
 if err != nil {
 log.Fatal(err)
 }
 defer session.Close()

 session.Run("ls /; ls /abc")
}

After the above code runs, although the command executes normally, there is no normal output result or abnormal output result. To display the results, you need to modify func main for stdout and stderr redirection of the session as follows:


func main() { 
 session, err := connect("root", "xxxxx", "127.0.0.1", 22)
 if err != nil {
 log.Fatal(err)
 }
 defer session.Close()

 session.Stdout = os.Stdout
 session.Stderr = os.Stderr
 session.Run("ls /; ls /abc")
}

In this way, normal and abnormal information can be displayed on the screen.

Interactive commands

In the above way, you cannot execute interactive commands remotely, such as top. You can edit a file remotely, such asvi /etc/nginx/nginx.conf If you want to support interactive commands, you need the current terminal to take over the remote Pty.


func main() { 
 session, err := connect("root", "olordjesus", "dockers.iotalabs.io", 2210)
 if err != nil {
 log.Fatal(err)
 }
 defer session.Close()

 fd := int(os.Stdin.Fd())
 oldState, err := terminal.MakeRaw(fd)
 if err != nil {
 panic(err)
 }
 defer terminal.Restore(fd, oldState)

 // excute command
 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.Fatal(err)
 }

 session.Run("top")
}

summary

OK, so you can execute interactive commands. For example, the top above can also use thevi /etc/nginx/nignx.conf Command to edit files remotely. The above is all about how to use go language to implement remote command execution. I hope this article can help you learn python.