podman

Форк
0
/
ssh.go 
137 строк · 3.6 Кб
1
package machine
2

3
import (
4
	"bufio"
5
	"fmt"
6
	"io"
7
	"os"
8
	"os/exec"
9
	"strconv"
10
	"strings"
11

12
	"github.com/sirupsen/logrus"
13
	"golang.org/x/crypto/ssh"
14
)
15

16
// CommonSSH is a common function for ssh'ing to a podman machine using system-connections
17
// and a port
18
// TODO This should probably be taught about an machineconfig to reduce input
19
func CommonSSH(username, identityPath, name string, sshPort int, inputArgs []string) error {
20
	return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, os.Stdin)
21
}
22

23
func CommonSSHShell(username, identityPath, name string, sshPort int, inputArgs []string) error {
24
	return commonNativeSSH(username, identityPath, name, sshPort, inputArgs, os.Stdin)
25
}
26

27
func CommonSSHSilent(username, identityPath, name string, sshPort int, inputArgs []string) error {
28
	return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, false, nil)
29
}
30

31
func CommonSSHWithStdin(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
32
	return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, stdin)
33
}
34

35
func commonBuiltinSSH(username, identityPath, name string, sshPort int, inputArgs []string, passOutput bool, stdin io.Reader) error {
36
	config, err := createConfig(username, identityPath)
37
	if err != nil {
38
		return err
39
	}
40

41
	client, err := ssh.Dial("tcp", fmt.Sprintf("localhost:%d", sshPort), config)
42
	if err != nil {
43
		return err
44
	}
45
	defer client.Close()
46

47
	session, err := client.NewSession()
48
	if err != nil {
49
		return err
50
	}
51
	defer session.Close()
52

53
	cmd := strings.Join(inputArgs, " ")
54
	logrus.Debugf("Running ssh command on machine %q: %s", name, cmd)
55
	session.Stdin = stdin
56
	if passOutput {
57
		session.Stdout = os.Stdout
58
		session.Stderr = os.Stderr
59
	} else if logrus.IsLevelEnabled(logrus.DebugLevel) {
60
		return runSessionWithDebug(session, cmd)
61
	}
62

63
	return session.Run(cmd)
64
}
65

66
func runSessionWithDebug(session *ssh.Session, cmd string) error {
67
	outPipe, err := session.StdoutPipe()
68
	if err != nil {
69
		return err
70
	}
71
	errPipe, err := session.StderrPipe()
72
	if err != nil {
73
		return err
74
	}
75
	logOuput := func(pipe io.Reader, done chan struct{}) {
76
		scanner := bufio.NewScanner(pipe)
77
		for scanner.Scan() {
78
			logrus.Debugf("ssh output: %s", scanner.Text())
79
		}
80
		done <- struct{}{}
81
	}
82
	if err := session.Start(cmd); err != nil {
83
		return err
84
	}
85
	completed := make(chan struct{}, 2)
86
	go logOuput(outPipe, completed)
87
	go logOuput(errPipe, completed)
88
	<-completed
89
	<-completed
90

91
	return session.Wait()
92
}
93

94
func createConfig(user string, identityPath string) (*ssh.ClientConfig, error) {
95
	key, err := os.ReadFile(identityPath)
96
	if err != nil {
97
		return nil, err
98
	}
99

100
	signer, err := ssh.ParsePrivateKey(key)
101
	if err != nil {
102
		return nil, err
103
	}
104

105
	return &ssh.ClientConfig{
106
		User:            user,
107
		Auth:            []ssh.AuthMethod{ssh.PublicKeys(signer)},
108
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
109
	}, nil
110
}
111

112
func commonNativeSSH(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
113
	sshDestination := username + "@localhost"
114
	port := strconv.Itoa(sshPort)
115
	interactive := true
116

117
	args := []string{"-i", identityPath, "-p", port, sshDestination,
118
		"-o", "IdentitiesOnly=yes",
119
		"-o", "StrictHostKeyChecking=no", "-o", "LogLevel=ERROR", "-o", "SetEnv=LC_ALL="}
120
	if len(inputArgs) > 0 {
121
		interactive = false
122
		args = append(args, inputArgs...)
123
	} else {
124
		// ensure we have a tty
125
		args = append(args, "-t")
126
		fmt.Printf("Connecting to vm %s. To close connection, use `~.` or `exit`\n", name)
127
	}
128

129
	cmd := exec.Command("ssh", args...)
130
	logrus.Debugf("Executing: ssh %v\n", args)
131

132
	if err := setupIOPassthrough(cmd, interactive, stdin); err != nil {
133
		return err
134
	}
135

136
	return cmd.Run()
137
}
138

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.