Add support for ssh:// and unix:// podman clients

* Make context keys package safe
 * Add support for PODMAN_HOST and PODMAN_SSHKEY
 * Add slight increasing delay when client connections fail
 * Remove usages of path.Join(), added JoinURL(). '/' is not OS
   dependent.

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce 2020-02-19 17:38:43 -07:00
parent 83a9b318e1
commit 0f0b4fd3c2
14 changed files with 231 additions and 213 deletions

View File

@ -1,113 +0,0 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"golang.org/x/crypto/ssh"
)
// remote PODMAN_HOST=ssh://<user>@<host>[:port]/run/podman/podman.sock
// local PODMAN_HOST=unix://run/podman/podman.sock
var (
DefaultURL = "unix://root@localhost/run/podman/podman.sock"
)
func main() {
connectionURL := DefaultURL
if value, found := os.LookupEnv("PODMAN_HOST"); found {
connectionURL = value
}
_url, err := url.Parse(connectionURL)
if err != nil {
die("Value of PODMAN_HOST is not a valid url: %s\n", connectionURL)
}
if _url.Scheme != "ssh" && _url.Scheme != "unix" {
die("Scheme from PODMAN_HOST is not supported: %s\n", _url.Scheme)
}
// Now we setup the http client to use the connection above
client := &http.Client{}
if _url.Scheme == "ssh" {
var auth ssh.AuthMethod
if value, found := os.LookupEnv("PODMAN_SSHKEY"); found {
auth, err = publicKey(value)
if err != nil {
die("Failed to parse %s: %v\n", value, err)
}
} else {
die("PODMAN_SSHKEY was not defined\n")
}
// Connect to sshd
bastion, err := ssh.Dial("tcp",
net.JoinHostPort(_url.Hostname(), _url.Port()),
&ssh.ClientConfig{
User: _url.User.Username(),
Auth: []ssh.AuthMethod{auth},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
},
)
if err != nil {
die("Failed to build ssh tunnel")
}
defer bastion.Close()
client.Transport = &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
// Now we make the connection to the unix domain socket on the server using the ssh tunnel
return bastion.Dial("unix", _url.Path)
},
}
} else {
client.Transport = &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
d := net.Dialer{}
return d.DialContext(ctx, "unix", _url.Path)
},
DisableCompression: true,
}
}
resp, err := client.Get("http://localhost/v1.24/images/json")
if err != nil {
die(err.Error())
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var output bytes.Buffer
_ = json.Indent(&output, body, "", " ")
fmt.Printf("%s\n", output.String())
os.Exit(0)
}
func die(format string, a ...interface{}) {
fmt.Fprintf(os.Stderr, format, a...)
fmt.Fprintf(os.Stderr, "\n")
os.Exit(1)
}
func publicKey(path string) (ssh.AuthMethod, error) {
key, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return nil, err
}
return ssh.PublicKeys(signer), nil
}

1
go.sum
View File

