summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/cli/main.go113
-rw-r--r--cmd/podman/login.go4
-rw-r--r--cni/87-podman-bridge.conflist72
-rw-r--r--docs/source/markdown/podman-images.1.md8
-rw-r--r--go.sum1
-rw-r--r--libpod/image/filters.go2
-rw-r--r--pkg/api/handlers/decoder.go13
-rw-r--r--pkg/api/handlers/libpod/pods.go2
-rw-r--r--pkg/bindings/connection.go234
-rw-r--r--pkg/bindings/containers/containers.go24
-rw-r--r--pkg/bindings/containers/create.go2
-rw-r--r--pkg/bindings/containers/healthcheck.go2
-rw-r--r--pkg/bindings/containers/mount.go6
-rw-r--r--pkg/bindings/images/images.go18
-rw-r--r--pkg/bindings/images/search.go2
-rw-r--r--pkg/bindings/network/network.go6
-rw-r--r--pkg/bindings/pods/pods.go34
-rw-r--r--pkg/bindings/test/common_test.go30
-rw-r--r--pkg/bindings/test/images_test.go4
-rw-r--r--pkg/bindings/test/pods_test.go202
-rw-r--r--pkg/bindings/volumes/volumes.go8
-rw-r--r--pkg/spec/storage.go5
-rw-r--r--test/e2e/create_staticip_test.go16
-rw-r--r--test/e2e/run_volume_test.go20
-rw-r--r--test/e2e/search_test.go13
-rw-r--r--test/system/010-images.bats36
-rw-r--r--test/system/150-login.bats8
27 files changed, 607 insertions, 278 deletions
diff --git a/cmd/cli/main.go b/cmd/cli/main.go
deleted file mode 100644
index 4eec05ef2..000000000
--- a/cmd/cli/main.go
+++ /dev/null
@@ -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
-}
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index e5ff273b8..e09117833 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -82,6 +82,10 @@ func loginCmd(c *cliconfig.LoginValues) error {
server = registryFromFullName(scrubServer(args[0]))
}
+ if c.Flag("password").Changed {
+ fmt.Fprintf(os.Stderr, "WARNING! Using --password via the cli is insecure. Please consider using --password-stdin\n")
+ }
+
sc := image.GetSystemContext("", c.Authfile, false)
if c.Flag("tls-verify").Changed {
sc.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify)
diff --git a/cni/87-podman-bridge.conflist b/cni/87-podman-bridge.conflist
index a7bcf47bb..39e79b13c 100644
--- a/cni/87-podman-bridge.conflist
+++ b/cni/87-podman-bridge.conflist
@@ -1,41 +1,37 @@
{
- "cniVersion": "0.4.0",
- "name": "podman",
- "plugins": [
- {
- "type": "bridge",
- "bridge": "cni-podman0",
- "isGateway": true,
- "ipMasq": true,
- "ipam": {
- "type": "host-local",
- "routes": [
- {
- "dst": "0.0.0.0/0"
- }
- ],
- "ranges": [
- [
- {
- "subnet": "10.88.0.0/16",
- "gateway": "10.88.0.1"
- }
- ]
- ]
+ "cniVersion": "0.4.0",
+ "name": "podman",
+ "plugins": [
+ {
+ "type": "bridge",
+ "bridge": "cni-podman0",
+ "isGateway": true,
+ "ipMasq": true,
+ "ipam": {
+ "type": "host-local",
+ "routes": [{ "dst": "0.0.0.0/0" }],
+ "ranges": [
+ [
+ {
+ "subnet": "10.88.0.0/16",
+ "gateway": "10.88.0.1"
}
- },
- {
- "type": "portmap",
- "capabilities": {
- "portMappings": true
- }
- },
- {
- "type": "firewall",
- "backend": "iptables"
- },
- {
- "type": "tuning"
- }
- ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "portmap",
+ "capabilities": {
+ "portMappings": true
+ }
+ },
+ {
+ "type": "firewall",
+ "backend": "iptables"
+ },
+ {
+ "type": "tuning"
+ }
+ ]
}
diff --git a/docs/source/markdown/podman-images.1.md b/docs/source/markdown/podman-images.1.md
index d22fb940f..09778e3c2 100644
--- a/docs/source/markdown/podman-images.1.md
+++ b/docs/source/markdown/podman-images.1.md
@@ -29,11 +29,11 @@ Filter output based on conditions provided
Filters:
- **after==TIMESTRING**
- Filter on images created after the given time.Time.
+ **since=IMAGE**
+ Filter on images created after the given IMAGE (name or tag).
- **before==TIMESTRING**
- Filter on images created before the given time.Time.
+ **before=IMAGE**
+ Filter on images created before the given IMAGE (name or tag).
**dangling=true|false**
Show dangling images. Dangling images are a file system layer that was used in a previous build of an image and is no longer referenced by any active images. They are denoted with the <none> tag, consume disk space and serve no active purpose.
diff --git a/go.sum b/go.sum
index 4fc380adf..a1cf437a8 100644
--- a/go.sum
+++ b/go.sum
@@ -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-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-20190920225731-5eefd052ad72 h1:bw9doJza/SFBEweII/rHQh338oozWyiFsBRHtrflcws=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/libpod/image/filters.go b/libpod/image/filters.go
index d545f1bfc..7c7394930 100644
--- a/libpod/image/filters.go
+++ b/libpod/image/filters.go
@@ -141,7 +141,7 @@ func (ir *Runtime) createFilterFuncs(filters []string, img *Image) ([]ResultFilt
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
}
filterFuncs = append(filterFuncs, CreatedBeforeFilter(before.Created()))
- case "after":
+ case "since", "after":
after, err := ir.NewFromLocal(splitFilter[1])
if err != nil {
return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
diff --git a/pkg/api/handlers/decoder.go b/pkg/api/handlers/decoder.go
index 890d77ecc..03b86275d 100644
--- a/pkg/api/handlers/decoder.go
+++ b/pkg/api/handlers/decoder.go
@@ -3,8 +3,10 @@ package handlers
import (
"encoding/json"
"reflect"
+ "syscall"
"time"
+ "github.com/containers/libpod/pkg/util"
"github.com/gorilla/schema"
"github.com/sirupsen/logrus"
)
@@ -17,6 +19,9 @@ func NewAPIDecoder() *schema.Decoder {
d.IgnoreUnknownKeys(true)
d.RegisterConverter(map[string][]string{}, convertUrlValuesString)
d.RegisterConverter(time.Time{}, convertTimeString)
+
+ var Signal syscall.Signal
+ d.RegisterConverter(Signal, convertSignal)
return d
}
@@ -89,3 +94,11 @@ func convertTimeString(query string) reflect.Value {
func ParseDateTime(query string) time.Time {
return convertTimeString(query).Interface().(time.Time)
}
+
+func convertSignal(query string) reflect.Value {
+ signal, err := util.ParseSignal(query)
+ if err != nil {
+ logrus.Infof("convertSignal: Failed to parse %s: %s", query, err.Error())
+ }
+ return reflect.ValueOf(signal)
+}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 008b9b14b..f5700579b 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -119,7 +119,7 @@ func Pods(w http.ResponseWriter, r *http.Request) {
return
}
- if _, found := r.URL.Query()["filters"]; found {
+ if len(query.Filters) > 0 {
utils.Error(w, "filters are not implemented yet", http.StatusInternalServerError, define.ErrNotImplemented)
return
}
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index f270060a6..75f1fc6a5 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -1,22 +1,34 @@
package bindings
import (
+ "bufio"
"context"
"fmt"
"io"
+ "io/ioutil"
"net"
"net/http"
"net/url"
+ "os"
"path/filepath"
+ "strconv"
"strings"
+ "time"
"github.com/containers/libpod/pkg/api/handlers"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/crypto/ssh"
+ "k8s.io/client-go/util/homedir"
)
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 {
@@ -25,9 +37,28 @@ type APIResponse struct {
}
type Connection struct {
- scheme string
- address string
- client *http.Client
+ _url *url.URL
+ 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
@@ -36,46 +67,81 @@ type Connection struct {
//
// A valid URI connection should be scheme://
// For example tcp://localhost:<port>
-// or unix://run/podman/podman.sock
-func NewConnection(uri string) (context.Context, error) {
- u, err := url.Parse(uri)
- if err != nil {
- return nil, err
- }
- // TODO once ssh is implemented, remove this block and
- // add it to the conditional beneath it
- if u.Scheme == "ssh" {
- return nil, ErrNotImplemented
+// or unix:///run/podman/podman.sock
+// or ssh://<user>@<host>[:port]/run/podman/podman.sock?secure=True
+func NewConnection(ctx context.Context, uri string, identity ...string) (context.Context, error) {
+ var (
+ err error
+ secure bool
+ )
+ if v, found := os.LookupEnv("PODMAN_HOST"); found {
+ uri = v
}
- if u.Scheme != "tcp" && u.Scheme != "unix" {
- return nil, errors.Errorf("%s is not a support schema", u.Scheme)
+
+ if v, found := os.LookupEnv("PODMAN_SSHKEY"); found {
+ identity = []string{v}
}
- if u.Scheme == "tcp" && !strings.HasPrefix(uri, "tcp://") {
- return nil, errors.New("tcp URIs should begin with tcp://")
+ _url, err := url.Parse(uri)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Value of PODMAN_HOST is not a valid url: %s", uri)
}
- address := u.Path
- if u.Scheme == "tcp" {
- address = u.Host
+ // 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://")
+ }
+ client, err = tcpClient(_url)
+ default:
+ return nil, errors.Errorf("%s is not a support schema", _url.Scheme)
+ }
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to create %sClient", _url.Scheme)
}
- newConn := newConnection(u.Scheme, address)
- ctx := context.WithValue(context.Background(), "conn", &newConn)
+
+ ctx = context.WithValue(ctx, clientKey, &Connection{_url, client})
if err := pingNewConnection(ctx); err != nil {
return nil, err
}
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
// and running. it should only be used where initializing a connection
func pingNewConnection(ctx context.Context) error {
- conn, err := GetConnectionFromContext(ctx)
+ client, err := GetClient(ctx)
if err != nil {
return err
}
// 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 {
return err
}
@@ -85,26 +151,58 @@ func pingNewConnection(ctx context.Context) error {
return errors.Errorf("ping response was %q", response.StatusCode)
}
-// newConnection takes a scheme and address and creates a connection from it
-func newConnection(scheme, address string) Connection {
- client := http.Client{
- Transport: &http.Transport{
- DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
- return net.Dial(scheme, address)
+func sshClient(_url *url.URL, identity string, secure bool) (*http.Client, error) {
+ auth, err := publicKey(identity)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Failed to parse identity %s: %v\n", _url.String(), identity)
+ }
+
+ callback := ssh.InsecureIgnoreHostKey()
+ if secure {
+ 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())
}
- newConn := Connection{
- client: &client,
- address: address,
- scheme: scheme,
- }
- return newConn
+ return &http.Client{
+ Transport: &http.Transport{
+ DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
+ return bastion.Dial("unix", _url.Path)
+ },
+ }}, nil
}
-func (c *Connection) makeEndpoint(u string) string {
- // The d character in the url is discarded and is meaningless
- return fmt.Sprintf("http://d/%s%s", defaultConnectionPath, u)
+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
@@ -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
// usage
safeEndpoint := fmt.Sprintf(endpoint, safePathValues...)
- e := c.makeEndpoint(safeEndpoint)
+ e := basePath.String() + safeEndpoint
req, err := http.NewRequest(httpMethod, e, httpBody)
if err != nil {
return nil, err
@@ -140,21 +238,11 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
if err == nil {
break
}
+ time.Sleep(time.Duration(i*100) * time.Millisecond)
}
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
// map[string][]string to a query/html safe string.
func FiltersToString(filters map[string][]string) (string, error) {
@@ -189,3 +277,45 @@ func (h *APIResponse) IsClientError() bool {
func (h *APIResponse) IsServerError() bool {
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
+}
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 04f7f8802..a437e9a9b 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -16,7 +16,7 @@ import (
// size information should also be included. Finally, the sync bool synchronizes the OCI runtime and
// container state.
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 {
return nil, err
}
@@ -59,7 +59,7 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
var (
pruneResponse []string
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// bool dictates that a container's volumes should also be removed.
func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// is therefore slower.
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 {
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
// or a partial/full ID
func Kill(ctx context.Context, nameOrID string, signal string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -143,7 +143,7 @@ func Logs() {}
// Pause pauses a given container. The nameOrID can be a container name
// or a partial/full ID.
func Pause(ctx context.Context, nameOrID string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// for the running container to stop before killing it.
func Restart(ctx context.Context, nameOrID string, timeout *int) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// detach key sequence.
func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -198,7 +198,7 @@ func Top() {}
// Unpause resumes the given paused container. The nameOrID can be a container name
// or a partial/full ID.
func Unpause(ctx context.Context, nameOrID string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -213,7 +213,7 @@ func Unpause(ctx context.Context, nameOrID string) error {
// or a partial/full ID.
func Wait(ctx context.Context, nameOrID string) (int32, error) {
var exitCode int32
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// or a partial/full ID.
func Exists(ctx context.Context, nameOrID string) (bool, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return false, err
}
@@ -243,7 +243,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// or a partial/full ID
func Stop(ctx context.Context, nameOrID string, timeout *int) error {
params := make(map[string]string)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
diff --git a/pkg/bindings/containers/create.go b/pkg/bindings/containers/create.go
index 18b32335b..2943cb522 100644
--- a/pkg/bindings/containers/create.go
+++ b/pkg/bindings/containers/create.go
@@ -13,7 +13,7 @@ import (
func CreateWithSpec(ctx context.Context, s specgen.SpecGenerator) (utils.ContainerCreateResponse, error) {
var ccr utils.ContainerCreateResponse
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return ccr, err
}
diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go
index 9ed7f858d..dc607c1b3 100644
--- a/pkg/bindings/containers/healthcheck.go
+++ b/pkg/bindings/containers/healthcheck.go
@@ -11,7 +11,7 @@ import (
// RunHealthCheck executes the container's healthcheck and returns the health status of the
// container.
func RunHealthCheck(ctx context.Context, nameOrID string) (*libpod.HealthCheckStatus, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/mount.go b/pkg/bindings/containers/mount.go
index d68dee981..e0627d9a3 100644
--- a/pkg/bindings/containers/mount.go
+++ b/pkg/bindings/containers/mount.go
@@ -10,7 +10,7 @@ import (
// Mount mounts an existing container to the filesystem. It returns the path
// of the mounted container in string format.
func Mount(ctx context.Context, nameOrID string) (string, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// or the unmount will fail.
func Unmount(ctx context.Context, nameOrID string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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.
func GetMountedContainerPaths(ctx context.Context) (map[string]string, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index b19482943..271d58952 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -14,7 +14,7 @@ import (
// Exists a lightweight way to determine if an image exists in local storage. It returns a
// boolean response.
func Exists(ctx context.Context, nameOrID string) (bool, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return false, err
}
@@ -29,7 +29,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
// ways to alter the image query.
func List(ctx context.Context, all *bool, filters map[string][]string) ([]*handlers.ImageSummary, error) {
var imageSummary []*handlers.ImageSummary
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// use the optional size parameter.
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 {
return nil, err
}
@@ -77,7 +77,7 @@ func ImageTree(ctx context.Context, nameOrId string) error {
// History returns the parent layers of an image.
func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse, error) {
var history []*handlers.HistoryResponse
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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 {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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.
func Remove(ctx context.Context, nameOrID string, force *bool) ([]map[string]string, error) {
var deletes []map[string]string
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// 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 {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -149,7 +149,7 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
var (
deleted []string
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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.
func Tag(ctx context.Context, nameOrID, tag, repo string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
diff --git a/pkg/bindings/images/search.go b/pkg/bindings/images/search.go
index 58b25425b..dca1b0e63 100644
--- a/pkg/bindings/images/search.go
+++ b/pkg/bindings/images/search.go
@@ -16,7 +16,7 @@ func Search(ctx context.Context, term string, limit *int, filters map[string][]s
var (
searchResults []image.SearchResult
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go
index 97bbb8c42..c95b22953 100644
--- a/pkg/bindings/network/network.go
+++ b/pkg/bindings/network/network.go
@@ -10,7 +10,7 @@ import (
func Create() {}
func Inspect(ctx context.Context, nameOrID string) (map[string]interface{}, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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 {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -38,7 +38,7 @@ func List(ctx context.Context) ([]*libcni.NetworkConfigList, error) {
var (
netList []*libcni.NetworkConfigList
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go
index d079f01c2..838b22e43 100644
--- a/pkg/bindings/pods/pods.go
+++ b/pkg/bindings/pods/pods.go
@@ -16,7 +16,7 @@ func CreatePod() error {
// Exists is a lightweight method to determine if a pod exists in local storage
func Exists(ctx context.Context, nameOrID string) (bool, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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.
func Inspect(ctx context.Context, nameOrID string) (*libpod.PodInspect, error) {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// can be used to override SIGTERM.
func Kill(ctx context.Context, nameOrID string, signal *string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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.
func Pause(ctx context.Context, nameOrID string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -74,7 +74,7 @@ func Pause(ctx context.Context, nameOrID string) error {
// Prune removes all non-running pods in local storage.
func Prune(ctx context.Context) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -87,11 +87,11 @@ func Prune(ctx context.Context) error {
// List returns all pods in local storage. The optional filters parameter can
// be used to refine which pods should be listed.
-func List(ctx context.Context, filters map[string][]string) (*[]libpod.PodInspect, error) {
+func List(ctx context.Context, filters map[string][]string) ([]*libpod.PodInspect, error) {
var (
- inspect []libpod.PodInspect
+ inspect []*libpod.PodInspect
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
@@ -103,16 +103,16 @@ func List(ctx context.Context, filters map[string][]string) (*[]libpod.PodInspec
}
params["filters"] = stringFilter
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/json", params)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/pods/json", params)
if err != nil {
- return &inspect, err
+ return inspect, err
}
- return &inspect, response.Process(&inspect)
+ return inspect, response.Process(&inspect)
}
// Restart restarts all containers in a pod.
func Restart(ctx context.Context, nameOrID string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// that the Pod can be removed even if in a running state.
func Remove(ctx context.Context, nameOrID string, force *bool) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -143,11 +143,11 @@ func Remove(ctx context.Context, nameOrID string, force *bool) error {
// Start starts all containers in a pod.
func Start(ctx context.Context, nameOrID string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- response, err := conn.DoRequest(nil, http.MethodDelete, "/pods/%s/start", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/start", nil, nameOrID)
if err != nil {
return err
}
@@ -162,7 +162,7 @@ func Stats() error {
// Stop stops all containers in a Pod. The optional timeout parameter can be
// used to override the timeout before the container is killed.
func Stop(ctx context.Context, nameOrID string, timeout *int) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
@@ -184,7 +184,7 @@ func Top() error {
// Unpause unpauses all paused containers in a Pod.
func Unpause(ctx context.Context, nameOrID string) error {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index dba94cb35..98d64bbaa 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -114,7 +114,7 @@ func newBindingTest() *bindingTest {
runRoot: filepath.Join(tmpPath, "run"),
artifactDirPath: "",
imageCacheDir: "",
- sock: fmt.Sprintf("unix:%s", filepath.Join(tmpPath, "api.sock")),
+ sock: fmt.Sprintf("unix://%s", filepath.Join(tmpPath, "api.sock")),
tempDirPath: tmpPath,
}
return &b
@@ -162,16 +162,30 @@ func (b *bindingTest) restoreImageFromCache(i testImage) {
p.Wait(45)
}
-// Run a container and add append the alpine image to it
-func (b *bindingTest) RunTopContainer(name *string) {
+// Run a container within or without a pod
+// and add or append the alpine image to it
+func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, podName *string) {
cmd := []string{"run", "-dt"}
- if name != nil {
- containerName := *name
- cmd = append(cmd, "--name", containerName)
+ if *insidePod && podName != nil {
+ pName := *podName
+ cmd = append(cmd, "--pod", pName)
+ } else if containerName != nil {
+ cName := *containerName
+ cmd = append(cmd, "--name", cName)
}
cmd = append(cmd, alpine.name, "top")
- p := b.runPodman(cmd)
- p.Wait(45)
+ b.runPodman(cmd).Wait(45)
+}
+
+// This method creates a pod with the given pod name.
+// Podname is an optional parameter
+func (b *bindingTest) Podcreate(name *string) {
+ if name != nil {
+ podname := *name
+ b.runPodman([]string{"pod", "create", "--name", podname}).Wait(45)
+ } else {
+ b.runPodman([]string{"pod", "create"}).Wait(45)
+ }
}
// StringInSlice returns a boolean based on whether a given
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 74e0cc67a..0b51c8c9e 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -38,7 +38,7 @@ var _ = Describe("Podman images", func() {
bt.RestoreImagesFromCache()
s = bt.startAPIService()
time.Sleep(1 * time.Second)
- connText, err = bindings.NewConnection(bt.sock)
+ connText, err = bindings.NewConnection(context.Background(), bt.sock)
Expect(err).To(BeNil())
})
@@ -93,7 +93,7 @@ var _ = Describe("Podman images", func() {
// Start a container with alpine image
var top string = "top"
- bt.RunTopContainer(&top)
+ bt.RunTopContainer(&top, &falseFlag, nil)
// we should now have a container called "top" running
containerResponse, err := containers.Inspect(connText, "top", &falseFlag)
Expect(err).To(BeNil())
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
new file mode 100644
index 000000000..76ccd10f2
--- /dev/null
+++ b/pkg/bindings/test/pods_test.go
@@ -0,0 +1,202 @@
+package test_bindings
+
+import (
+ "context"
+ "net/http"
+ "time"
+
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/bindings"
+ "github.com/containers/libpod/pkg/bindings/pods"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gexec"
+)
+
+var _ = Describe("Podman images", func() {
+ var (
+ bt *bindingTest
+ s *gexec.Session
+ connText context.Context
+ newpod string
+ err error
+ trueFlag bool = true
+ )
+
+ BeforeEach(func() {
+ bt = newBindingTest()
+ newpod = "newpod"
+ bt.RestoreImagesFromCache()
+ bt.Podcreate(&newpod)
+ s = bt.startAPIService()
+ time.Sleep(1 * time.Second)
+ connText, err = bindings.NewConnection(bt.sock)
+ Expect(err).To(BeNil())
+ })
+
+ AfterEach(func() {
+ s.Kill()
+ bt.cleanup()
+ })
+
+ It("inspect pod", func() {
+ //Inspect an invalid pod name
+ _, err := pods.Inspect(connText, "dummyname")
+ Expect(err).ToNot(BeNil())
+ code, _ := bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotFound))
+
+ //Inspect an valid pod name
+ response, err := pods.Inspect(connText, newpod)
+ Expect(err).To(BeNil())
+ Expect(response.Config.Name).To(Equal(newpod))
+ })
+
+ // Test validates the list all api returns
+ It("list pod", func() {
+ //List all the pods in the current instance
+ podSummary, err := pods.List(connText, nil)
+ Expect(err).To(BeNil())
+ Expect(len(podSummary)).To(Equal(1))
+ // Adding an alpine container to the existing pod
+ bt.RunTopContainer(nil, &trueFlag, &newpod)
+ podSummary, err = pods.List(connText, nil)
+ // Verify no errors.
+ Expect(err).To(BeNil())
+ // Verify number of containers in the pod.
+ Expect(len(podSummary[0].Containers)).To(Equal(2))
+
+ // Add multiple pods and verify them by name and size.
+ var newpod2 string = "newpod2"
+ bt.Podcreate(&newpod2)
+ podSummary, err = pods.List(connText, nil)
+ Expect(len(podSummary)).To(Equal(2))
+ var names []string
+ for _, i := range podSummary {
+ names = append(names, i.Config.Name)
+ }
+ Expect(StringInSlice(newpod, names)).To(BeTrue())
+ Expect(StringInSlice("newpod2", names)).To(BeTrue())
+
+ // Not working Because: code to list based on filter
+ // "not yet implemented",
+ // Validate list pod with filters
+ filters := make(map[string][]string)
+ filters["name"] = []string{newpod}
+ filteredPods, err := pods.List(connText, filters)
+ Expect(err).To(BeNil())
+ Expect(len(filteredPods)).To(BeNumerically("==", 1))
+ })
+
+ // The test validates if the exists responds
+ It("exists pod", func() {
+ response, err := pods.Exists(connText, "dummyName")
+ Expect(err).To(BeNil())
+ Expect(response).To(BeFalse())
+
+ // Should exit with no error and response should be true
+ response, err = pods.Exists(connText, "newpod")
+ Expect(err).To(BeNil())
+ Expect(response).To(BeTrue())
+ })
+
+ // This test validates if All running containers within
+ // each specified pod are paused and unpaused
+ It("pause upause pod", func() {
+ // Pause invalid container
+ err := pods.Pause(connText, "dummyName")
+ Expect(err).ToNot(BeNil())
+ code, _ := bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotFound))
+
+ // Adding an alpine container to the existing pod
+ bt.RunTopContainer(nil, &trueFlag, &newpod)
+ response, err := pods.Inspect(connText, newpod)
+ Expect(err).To(BeNil())
+
+ // Binding needs to be modified to inspect the pod state.
+ // Since we dont have a pod state we inspect the states of the containers within the pod.
+ // Pause a valid container
+ err = pods.Pause(connText, newpod)
+ Expect(err).To(BeNil())
+ response, err = pods.Inspect(connText, newpod)
+ for _, i := range response.Containers {
+ Expect(define.StringToContainerStatus(i.State)).
+ To(Equal(define.ContainerStatePaused))
+ }
+
+ // Unpause a valid container
+ err = pods.Unpause(connText, newpod)
+ Expect(err).To(BeNil())
+ response, err = pods.Inspect(connText, newpod)
+ for _, i := range response.Containers {
+ Expect(define.StringToContainerStatus(i.State)).
+ To(Equal(define.ContainerStateRunning))
+ }
+ })
+
+ It("start stop restart pod", func() {
+ // Start an invalid pod
+ err = pods.Start(connText, "dummyName")
+ Expect(err).ToNot(BeNil())
+ code, _ := bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotFound))
+
+ // Stop an invalid pod
+ err = pods.Stop(connText, "dummyName", nil)
+ Expect(err).ToNot(BeNil())
+ code, _ = bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotFound))
+
+ // Restart an invalid pod
+ err = pods.Restart(connText, "dummyName")
+ Expect(err).ToNot(BeNil())
+ code, _ = bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotFound))
+
+ // Start a valid pod and inspect status of each container
+ err = pods.Start(connText, newpod)
+ Expect(err).To(BeNil())
+
+ response, err := pods.Inspect(connText, newpod)
+ for _, i := range response.Containers {
+ Expect(define.StringToContainerStatus(i.State)).
+ To(Equal(define.ContainerStateRunning))
+ }
+
+ // Start a already running container
+ // (Test fails for now needs to be fixed)
+ err = pods.Start(connText, newpod)
+ Expect(err).ToNot(BeNil())
+ code, _ = bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotModified))
+
+ // Stop the running pods
+ err = pods.Stop(connText, newpod, nil)
+ Expect(err).To(BeNil())
+ response, _ = pods.Inspect(connText, newpod)
+ for _, i := range response.Containers {
+ Expect(define.StringToContainerStatus(i.State)).
+ To(Equal(define.ContainerStateStopped))
+ }
+
+ // Stop a already running pod
+ // (Test fails for now needs to be fixed)
+ err = pods.Stop(connText, newpod, nil)
+ Expect(err).ToNot(BeNil())
+ code, _ = bindings.CheckResponseCode(err)
+ Expect(code).To(BeNumerically("==", http.StatusNotModified))
+
+ err = pods.Restart(connText, newpod)
+ Expect(err).To(BeNil())
+ response, _ = pods.Inspect(connText, newpod)
+ for _, i := range response.Containers {
+ Expect(define.StringToContainerStatus(i.State)).
+ To(Equal(define.ContainerStateRunning))
+ }
+ })
+
+ // Remove all stopped pods and their container to be implemented.
+ It("prune pod", func() {
+ })
+})
diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go
index 05a4f73fd..8313a7460 100644
--- a/pkg/bindings/volumes/volumes.go
+++ b/pkg/bindings/volumes/volumes.go
@@ -16,7 +16,7 @@ func Create(ctx context.Context, config handlers.VolumeCreateConfig) (string, er
var (
volumeID string
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return "", err
}
@@ -32,7 +32,7 @@ func Inspect(ctx context.Context, nameOrID string) (*libpod.InspectVolumeData, e
var (
inspect libpod.InspectVolumeData
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
}
@@ -55,7 +55,7 @@ func Prune(ctx context.Context) ([]string, error) {
var (
pruned []string
)
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
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
// 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 {
- conn, err := bindings.GetConnectionFromContext(ctx)
+ conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index e37fa2451..c365701de 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -739,6 +739,7 @@ func (config *CreateConfig) getImageVolumes() (map[string]spec.Mount, map[string
for vol := range config.BuiltinImgVolumes {
cleanDest := filepath.Clean(vol)
+ logrus.Debugf("Adding image volume at %s", cleanDest)
if config.ImageVolumeType == "tmpfs" {
// Tmpfs image volumes are handled as mounts
mount := spec.Mount{
@@ -747,13 +748,13 @@ func (config *CreateConfig) getImageVolumes() (map[string]spec.Mount, map[string
Type: TypeTmpfs,
Options: []string{"rprivate", "rw", "nodev", "exec"},
}
- mounts[vol] = mount
+ mounts[cleanDest] = mount
} else {
// Anonymous volumes have no name.
namedVolume := new(libpod.ContainerNamedVolume)
namedVolume.Options = []string{"rprivate", "rw", "nodev", "exec"}
namedVolume.Dest = cleanDest
- volumes[vol] = namedVolume
+ volumes[cleanDest] = namedVolume
}
}
diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go
index 72a0638f9..693795637 100644
--- a/test/e2e/create_staticip_test.go
+++ b/test/e2e/create_staticip_test.go
@@ -4,6 +4,7 @@ package integration
import (
"os"
+ "time"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
@@ -86,8 +87,23 @@ var _ = Describe("Podman create with --ip flag", func() {
result = podmanTest.Podman([]string{"start", "test1"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
+
+ // race prevention: wait until IP address is assigned
+ for i := 0; i < 5; i++ {
+ result = podmanTest.Podman([]string{"inspect", "--format", "{{.NetworkSettings.IPAddress}}", "test1"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ if result.OutputToString() != "" {
+ break
+ }
+ time.Sleep(1 * time.Second)
+ }
+ Expect(result.OutputToString()).To(Equal(ip))
+
+ // test1 container is running with the given IP.
result = podmanTest.Podman([]string{"start", "test2"})
result.WaitWithDefaultTimeout()
Expect(result).To(ExitWithError())
+ Expect(result.ErrorToString()).To(ContainSubstring("requested IP address " + ip + " is not available"))
})
})
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 46c27dc2e..e31338dbc 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -15,6 +15,10 @@ import (
"github.com/onsi/gomega/gexec"
)
+var VolumeTrailingSlashDockerfile = `
+FROM alpine:latest
+VOLUME /test/`
+
var _ = Describe("Podman run with volumes", func() {
var (
tempdir string
@@ -421,4 +425,20 @@ var _ = Describe("Podman run with volumes", func() {
Expect(len(outputArr)).To(Equal(1))
Expect(strings.Contains(outputArr[0], fileName)).To(BeTrue())
})
+
+ It("Podman mount over image volume with trailing /", func() {
+ image := "podman-volume-test:trailing"
+ podmanTest.BuildImage(VolumeTrailingSlashDockerfile, image, "false")
+
+ ctrName := "testCtr"
+ create := podmanTest.Podman([]string{"create", "-v", "/tmp:/test", "--name", ctrName, image, "ls"})
+ create.WaitWithDefaultTimeout()
+ Expect(create.ExitCode()).To(Equal(0))
+
+ data := podmanTest.InspectContainer(ctrName)
+ Expect(len(data)).To(Equal(1))
+ Expect(len(data[0].Mounts)).To(Equal(1))
+ Expect(data[0].Mounts[0].Source).To(Equal("/tmp"))
+ Expect(data[0].Mounts[0].Destination).To(Equal("/test"))
+ })
})
diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go
index d88231510..a697831ab 100644
--- a/test/e2e/search_test.go
+++ b/test/e2e/search_test.go
@@ -9,6 +9,7 @@ import (
"os"
"strconv"
"text/template"
+ "time"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
@@ -165,8 +166,16 @@ registries = ['{{.Host}}:{{.Port}}']`
})
It("podman search v2 registry with empty query", func() {
- search := podmanTest.Podman([]string{"search", "registry.fedoraproject.org/"})
- search.WaitWithDefaultTimeout()
+ var search *PodmanSessionIntegration
+ for i := 0; i < 5; i++ {
+ search = podmanTest.Podman([]string{"search", "registry.fedoraproject.org/"})
+ search.WaitWithDefaultTimeout()
+ if search.ExitCode() == 0 {
+ break
+ }
+ fmt.Println("Search failed; sleeping & retrying...")
+ time.Sleep(2 * time.Second)
+ }
Expect(search.ExitCode()).To(Equal(0))
Expect(len(search.OutputToStringArray())).To(BeNumerically(">=", 1))
})
diff --git a/test/system/010-images.bats b/test/system/010-images.bats
index 66ef53590..3224c9b42 100644
--- a/test/system/010-images.bats
+++ b/test/system/010-images.bats
@@ -74,4 +74,40 @@ size | [0-9]\\\+
run_podman rm my-container
}
+@test "podman images - filter" {
+ skip_if_remote "podman commit -q is broken in podman-remote"
+
+ run_podman inspect --format '{{.ID}}' $IMAGE
+ iid=$output
+
+ run_podman images --noheading --filter=after=$iid
+ is "$output" "" "baseline: empty results from filter (after)"
+
+ run_podman images --noheading --filter=before=$iid
+ is "$output" "" "baseline: empty results from filter (before)"
+
+ # Create a dummy container, then commit that as an image. We will
+ # now be able to use before/after/since queries
+ run_podman run --name mytinycontainer $IMAGE true
+ run_podman commit -q mytinycontainer mynewimage
+ new_iid=$output
+
+ # (refactor common options for legibility)
+ opts='--noheading --no-trunc --format={{.ID}}--{{.Repository}}:{{.Tag}}'
+
+ run_podman images ${opts} --filter=after=$iid
+ is "$output" "sha256:$new_iid--localhost/mynewimage:latest" "filter: after"
+
+ # Same thing, with 'since' instead of 'after'
+ run_podman images ${opts} --filter=since=$iid
+ is "$output" "sha256:$new_iid--localhost/mynewimage:latest" "filter: since"
+
+ run_podman images ${opts} --filter=before=mynewimage
+ is "$output" "sha256:$iid--$IMAGE" "filter: before"
+
+ # Clean up
+ run_podman rmi mynewimage
+ run_podman rm mytinycontainer
+}
+
# vim: filetype=sh
diff --git a/test/system/150-login.bats b/test/system/150-login.bats
index 9c9593311..e33217e14 100644
--- a/test/system/150-login.bats
+++ b/test/system/150-login.bats
@@ -108,8 +108,8 @@ function setup() {
@test "podman login - basic test" {
run_podman login --tls-verify=false \
--username ${PODMAN_LOGIN_USER} \
- --password ${PODMAN_LOGIN_PASS} \
- localhost:${PODMAN_LOGIN_REGISTRY_PORT}
+ --password-stdin \
+ localhost:${PODMAN_LOGIN_REGISTRY_PORT} <<<"${PODMAN_LOGIN_PASS}"
is "$output" "Login Succeeded!" "output from podman login"
# Now log out
@@ -123,8 +123,8 @@ function setup() {
run_podman 125 login --tls-verify=false \
--username ${PODMAN_LOGIN_USER} \
- --password "x${PODMAN_LOGIN_PASS}" \
- $registry
+ --password-stdin \
+ $registry <<< "x${PODMAN_LOGIN_PASS}"
is "$output" \
"Error: error logging into \"$registry\": invalid username/password" \
'output from podman login'