Expose Podman connection creation over existing SSH client connection

This enables creation of a Podman connection from a pre-existing SSH
connection, avoiding the creation of a new SSH connection when one
already exists, or writing the private key to the file system so it can
be found by the connection mechanism.

Signed-off-by: Matt Kingston <mattkingston@protonmail.com>
This commit is contained in:
Matt Kingston 2024-02-19 17:30:05 +01:00
parent 58bbe14d2e
commit 97eeaf04e1
No known key found for this signature in database
GPG Key ID: 29086A26F326ED5C
1 changed files with 27 additions and 0 deletions

View File

@ -21,6 +21,7 @@ import (
"github.com/containers/podman/v5/version" "github.com/containers/podman/v5/version"
"github.com/kevinburke/ssh_config" "github.com/kevinburke/ssh_config"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
gossh "golang.org/x/crypto/ssh"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
) )
@ -83,6 +84,28 @@ func NewConnection(ctx context.Context, uri string) (context.Context, error) {
return NewConnectionWithIdentity(ctx, uri, "", false) return NewConnectionWithIdentity(ctx, uri, "", false)
} }
// NewConnectionWithSshClient creates a new service connection with an existing SSH client
// connection
func NewConnectionWithSSHClient(ctx context.Context, sshClient *gossh.Client, relativePath string) (context.Context, error) {
_url, err := url.Parse(relativePath)
if err != nil {
return nil, fmt.Errorf("value of relativePath is not a valid url: %s: %w", relativePath, err)
}
_url.Scheme = "ssh"
_url.Host = sshClient.RemoteAddr().String()
_url.User = url.User(sshClient.User())
connection := Connection{URI: _url}
connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return ssh.DialNet(sshClient, "unix", _url)
},
}}
return newConnection(ctx, connection)
}
// NewConnectionWithIdentity takes a URI as a string and returns a context with the // NewConnectionWithIdentity takes a URI as a string and returns a context with the
// Connection embedded as a value. This context needs to be passed to each // Connection embedded as a value. This context needs to be passed to each
// endpoint to work correctly. // endpoint to work correctly.
@ -137,6 +160,10 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, identity string,
return nil, fmt.Errorf("unable to create connection. %q is not a supported schema", _url.Scheme) return nil, fmt.Errorf("unable to create connection. %q is not a supported schema", _url.Scheme)
} }
return newConnection(ctx, connection)
}
func newConnection(ctx context.Context, connection Connection) (context.Context, error) {
ctx = context.WithValue(ctx, clientKey, &connection) ctx = context.WithValue(ctx, clientKey, &connection)
serviceVersion, err := pingNewConnection(ctx) serviceVersion, err := pingNewConnection(ctx)
if err != nil { if err != nil {