@ -638,6 +638,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 h1:bw9doJza/SFBEweII/rHQh338oozWyiFsBRHtrflcws=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -1,22 +1,34 @@
package bindings package bindings
import ( import (
"bufio"
"context" "context"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"os"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"time"
"github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/api/handlers"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
"k8s.io/client-go/util/homedir"
) )
var ( var (
defaultConnectionPath string = filepath.Join(fmt.Sprintf("v%s", handlers.MinimalApiVersion), "libpod") basePath = &url.URL{
Scheme: "http",
Host: "d",
Path: "/v" + handlers.MinimalApiVersion + "/libpod",
}
) )
type APIResponse struct { type APIResponse struct {
@ -25,57 +37,111 @@ type APIResponse struct {
} }
type Connection struct { type Connection struct {
scheme string _url *url.URL
address string
client *http.Client client *http.Client
} }
type valueKey string
const (
clientKey = valueKey("client")
)
// GetClient from context build by NewConnection()
func GetClient(ctx context.Context) (*Connection, error) {
c, ok := ctx.Value(clientKey).(*Connection)
if !ok {
return nil, errors.Errorf("ClientKey not set in context")
}
return c, nil
}
// JoinURL elements with '/'
func JoinURL(elements ...string) string {
return strings.Join(elements, "/")
}
// NewConnection takes a URI as a string and returns a context with the // NewConnection 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.
// //
// A valid URI connection should be scheme:// // A valid URI connection should be scheme://
// For example tcp://localhost:<port> // For example tcp://localhost:<port>
// or unix://run/podman/podman.sock // or unix:///run/podman/podman.sock
func NewConnection(uri string) (context.Context, error) { // or ssh://<user>@<host>[:port]/run/podman/podman.sock?secure=True
u, err := url.Parse(uri) func NewConnection(ctx context.Context, uri string, identity ...string) (context.Context, error) {
if err != nil { var (
return nil, err err error
} secure bool
// TODO once ssh is implemented, remove this block and )
// add it to the conditional beneath it if v, found := os.LookupEnv("PODMAN_HOST"); found {
if u.Scheme == "ssh" { uri = v
return nil, ErrNotImplemented
}
if u.Scheme != "tcp" && u.Scheme != "unix" {
return nil, errors.Errorf("%s is not a support schema", u.Scheme)
} }
if u.Scheme == "tcp" && !strings.HasPrefix(uri, "tcp://") { if v, found := os.LookupEnv("PODMAN_SSHKEY"); found {
identity = []string{v}
}
_url, err := url.Parse(uri)
if err != nil {
return nil, errors.Wrapf(err, "Value of PODMAN_HOST is not a valid url: %s", uri)
}
// Now we setup the http client to use the connection above
var client *http.Client
switch _url.Scheme {
case "ssh":
secure, err = strconv.ParseBool(_url.Query().Get("secure"))
if err != nil {
secure = false
}
client, err = sshClient(_url, identity[0], secure)
case "unix":
if !strings.HasPrefix(uri, "unix:///") {
// autofix unix://path_element vs unix:///path_element
_url.Path = JoinURL(_url.Host, _url.Path)
_url.Host = ""
}
client, err = unixClient(_url)
case "tcp":
if !strings.HasPrefix(uri, "tcp://") {
return nil, errors.New("tcp URIs should begin with tcp://") return nil, errors.New("tcp URIs should begin with tcp://")
} }
client, err = tcpClient(_url)
address := u.Path default:
if u.Scheme == "tcp" { return nil, errors.Errorf("%s is not a support schema", _url.Scheme)
address = u.Host
} }
newConn := newConnection(u.Scheme, address) if err != nil {
ctx := context.WithValue(context.Background(), "conn", &newConn) return nil, errors.Wrapf(err, "Failed to create %sClient", _url.Scheme)
}
ctx = context.WithValue(ctx, clientKey, &Connection{_url, client})
if err := pingNewConnection(ctx); err != nil { if err := pingNewConnection(ctx); err != nil {
return nil, err return nil, err
} }
return ctx, nil return ctx, nil
} }
func tcpClient(_url *url.URL) (*http.Client, error) {
return &http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("tcp", _url.Path)
},
DisableCompression: true,
},
}, nil
}
// pingNewConnection pings to make sure the RESTFUL service is up // pingNewConnection pings to make sure the RESTFUL service is up
// and running. it should only be used where initializing a connection // and running. it should only be used where initializing a connection
func pingNewConnection(ctx context.Context) error { func pingNewConnection(ctx context.Context) error {
conn, err := GetConnectionFromContext(ctx) client, err := GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
// the ping endpoint sits at / in this case // the ping endpoint sits at / in this case
response, err := conn.DoRequest(nil, http.MethodGet, "../../../_ping", nil) response, err := client.DoRequest(nil, http.MethodGet, "../../../_ping", nil)
if err != nil { if err != nil {
return err return err
} }
@ -85,26 +151,58 @@ func pingNewConnection(ctx context.Context) error {
return errors.Errorf("ping response was %q", response.StatusCode) return errors.Errorf("ping response was %q", response.StatusCode)
} }
// newConnection takes a scheme and address and creates a connection from it func sshClient(_url *url.URL, identity string, secure bool) (*http.Client, error) {
func newConnection(scheme, address string) Connection { auth, err := publicKey(identity)
client := http.Client{ if err != nil {
Transport: &http.Transport{ return nil, errors.Wrapf(err, "Failed to parse identity %s: %v\n", _url.String(), identity)
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(scheme, address)
},
},
}
newConn := Connection{
client: &client,
address: address,
scheme: scheme,
}
return newConn
} }
func (c *Connection) makeEndpoint(u string) string { callback := ssh.InsecureIgnoreHostKey()
// The d character in the url is discarded and is meaningless if secure {
return fmt.Sprintf("http://d/%s%s", defaultConnectionPath, u) key := hostKey(_url.Hostname())
if key != nil {
callback = ssh.FixedHostKey(key)
}
}
bastion, err := ssh.Dial("tcp",
net.JoinHostPort(_url.Hostname(), _url.Port()),
&ssh.ClientConfig{
User: _url.User.Username(),
Auth: []ssh.AuthMethod{auth},
HostKeyCallback: callback,
HostKeyAlgorithms: []string{
ssh.KeyAlgoRSA,
ssh.KeyAlgoDSA,
ssh.KeyAlgoECDSA256,
ssh.KeyAlgoECDSA384,
ssh.KeyAlgoECDSA521,
ssh.KeyAlgoED25519,
},
Timeout: 5 * time.Second,
},
)
if err != nil {
return nil, errors.Wrapf(err, "Connection to bastion host (%s) failed.", _url.String())
}
return &http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return bastion.Dial("unix", _url.Path)
},
}}, nil
}
func unixClient(_url *url.URL) (*http.Client, error) {
return &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
d := net.Dialer{}
return d.DialContext(ctx, "unix", _url.Path)
},
DisableCompression: true,
},
}, nil
} }
// DoRequest assembles the http request and returns the response // DoRequest assembles the http request and returns the response
@ -121,7 +219,7 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
// Lets eventually use URL for this which might lead to safer // Lets eventually use URL for this which might lead to safer
// usage // usage
safeEndpoint := fmt.Sprintf(endpoint, safePathValues...) safeEndpoint := fmt.Sprintf(endpoint, safePathValues...)
e := c.makeEndpoint(safeEndpoint) e := basePath.String() + safeEndpoint
req, err := http.NewRequest(httpMethod, e, httpBody) req, err := http.NewRequest(httpMethod, e, httpBody)
if err != nil { if err != nil {
return nil, err return nil, err
@ -140,21 +238,11 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
if err == nil { if err == nil {
break break
} }
time.Sleep(time.Duration(i*100) * time.Millisecond)
} }
return &APIResponse{response, req}, err return &APIResponse{response, req}, err
} }
// GetConnectionFromContext returns a bindings connection from the context
// being passed into each method.
func GetConnectionFromContext(ctx context.Context) (*Connection, error) {
c := ctx.Value("conn")
if c == nil {
return nil, errors.New("unable to get connection from context")
}
conn := c.(*Connection)
return conn, nil
}
// FiltersToString converts our typical filter format of a // FiltersToString converts our typical filter format of a
// map[string][]string to a query/html safe string. // map[string][]string to a query/html safe string.
func FiltersToString(filters map[string][]string) (string, error) { func FiltersToString(filters map[string][]string) (string, error) {
@ -189,3 +277,45 @@ func (h *APIResponse) IsClientError() bool {
func (h *APIResponse) IsServerError() bool { func (h *APIResponse) IsServerError() bool {
return h.Response.StatusCode/100 == 5 return h.Response.StatusCode/100 == 5
} }
func publicKey(path string) (ssh.AuthMethod, error) {
key, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return nil, err
}
return ssh.PublicKeys(signer), nil
}
func hostKey(host string) ssh.PublicKey {
// parse OpenSSH known_hosts file
// ssh or use ssh-keyscan to get initial key
known_hosts := filepath.Join(homedir.HomeDir(), ".ssh", "known_hosts")
fd, err := os.Open(known_hosts)
if err != nil {
logrus.Error(err)
return nil
}
scanner := bufio.NewScanner(fd)
for scanner.Scan() {
_, hosts, key, _, _, err := ssh.ParseKnownHosts(scanner.Bytes())
if err != nil {
logrus.Errorf("Failed to parse known_hosts: %s", scanner.Text())
continue
}
for _, h := range hosts {
if h == host {
return key
}
}
}
return nil
}

View File

@ -16,7 +16,7 @@ import (
// size information should also be included. Finally, the sync bool synchronizes the OCI runtime and // size information should also be included. Finally, the sync bool synchronizes the OCI runtime and
// container state. // container state.
func List(ctx context.Context, filters map[string][]string, all *bool, last *int, pod, size, sync *bool) ([]lpapiv2.ListContainer, error) { // nolint:typecheck func List(ctx context.Context, filters map[string][]string, all *bool, last *int, pod, size, sync *bool) ([]lpapiv2.ListContainer, error) { // nolint:typecheck
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -59,7 +59,7 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
var ( var (
pruneResponse []string pruneResponse []string
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -82,7 +82,7 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
// that the container should be removed forcibly (example, even it is running). The volumes // that the container should be removed forcibly (example, even it is running). The volumes
// bool dictates that a container's volumes should also be removed. // bool dictates that a container's volumes should also be removed.
func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error { func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -105,7 +105,7 @@ func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
// should be calculated. Calculating the size of a container requires extra work from the filesystem and // should be calculated. Calculating the size of a container requires extra work from the filesystem and
// is therefore slower. // is therefore slower.
func Inspect(ctx context.Context, nameOrID string, size *bool) (*libpod.InspectContainerData, error) { func Inspect(ctx context.Context, nameOrID string, size *bool) (*libpod.InspectContainerData, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -125,7 +125,7 @@ func Inspect(ctx context.Context, nameOrID string, size *bool) (*libpod.InspectC
// representation of a signal like 'SIGKILL'. The nameOrID can be a container name // representation of a signal like 'SIGKILL'. The nameOrID can be a container name
// or a partial/full ID // or a partial/full ID
func Kill(ctx context.Context, nameOrID string, signal string) error { func Kill(ctx context.Context, nameOrID string, signal string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -143,7 +143,7 @@ func Logs() {}
// Pause pauses a given container. The nameOrID can be a container name // Pause pauses a given container. The nameOrID can be a container name
// or a partial/full ID. // or a partial/full ID.
func Pause(ctx context.Context, nameOrID string) error { func Pause(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -158,7 +158,7 @@ func Pause(ctx context.Context, nameOrID string) error {
// or a partial/full ID. The optional timeout specifies the number of seconds to wait // or a partial/full ID. The optional timeout specifies the number of seconds to wait
// for the running container to stop before killing it. // for the running container to stop before killing it.
func Restart(ctx context.Context, nameOrID string, timeout *int) error { func Restart(ctx context.Context, nameOrID string, timeout *int) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -177,7 +177,7 @@ func Restart(ctx context.Context, nameOrID string, timeout *int) error {
// or a partial/full ID. The optional parameter for detach keys are to override the default // or a partial/full ID. The optional parameter for detach keys are to override the default
// detach key sequence. // detach key sequence.
func Start(ctx context.Context, nameOrID string, detachKeys *string) error { func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -198,7 +198,7 @@ func Top() {}
// Unpause resumes the given paused container. The nameOrID can be a container name // Unpause resumes the given paused container. The nameOrID can be a container name
// or a partial/full ID. // or a partial/full ID.
func Unpause(ctx context.Context, nameOrID string) error { func Unpause(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -213,7 +213,7 @@ func Unpause(ctx context.Context, nameOrID string) error {
// or a partial/full ID. // or a partial/full ID.
func Wait(ctx context.Context, nameOrID string) (int32, error) { func Wait(ctx context.Context, nameOrID string) (int32, error) {
var exitCode int32 var exitCode int32
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return exitCode, err return exitCode, err
} }
@ -228,7 +228,7 @@ func Wait(ctx context.Context, nameOrID string) (int32, error) {
// exists in local storage. The nameOrID can be a container name // exists in local storage. The nameOrID can be a container name
// or a partial/full ID. // or a partial/full ID.
func Exists(ctx context.Context, nameOrID string) (bool, error) { func Exists(ctx context.Context, nameOrID string) (bool, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -243,7 +243,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// or a partial/full ID // or a partial/full ID
func Stop(ctx context.Context, nameOrID string, timeout *int) error { func Stop(ctx context.Context, nameOrID string, timeout *int) error {
params := make(map[string]string) params := make(map[string]string)
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }

View File

@ -13,7 +13,7 @@ import (
func CreateWithSpec(ctx context.Context, s specgen.SpecGenerator) (utils.ContainerCreateResponse, error) { func CreateWithSpec(ctx context.Context, s specgen.SpecGenerator) (utils.ContainerCreateResponse, error) {
var ccr utils.ContainerCreateResponse var ccr utils.ContainerCreateResponse
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return ccr, err return ccr, err
} }

View File

@ -11,7 +11,7 @@ import (
// RunHealthCheck executes the container's healthcheck and returns the health status of the // RunHealthCheck executes the container's healthcheck and returns the health status of the
// container. // container.
func RunHealthCheck(ctx context.Context, nameOrID string) (*libpod.HealthCheckStatus, error) { func RunHealthCheck(ctx context.Context, nameOrID string) (*libpod.HealthCheckStatus, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -10,7 +10,7 @@ import (
// Mount mounts an existing container to the filesystem. It returns the path // Mount mounts an existing container to the filesystem. It returns the path
// of the mounted container in string format. // of the mounted container in string format.
func Mount(ctx context.Context, nameOrID string) (string, error) { func Mount(ctx context.Context, nameOrID string) (string, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -27,7 +27,7 @@ func Mount(ctx context.Context, nameOrID string) (string, error) {
// Unmount unmounts a container from the filesystem. The container must not be running // Unmount unmounts a container from the filesystem. The container must not be running
// or the unmount will fail. // or the unmount will fail.
func Unmount(ctx context.Context, nameOrID string) error { func Unmount(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -40,7 +40,7 @@ func Unmount(ctx context.Context, nameOrID string) error {
// GetMountedContainerPaths returns a map of mounted containers and their mount locations. // GetMountedContainerPaths returns a map of mounted containers and their mount locations.
func GetMountedContainerPaths(ctx context.Context) (map[string]string, error) { func GetMountedContainerPaths(ctx context.Context) (map[string]string, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -14,7 +14,7 @@ import (
// Exists a lightweight way to determine if an image exists in local storage. It returns a // Exists a lightweight way to determine if an image exists in local storage. It returns a
// boolean response. // boolean response.
func Exists(ctx context.Context, nameOrID string) (bool, error) { func Exists(ctx context.Context, nameOrID string) (bool, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -29,7 +29,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// ways to alter the image query. // ways to alter the image query.
func List(ctx context.Context, all *bool, filters map[string][]string) ([]*handlers.ImageSummary, error) { func List(ctx context.Context, all *bool, filters map[string][]string) ([]*handlers.ImageSummary, error) {
var imageSummary []*handlers.ImageSummary var imageSummary []*handlers.ImageSummary
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -54,7 +54,7 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*handl
// Get performs an image inspect. To have the on-disk size of the image calculated, you can // Get performs an image inspect. To have the on-disk size of the image calculated, you can
// use the optional size parameter. // use the optional size parameter.
func GetImage(ctx context.Context, nameOrID string, size *bool) (*inspect.ImageData, error) { func GetImage(ctx context.Context, nameOrID string, size *bool) (*inspect.ImageData, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -77,7 +77,7 @@ func ImageTree(ctx context.Context, nameOrId string) error {
// History returns the parent layers of an image. // History returns the parent layers of an image.
func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) { func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) {
var history []*handlers.HistoryResponse var history []*handlers.HistoryResponse
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -89,7 +89,7 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse,
} }
func Load(ctx context.Context, r io.Reader) error { func Load(ctx context.Context, r io.Reader) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -103,7 +103,7 @@ func Load(ctx context.Context, r io.Reader) error {
// the image by removing all all containers, including those that are Running, first. // the image by removing all all containers, including those that are Running, first.
func Remove(ctx context.Context, nameOrID string, force *bool) ([]map[string]string, error) { func Remove(ctx context.Context, nameOrID string, force *bool) ([]map[string]string, error) {
var deletes []map[string]string var deletes []map[string]string
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -121,7 +121,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) ([]map[string]str
// Export saves an image from local storage as a tarball or image archive. The optional format // Export saves an image from local storage as a tarball or image archive. The optional format
// parameter is used to change the format of the output. // parameter is used to change the format of the output.
func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, compress *bool) error { func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, compress *bool) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -149,7 +149,7 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
var ( var (
deleted []string deleted []string
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -170,7 +170,7 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required. // Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
func Tag(ctx context.Context, nameOrID, tag, repo string) error { func Tag(ctx context.Context, nameOrID, tag, repo string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }

View File

@ -16,7 +16,7 @@ func Search(ctx context.Context, term string, limit *int, filters map[string][]s
var ( var (
searchResults []image.SearchResult searchResults []image.SearchResult
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -10,7 +10,7 @@ import (
func Create() {} func Create() {}
func Inspect(ctx context.Context, nameOrID string) (map[string]interface{}, error) { func Inspect(ctx context.Context, nameOrID string) (map[string]interface{}, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -23,7 +23,7 @@ func Inspect(ctx context.Context, nameOrID string) (map[string]interface{}, erro
} }
func Remove(ctx context.Context, nameOrID string) error { func Remove(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -38,7 +38,7 @@ func List(ctx context.Context) ([]*libcni.NetworkConfigList, error) {
var ( var (
netList []*libcni.NetworkConfigList netList []*libcni.NetworkConfigList
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -16,7 +16,7 @@ func CreatePod() error {
// Exists is a lightweight method to determine if a pod exists in local storage // Exists is a lightweight method to determine if a pod exists in local storage
func Exists(ctx context.Context, nameOrID string) (bool, error) { func Exists(ctx context.Context, nameOrID string) (bool, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -29,7 +29,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// Inspect returns low-level information about the given pod. // Inspect returns low-level information about the given pod.
func Inspect(ctx context.Context, nameOrID string) (*libpod.PodInspect, error) { func Inspect(ctx context.Context, nameOrID string) (*libpod.PodInspect, error) {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -44,7 +44,7 @@ func Inspect(ctx context.Context, nameOrID string) (*libpod.PodInspect, error) {
// Kill sends a SIGTERM to all the containers in a pod. The optional signal parameter // Kill sends a SIGTERM to all the containers in a pod. The optional signal parameter
// can be used to override SIGTERM. // can be used to override SIGTERM.
func Kill(ctx context.Context, nameOrID string, signal *string) error { func Kill(ctx context.Context, nameOrID string, signal *string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -61,7 +61,7 @@ func Kill(ctx context.Context, nameOrID string, signal *string) error {
// Pause pauses all running containers in a given pod. // Pause pauses all running containers in a given pod.
func Pause(ctx context.Context, nameOrID string) error { func Pause(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -74,7 +74,7 @@ func Pause(ctx context.Context, nameOrID string) error {
// Prune removes all non-running pods in local storage. // Prune removes all non-running pods in local storage.
func Prune(ctx context.Context) error { func Prune(ctx context.Context) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -91,7 +91,7 @@ func List(ctx context.Context, filters map[string][]string) ([]*libpod.PodInspec
var ( var (
inspect []*libpod.PodInspect inspect []*libpod.PodInspect
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -112,7 +112,7 @@ func List(ctx context.Context, filters map[string][]string) ([]*libpod.PodInspec
// Restart restarts all containers in a pod. // Restart restarts all containers in a pod.
func Restart(ctx context.Context, nameOrID string) error { func Restart(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -126,7 +126,7 @@ func Restart(ctx context.Context, nameOrID string) error {
// Remove deletes a Pod from from local storage. The optional force parameter denotes // Remove deletes a Pod from from local storage. The optional force parameter denotes
// that the Pod can be removed even if in a running state. // that the Pod can be removed even if in a running state.
func Remove(ctx context.Context, nameOrID string, force *bool) error { func Remove(ctx context.Context, nameOrID string, force *bool) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -143,7 +143,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) error {
// Start starts all containers in a pod. // Start starts all containers in a pod.
func Start(ctx context.Context, nameOrID string) error { func Start(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -162,7 +162,7 @@ func Stats() error {
// Stop stops all containers in a Pod. The optional timeout parameter can be // Stop stops all containers in a Pod. The optional timeout parameter can be
// used to override the timeout before the container is killed. // used to override the timeout before the container is killed.
func Stop(ctx context.Context, nameOrID string, timeout *int) error { func Stop(ctx context.Context, nameOrID string, timeout *int) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }
@ -184,7 +184,7 @@ func Top() error {
// Unpause unpauses all paused containers in a Pod. // Unpause unpauses all paused containers in a Pod.
func Unpause(ctx context.Context, nameOrID string) error { func Unpause(ctx context.Context, nameOrID string) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }

View File

@ -114,7 +114,7 @@ func newBindingTest() *bindingTest {
runRoot: filepath.Join(tmpPath, "run"), runRoot: filepath.Join(tmpPath, "run"),
artifactDirPath: "", artifactDirPath: "",
imageCacheDir: "", imageCacheDir: "",
sock: fmt.Sprintf("unix:%s", filepath.Join(tmpPath, "api.sock")), sock: fmt.Sprintf("unix://%s", filepath.Join(tmpPath, "api.sock")),
tempDirPath: tmpPath, tempDirPath: tmpPath,
} }
return &b return &b

View File

@ -38,7 +38,7 @@ var _ = Describe("Podman images", func() {
bt.RestoreImagesFromCache() bt.RestoreImagesFromCache()
s = bt.startAPIService() s = bt.startAPIService()
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
connText, err = bindings.NewConnection(bt.sock) connText, err = bindings.NewConnection(context.Background(), bt.sock)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
}) })

View File

@ -16,7 +16,7 @@ func Create(ctx context.Context, config handlers.VolumeCreateConfig) (string, er
var ( var (
volumeID string volumeID string
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -32,7 +32,7 @@ func Inspect(ctx context.Context, nameOrID string) (*libpod.InspectVolumeData, e
var ( var (
inspect libpod.InspectVolumeData inspect libpod.InspectVolumeData
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -55,7 +55,7 @@ func Prune(ctx context.Context) ([]string, error) {
var ( var (
pruned []string pruned []string
) )
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -69,7 +69,7 @@ func Prune(ctx context.Context) ([]string, error) {
// Remove deletes the given volume from storage. The optional force parameter // Remove deletes the given volume from storage. The optional force parameter
// is used to remove a volume even if it is being used by a container. // is used to remove a volume even if it is being used by a container.
func Remove(ctx context.Context, nameOrID string, force *bool) error { func Remove(ctx context.Context, nameOrID string, force *bool) error {
conn, err := bindings.GetConnectionFromContext(ctx) conn, err := bindings.GetClient(ctx)
if err != nil { if err != nil {
return err return err
} }