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.