mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00
Use built-in ssh impl for all non-pty operations
Windows is not guaranteed to have the SSH feature installed, so prefer the use of the built-in ssh client for all operations other than podman machine ssh, which requires terminal pty logic. This restores previous behavior in 4.x. Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
This commit is contained in:

committed by
openshift-cherrypick-robot

parent
e852b970f6
commit
3123138729
@ -120,7 +120,7 @@ func ssh(cmd *cobra.Command, args []string) error {
|
||||
username = mc.SSH.RemoteUsername
|
||||
}
|
||||
|
||||
err = machine.CommonSSH(username, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, sshOpts.Args)
|
||||
err = machine.CommonSSHShell(username, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, sshOpts.Args)
|
||||
return utils.HandleOSExecError(err)
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -68,6 +68,7 @@ require (
|
||||
github.com/vbauerster/mpb/v8 v8.7.2
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2
|
||||
go.etcd.io/bbolt v1.3.9
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
|
||||
golang.org/x/net v0.22.0
|
||||
golang.org/x/sync v0.6.0
|
||||
@ -210,7 +211,6 @@ require (
|
||||
go.opentelemetry.io/otel/sdk v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.22.0 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/mod v0.15.0 // indirect
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
|
@ -42,8 +42,7 @@ func removeShares(mc *vmconfigs.MachineConfig) error {
|
||||
|
||||
func startShares(mc *vmconfigs.MachineConfig) error {
|
||||
for _, mount := range mc.Mounts {
|
||||
args := []string{"-q", "--"}
|
||||
|
||||
var args []string
|
||||
cleanTarget := path.Clean(mount.Target)
|
||||
requiresChattr := !strings.HasPrefix(cleanTarget, "/home") && !strings.HasPrefix(cleanTarget, "/mnt")
|
||||
if requiresChattr {
|
||||
|
@ -313,7 +313,7 @@ func (q *QEMUStubber) MountVolumesToVM(mc *vmconfigs.MachineConfig, quiet bool)
|
||||
// create mountpoint directory if it doesn't exist
|
||||
// because / is immutable, we have to monkey around with permissions
|
||||
// if we dont mount in /home or /mnt
|
||||
args := []string{"-q", "--"}
|
||||
var args []string
|
||||
if !strings.HasPrefix(mount.Target, "/home") && !strings.HasPrefix(mount.Target, "/mnt") {
|
||||
args = append(args, "sudo", "chattr", "-i", "/", ";")
|
||||
}
|
||||
@ -333,7 +333,7 @@ func (q *QEMUStubber) MountVolumesToVM(mc *vmconfigs.MachineConfig, quiet bool)
|
||||
if mount.ReadOnly {
|
||||
mountOptions = append(mountOptions, []string{"-o", "ro"}...)
|
||||
}
|
||||
err = machine.CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, append([]string{"-q", "--", "sudo", "mount"}, mountOptions...))
|
||||
err = machine.CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, append([]string{"sudo", "mount"}, mountOptions...))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1,31 +1,115 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// CommonSSH is a common function for ssh'ing to a podman machine using system-connections
|
||||
// and a port
|
||||
// TODO This should probably be taught about an machineconfig to reduce input
|
||||
func CommonSSH(username, identityPath, name string, sshPort int, inputArgs []string) error {
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, false, os.Stdin)
|
||||
return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, os.Stdin)
|
||||
}
|
||||
|
||||
func CommonSSHShell(username, identityPath, name string, sshPort int, inputArgs []string) error {
|
||||
return commonNativeSSH(username, identityPath, name, sshPort, inputArgs, os.Stdin)
|
||||
}
|
||||
|
||||
func CommonSSHSilent(username, identityPath, name string, sshPort int, inputArgs []string) error {
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, true, os.Stdin)
|
||||
return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, false, nil)
|
||||
}
|
||||
|
||||
func CommonSSHWithStdin(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
|
||||
return commonSSH(username, identityPath, name, sshPort, inputArgs, false, stdin)
|
||||
return commonBuiltinSSH(username, identityPath, name, sshPort, inputArgs, true, stdin)
|
||||
}
|
||||
|
||||
func commonSSH(username, identityPath, name string, sshPort int, inputArgs []string, silent bool, stdin io.Reader) error {
|
||||
func commonBuiltinSSH(username, identityPath, name string, sshPort int, inputArgs []string, passOutput bool, stdin io.Reader) error {
|
||||
config, err := createConfig(username, identityPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := ssh.Dial("tcp", fmt.Sprintf("localhost:%d", sshPort), config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
cmd := strings.Join(inputArgs, " ")
|
||||
logrus.Debugf("Running ssh command on machine %q: %s", name, cmd)
|
||||
session.Stdin = stdin
|
||||
if passOutput {
|
||||
session.Stdout = os.Stdout
|
||||
session.Stderr = os.Stderr
|
||||
} else if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||
return runSessionWithDebug(session, cmd)
|
||||
}
|
||||
|
||||
return session.Run(cmd)
|
||||
}
|
||||
|
||||
func runSessionWithDebug(session *ssh.Session, cmd string) error {
|
||||
outPipe, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errPipe, err := session.StderrPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logOuput := func(pipe io.Reader, done chan struct{}) {
|
||||
scanner := bufio.NewScanner(pipe)
|
||||
for scanner.Scan() {
|
||||
logrus.Debugf("ssh output: %s", scanner.Text())
|
||||
}
|
||||
done <- struct{}{}
|
||||
}
|
||||
if err := session.Start(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
completed := make(chan struct{}, 2)
|
||||
go logOuput(outPipe, completed)
|
||||
go logOuput(errPipe, completed)
|
||||
<-completed
|
||||
<-completed
|
||||
|
||||
return session.Wait()
|
||||
}
|
||||
|
||||
func createConfig(user string, identityPath string) (*ssh.ClientConfig, error) {
|
||||
key, err := os.ReadFile(identityPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ssh.ClientConfig{
|
||||
User: user,
|
||||
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func commonNativeSSH(username, identityPath, name string, sshPort int, inputArgs []string, stdin io.Reader) error {
|
||||
sshDestination := username + "@localhost"
|
||||
port := strconv.Itoa(sshPort)
|
||||
interactive := true
|
||||
@ -45,11 +129,9 @@ func commonSSH(username, identityPath, name string, sshPort int, inputArgs []str
|
||||
cmd := exec.Command("ssh", args...)
|
||||
logrus.Debugf("Executing: ssh %v\n", args)
|
||||
|
||||
if !silent {
|
||||
if err := setupIOPassthrough(cmd, interactive, stdin); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
|
Reference in New Issue
Block a user