diff options
68 files changed, 460 insertions, 298 deletions
diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go index 8d0c7920f..f8f12234d 100644 --- a/cmd/podman/containers/rm.go +++ b/cmd/podman/containers/rm.go @@ -105,7 +105,7 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit } responses, err := registry.ContainerEngine().ContainerRm(context.Background(), namesOrIDs, rmOptions) if err != nil { - if setExit && len(namesOrIDs) < 2 { + if setExit { setExitCode(err) } return err @@ -132,7 +132,7 @@ func setExitCode(err error) { switch { case cause == define.ErrNoSuchCtr: registry.SetExitCode(1) - case strings.Contains(cause.Error(), define.ErrNoSuchImage.Error()): + case strings.Contains(cause.Error(), define.ErrNoSuchCtr.Error()): registry.SetExitCode(1) case cause == define.ErrCtrStateInvalid: registry.SetExitCode(2) diff --git a/cmd/podman/networks/rm.go b/cmd/podman/networks/rm.go index ac49993b7..86aad43cb 100644 --- a/cmd/podman/networks/rm.go +++ b/cmd/podman/networks/rm.go @@ -2,10 +2,13 @@ package network import ( "fmt" + "strings" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -47,14 +50,30 @@ func networkRm(cmd *cobra.Command, args []string) error { responses, err := registry.ContainerEngine().NetworkRm(registry.Context(), args, networkRmOptions) if err != nil { + setExitCode(err) return err } for _, r := range responses { if r.Err == nil { fmt.Println(r.Name) } else { + setExitCode(r.Err) errs = append(errs, r.Err) } } return errs.PrintErrors() } + +func setExitCode(err error) { + cause := errors.Cause(err) + switch { + case cause == define.ErrNoSuchNetwork: + registry.SetExitCode(1) + case strings.Contains(cause.Error(), define.ErrNoSuchNetwork.Error()): + registry.SetExitCode(1) + case cause == define.ErrNetworkInUse: + registry.SetExitCode(2) + case strings.Contains(cause.Error(), define.ErrNetworkInUse.Error()): + registry.SetExitCode(2) + } +} diff --git a/cmd/podman/pods/rm.go b/cmd/podman/pods/rm.go index 0bb35e1ca..2975db3e8 100644 --- a/cmd/podman/pods/rm.go +++ b/cmd/podman/pods/rm.go @@ -3,12 +3,15 @@ package pods import ( "context" "fmt" + "strings" "github.com/containers/podman/v2/cmd/podman/common" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/validate" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -73,6 +76,7 @@ func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs b responses, err := registry.ContainerEngine().PodRm(context.Background(), namesOrIDs, rmOptions) if err != nil { + setExitCode(err) return err } @@ -83,8 +87,19 @@ func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs b fmt.Println(r.Id) } } else { + setExitCode(r.Err) errs = append(errs, r.Err) } } return errs.PrintErrors() } + +func setExitCode(err error) { + cause := errors.Cause(err) + switch { + case cause == define.ErrNoSuchPod: + registry.SetExitCode(1) + case strings.Contains(cause.Error(), define.ErrNoSuchPod.Error()): + registry.SetExitCode(1) + } +} diff --git a/cmd/podman/volumes/rm.go b/cmd/podman/volumes/rm.go index 5b23eb5e6..4c960d4d5 100644 --- a/cmd/podman/volumes/rm.go +++ b/cmd/podman/volumes/rm.go @@ -3,9 +3,11 @@ package volumes import ( "context" "fmt" + "strings" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -51,14 +53,30 @@ func rm(cmd *cobra.Command, args []string) error { } responses, err := registry.ContainerEngine().VolumeRm(context.Background(), args, rmOptions) if err != nil { + setExitCode(err) return err } for _, r := range responses { if r.Err == nil { fmt.Println(r.Id) } else { + setExitCode(r.Err) errs = append(errs, r.Err) } } return errs.PrintErrors() } + +func setExitCode(err error) { + cause := errors.Cause(err) + switch { + case cause == define.ErrNoSuchVolume: + registry.SetExitCode(1) + case strings.Contains(cause.Error(), define.ErrNoSuchVolume.Error()): + registry.SetExitCode(1) + case cause == define.ErrVolumeBeingUsed: + registry.SetExitCode(2) + case strings.Contains(cause.Error(), define.ErrVolumeBeingUsed.Error()): + registry.SetExitCode(2) + } +} diff --git a/contrib/rootless-cni-infra/Containerfile b/contrib/rootless-cni-infra/Containerfile index 6bf70d644..dd80fda28 100644 --- a/contrib/rootless-cni-infra/Containerfile +++ b/contrib/rootless-cni-infra/Containerfile @@ -2,8 +2,7 @@ ARG GOLANG_VERSION=1.15 ARG ALPINE_VERSION=3.12 ARG CNI_VERSION=v0.8.0 ARG CNI_PLUGINS_VERSION=v0.8.7 -# Aug 20, 2020 -ARG DNSNAME_VESION=78b4da7bbfc51c27366da630e1df1c4f2e8b1b5b +ARG DNSNAME_VESION=v1.0.0 FROM golang:${GOLANG_VERSION}-alpine${ALPINE_VERSION} AS golang-base RUN apk add --no-cache git @@ -34,4 +33,4 @@ COPY rootless-cni-infra /usr/local/bin ENV CNI_PATH=/opt/cni/bin CMD ["sleep", "infinity"] -ENV ROOTLESS_CNI_INFRA_VERSION=2 +ENV ROOTLESS_CNI_INFRA_VERSION=3 diff --git a/contrib/rootless-cni-infra/README.md b/contrib/rootless-cni-infra/README.md index 5aa13374b..c43b4cf49 100644 --- a/contrib/rootless-cni-infra/README.md +++ b/contrib/rootless-cni-infra/README.md @@ -22,3 +22,4 @@ The container images live on `quay.io/libpod/rootless-cni-infra`. The tags have * `/run/rootless-cni-infra/${CONTAINER_ID}/pid`: PID of the `sleep infinity` process that corresponds to the allocated netns * `/run/rootless-cni-infra/${CONTAINER_ID}/attached/${NETWORK_NAME}`: CNI result +* `/run/rootless-cni-infra/${CONTAINER_ID}/attached-args/${NETWORK_NAME}`: CNI args diff --git a/contrib/rootless-cni-infra/rootless-cni-infra b/contrib/rootless-cni-infra/rootless-cni-infra index 5cb43621d..463254c7f 100755 --- a/contrib/rootless-cni-infra/rootless-cni-infra +++ b/contrib/rootless-cni-infra/rootless-cni-infra @@ -33,7 +33,7 @@ cmd_entrypoint_alloc() { K8S_POD_NAME="$3" dir="${BASE}/${ID}" - mkdir -p "${dir}/attached" + mkdir -p "${dir}/attached" "${dir}/attached-args" pid="" if [ -f "${dir}/pid" ]; then @@ -50,6 +50,7 @@ cmd_entrypoint_alloc() { CNI_IFNAME="eth${nwcount}" export CNI_ARGS CNI_IFNAME cnitool add "${NET}" "/proc/${pid}/ns/net" >"${dir}/attached/${NET}" + echo "${CNI_ARGS}" >"${dir}/attached-args/${NET}" # return the result ns="/proc/${pid}/ns/net" @@ -71,8 +72,12 @@ cmd_entrypoint_dealloc() { exit 0 fi pid=$(cat "${dir}/pid") + if [ -f "${dir}/attached-args/${NET}" ]; then + CNI_ARGS=$(cat "${dir}/attached-args/${NET}") + export CNI_ARGS + fi cnitool del "${NET}" "/proc/${pid}/ns/net" - rm -f "${dir}/attached/${NET}" + rm -f "${dir}/attached/${NET}" "${dir}/attached-args/${NET}" nwcount=$(find "${dir}/attached" -type f | wc -l) if [ "${nwcount}" = 0 ]; then diff --git a/docs/source/markdown/podman-network-rm.1.md b/docs/source/markdown/podman-network-rm.1.md index 9ce4d1cd8..616bb2514 100644 --- a/docs/source/markdown/podman-network-rm.1.md +++ b/docs/source/markdown/podman-network-rm.1.md @@ -31,6 +31,15 @@ Delete the `fred` network and all containers associated with the network. Deleted: fred ``` +## Exit Status + **0** All specified networks removed + + **1** One of the specified networks did not exist, and no other failures + + **2** The network is in use by a container or a Pod + + **125** The command fails for any other reason + ## SEE ALSO podman(1), podman-network(1), podman-network-inspect(1) diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md index 95e7ab002..dd89694ec 100644 --- a/docs/source/markdown/podman-pod-rm.1.md +++ b/docs/source/markdown/podman-pod-rm.1.md @@ -49,6 +49,15 @@ podman pod rm -fa podman pod rm --pod-id-file /path/to/id/file +## Exit Status + **0** All specified pods removed + + **1** One of the specified pods did not exist, and no other failures + + **2** One of the specified pods is attached to a container + + **125** The command fails for any other reason + ## SEE ALSO podman-pod(1) diff --git a/docs/source/markdown/podman-rm.1.md b/docs/source/markdown/podman-rm.1.md index 990af0cd1..e3e6740df 100644 --- a/docs/source/markdown/podman-rm.1.md +++ b/docs/source/markdown/podman-rm.1.md @@ -93,7 +93,7 @@ $ podman rm -f --latest **2** One of the specified containers is paused or running - **125** The command fails for a reason other than container did not exist or is paused/running + **125** The command fails for any other reason ## SEE ALSO podman(1), podman-image-rm(1), podman-ps(1), podman-build(1) diff --git a/docs/source/markdown/podman-rmi.1.md b/docs/source/markdown/podman-rmi.1.md index 58280e831..27fe3b235 100644 --- a/docs/source/markdown/podman-rmi.1.md +++ b/docs/source/markdown/podman-rmi.1.md @@ -47,7 +47,7 @@ $ podman rmi -a -f **2** One of the specified images has child images or is being used by a container - **125** The command fails for a reason other than an image did not exist or is in use + **125** The command fails for any other reason ## SEE ALSO podman(1) diff --git a/docs/source/markdown/podman-volume-rm.1.md b/docs/source/markdown/podman-volume-rm.1.md index 9a2fe8c99..ed4a83f9e 100644 --- a/docs/source/markdown/podman-volume-rm.1.md +++ b/docs/source/markdown/podman-volume-rm.1.md @@ -39,6 +39,15 @@ $ podman volume rm --all $ podman volume rm --force myvol ``` +## Exit Status + **0** All specified volumes removed + + **1** One of the specified volumes did not exist, and no other failures + + **2** One of the specified volumes is being used by a container + + **125** The command fails for any other reason + ## SEE ALSO podman-volume(1) diff --git a/libpod/define/errors.go b/libpod/define/errors.go index b3f6483d1..627928ef7 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -162,6 +162,9 @@ var ( // in a pod. This cannot be done as the infra container has all the network information ErrNetworkOnPodContainer = errors.New("network cannot be configured when it is shared with a pod") + // ErrNetworkInUse indicates the requested operation failed because the network was in use + ErrNetworkInUse = errors.New("network is being used") + // ErrStoreNotInitialized indicates that the container storage was never // initialized. ErrStoreNotInitialized = errors.New("the container storage was never initialized") diff --git a/libpod/healthcheck_linux.go b/libpod/healthcheck_linux.go index 08f37d412..b0f1ff35d 100644 --- a/libpod/healthcheck_linux.go +++ b/libpod/healthcheck_linux.go @@ -35,9 +35,8 @@ func (c *Container) createTimer() error { conn.Close() logrus.Debugf("creating systemd-transient files: %s %s", "systemd-run", cmd) systemdRun := exec.Command("systemd-run", cmd...) - _, err = systemdRun.CombinedOutput() - if err != nil { - return err + if output, err := systemdRun.CombinedOutput(); err != nil { + return errors.Errorf("%s", output) } return nil } diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go index 2877191e5..21e43ebd0 100644 --- a/libpod/rootless_cni_linux.go +++ b/libpod/rootless_cni_linux.go @@ -25,7 +25,7 @@ import ( // Built from ../contrib/rootless-cni-infra. var rootlessCNIInfraImage = map[string]string{ - "amd64": "quay.io/libpod/rootless-cni-infra@sha256:e92c3a6367f8e554121b96d39af1f19f0f9ac5a32922b290112e13bc661d3a29", // 2-amd64 + "amd64": "quay.io/libpod/rootless-cni-infra@sha256:304742d5d221211df4ec672807a5842ff11e3729c50bc424ea0cea858f69d7b7", // 3-amd64 } const ( diff --git a/pkg/api/handlers/compat/containers_attach.go b/pkg/api/handlers/compat/containers_attach.go index e20d48d86..4a1196c89 100644 --- a/pkg/api/handlers/compat/containers_attach.go +++ b/pkg/api/handlers/compat/containers_attach.go @@ -6,7 +6,7 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers/utils" - "github.com/containers/podman/v2/pkg/api/server/idletracker" + "github.com/containers/podman/v2/pkg/api/server/idle" "github.com/gorilla/schema" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -92,7 +92,7 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) { return } - idleTracker := r.Context().Value("idletracker").(*idletracker.IdleTracker) + idleTracker := r.Context().Value("idletracker").(*idle.Tracker) hijackChan := make(chan bool, 1) // Perform HTTP attach. @@ -109,7 +109,7 @@ func AttachContainer(w http.ResponseWriter, r *http.Request) { // We do need to tell the idle tracker that the // connection has been closed, though. We can guarantee // that is true after HTTPAttach exits. - idleTracker.TrackHijackedClosed() + idleTracker.Close() } else { // A hijack was not successfully completed. We need to // report the error normally. diff --git a/pkg/api/handlers/compat/exec.go b/pkg/api/handlers/compat/exec.go index 1db950f85..df51293c2 100644 --- a/pkg/api/handlers/compat/exec.go +++ b/pkg/api/handlers/compat/exec.go @@ -10,7 +10,7 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/api/handlers/utils" - "github.com/containers/podman/v2/pkg/api/server/idletracker" + "github.com/containers/podman/v2/pkg/api/server/idle" "github.com/containers/podman/v2/pkg/specgen/generate" "github.com/gorilla/mux" "github.com/pkg/errors" @@ -174,7 +174,7 @@ func ExecStartHandler(w http.ResponseWriter, r *http.Request) { return } - idleTracker := r.Context().Value("idletracker").(*idletracker.IdleTracker) + idleTracker := r.Context().Value("idletracker").(*idle.Tracker) hijackChan := make(chan bool, 1) if err := sessionCtr.ExecHTTPStartAndAttach(sessionID, r, w, nil, nil, nil, hijackChan); err != nil { @@ -186,7 +186,7 @@ func ExecStartHandler(w http.ResponseWriter, r *http.Request) { // We do need to tell the idle tracker that the // connection has been closed, though. We can guarantee // that is true after HTTPAttach exits. - idleTracker.TrackHijackedClosed() + idleTracker.Close() } else { // A hijack was not successfully completed. We need to // report the error normally. diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index bc1bdc287..2f9c10746 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -560,24 +560,41 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) { func UntagImage(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) - name := utils.GetName(r) - newImage, err := runtime.ImageRuntime().NewFromLocal(name) - if err != nil { - utils.ImageNotFound(w, name, errors.Wrapf(err, "Failed to find image %s", name)) - return - } - tag := "latest" - if len(r.Form.Get("tag")) > 0 { - tag = r.Form.Get("tag") - } - if len(r.Form.Get("repo")) < 1 { + tags := []string{} // Note: if empty, all tags will be removed from the image. + repo := r.Form.Get("repo") + tag := r.Form.Get("tag") + + // Do the parameter dance. + switch { + // If tag is set, repo must be as well. + case len(repo) == 0 && len(tag) > 0: utils.Error(w, "repo tag is required", http.StatusBadRequest, errors.New("repo parameter is required to tag an image")) return + + case len(repo) == 0: + break + + // If repo is specified, we need to add that to the tags. + default: + if len(tag) == 0 { + // Normalize tag to "latest" if empty. + tag = "latest" + } + tags = append(tags, fmt.Sprintf("%s:%s", repo, tag)) } - repo := r.Form.Get("repo") - tagName := fmt.Sprintf("%s:%s", repo, tag) - if err := newImage.UntagImage(tagName); err != nil { - utils.Error(w, "failed to untag", http.StatusInternalServerError, err) + + // Now use the ABI implementation to prevent us from having duplicate + // code. + opts := entities.ImageUntagOptions{} + imageEngine := abi.ImageEngine{Libpod: runtime} + + name := utils.GetName(r) + if err := imageEngine.Untag(r.Context(), name, tags, opts); err != nil { + if errors.Cause(err) == define.ErrNoSuchImage { + utils.ImageNotFound(w, name, errors.Wrapf(err, "Failed to find image %s", name)) + } else { + utils.Error(w, "failed to untag", http.StatusInternalServerError, err) + } return } utils.WriteResponse(w, http.StatusCreated, "") diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go index dfece2a4e..b3c4840b8 100644 --- a/pkg/api/handlers/libpod/networks.go +++ b/pkg/api/handlers/libpod/networks.go @@ -92,8 +92,8 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) { } if reports[0].Err != nil { // If the network cannot be found, we return a 404. - if errors.Cause(err) == define.ErrNoSuchNetwork { - utils.Error(w, "Something went wrong", http.StatusNotFound, err) + if errors.Cause(reports[0].Err) == define.ErrNoSuchNetwork { + utils.Error(w, "Something went wrong", http.StatusNotFound, reports[0].Err) return } } diff --git a/pkg/api/server/idle/tracker.go b/pkg/api/server/idle/tracker.go new file mode 100644 index 000000000..1b378c492 --- /dev/null +++ b/pkg/api/server/idle/tracker.go @@ -0,0 +1,96 @@ +package idle + +import ( + "net" + "net/http" + "sync" + "time" + + "github.com/sirupsen/logrus" +) + +// Tracker holds the state for the server's idle tracking +type Tracker struct { + // Duration is the API idle window + Duration time.Duration + hijacked int // count of active connections managed by handlers + managed map[net.Conn]struct{} // set of active connections managed by http package + mux sync.Mutex // protect managed map + timer *time.Timer + total int // total number of connections made to this server instance +} + +// NewTracker creates and initializes a new Tracker object +// For best behavior, duration should be 2x http idle connection timeout +func NewTracker(idle time.Duration) *Tracker { + return &Tracker{ + managed: make(map[net.Conn]struct{}), + Duration: idle, + timer: time.NewTimer(idle), + } +} + +// ConnState is called on HTTP connection state changes. +// - Once StateHijacked, StateClose is _NOT_ called on that connection +// - There are two "idle" timeouts, the http idle connection (not to be confused with the TCP/IP idle socket timeout) +// and the API idle window. The caller should set the http idle timeout to 2x the time provided to NewTacker() which +// is the API idle window. +func (t *Tracker) ConnState(conn net.Conn, state http.ConnState) { + t.mux.Lock() + defer t.mux.Unlock() + + logrus.Debugf("IdleTracker %p:%v %dm+%dh/%dt connection(s)", conn, state, len(t.managed), t.hijacked, t.TotalConnections()) + switch state { + case http.StateNew, http.StateActive: + // stop the API timer when the server transitions any connection to an "active" state + t.managed[conn] = struct{}{} + t.timer.Stop() + t.total++ + case http.StateHijacked: + // hijacked connections should call Close() when finished. + // Note: If a handler hijack's a connection and then doesn't Close() it, + // the API timer will not fire and the server will _NOT_ timeout. + delete(t.managed, conn) + t.hijacked++ + case http.StateIdle: + // When any connection goes into the http idle state, we know: + // - we have an active connection + // - the API timer should not be counting down (See case StateNew/StateActive) + break + case http.StateClosed: + oldActive := t.ActiveConnections() + + // Either the server or a hijacking handler has closed the http connection to a client + if _, found := t.managed[conn]; found { + delete(t.managed, conn) + } else { + t.hijacked-- // guarded by t.mux above + } + + // Transitioned from any "active" connection to no connections + if oldActive > 0 && t.ActiveConnections() == 0 { + t.timer.Stop() // See library source for Reset() issues and why they are not fixed + t.timer.Reset(t.Duration) // Restart the API window timer + } + } +} + +// Close is used to update Tracker that a StateHijacked connection has been closed by handler (StateClosed) +func (t *Tracker) Close() { + t.ConnState(nil, http.StateClosed) +} + +// ActiveConnections returns the number of current managed or StateHijacked connections +func (t *Tracker) ActiveConnections() int { + return len(t.managed) + t.hijacked +} + +// TotalConnections returns total number of connections made to this instance of the service +func (t *Tracker) TotalConnections() int { + return t.total +} + +// Done is called when idle timer has expired +func (t *Tracker) Done() <-chan time.Time { + return t.timer.C +} diff --git a/pkg/api/server/idletracker/idletracker.go b/pkg/api/server/idletracker/idletracker.go deleted file mode 100644 index 1ee905a99..000000000 --- a/pkg/api/server/idletracker/idletracker.go +++ /dev/null @@ -1,74 +0,0 @@ -package idletracker - -import ( - "net" - "net/http" - "sync" - "time" - - "github.com/sirupsen/logrus" -) - -type IdleTracker struct { - http map[net.Conn]struct{} - hijacked int - total int - mux sync.Mutex - timer *time.Timer - Duration time.Duration -} - -func NewIdleTracker(idle time.Duration) *IdleTracker { - return &IdleTracker{ - http: make(map[net.Conn]struct{}), - Duration: idle, - timer: time.NewTimer(idle), - } -} - -func (t *IdleTracker) ConnState(conn net.Conn, state http.ConnState) { - t.mux.Lock() - defer t.mux.Unlock() - - oldActive := t.ActiveConnections() - logrus.Debugf("IdleTracker %p:%v %d/%d connection(s)", conn, state, oldActive, t.TotalConnections()) - switch state { - case http.StateNew, http.StateActive: - t.http[conn] = struct{}{} - // stop the timer if we transitioned from idle - if oldActive == 0 { - t.timer.Stop() - } - t.total++ - case http.StateHijacked: - // hijacked connections are handled elsewhere - delete(t.http, conn) - t.hijacked++ - case http.StateIdle, http.StateClosed: - delete(t.http, conn) - // Restart the timer if we've become idle - if oldActive > 0 && len(t.http) == 0 { - t.timer.Stop() - t.timer.Reset(t.Duration) - } - } -} - -func (t *IdleTracker) TrackHijackedClosed() { - t.mux.Lock() - defer t.mux.Unlock() - - t.hijacked-- -} - -func (t *IdleTracker) ActiveConnections() int { - return len(t.http) + t.hijacked -} - -func (t *IdleTracker) TotalConnections() int { - return t.total -} - -func (t *IdleTracker) Done() <-chan time.Time { - return t.timer.C -} diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index b1007fe09..32e401a54 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -1175,7 +1175,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // tags: // - images // summary: Untag an image - // description: Untag an image + // description: Untag an image. If not repo and tag are specified, all tags are removed from the image. // parameters: // - in: path // name: name:.* diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go index e7c031234..09a9f6370 100644 --- a/pkg/api/server/server.go +++ b/pkg/api/server/server.go @@ -16,7 +16,7 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/pkg/api/handlers" - "github.com/containers/podman/v2/pkg/api/server/idletracker" + "github.com/containers/podman/v2/pkg/api/server/idle" "github.com/coreos/go-systemd/v22/activation" "github.com/coreos/go-systemd/v22/daemon" "github.com/gorilla/mux" @@ -26,14 +26,14 @@ import ( ) type APIServer struct { - http.Server // The HTTP work happens here - *schema.Decoder // Decoder for Query parameters to structs - context.Context // Context to carry objects to handlers - *libpod.Runtime // Where the real work happens - net.Listener // mux for routing HTTP API calls to libpod routines - context.CancelFunc // Stop APIServer - idleTracker *idletracker.IdleTracker // Track connections to support idle shutdown - pprof *http.Server // Sidecar http server for providing performance data + http.Server // The HTTP work happens here + *schema.Decoder // Decoder for Query parameters to structs + context.Context // Context to carry objects to handlers + *libpod.Runtime // Where the real work happens + net.Listener // mux for routing HTTP API calls to libpod routines + context.CancelFunc // Stop APIServer + idleTracker *idle.Tracker // Track connections to support idle shutdown + pprof *http.Server // Sidecar http server for providing performance data } // Number of seconds to wait for next request, if exceeded shutdown server @@ -70,13 +70,13 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li } router := mux.NewRouter().UseEncodedPath() - idle := idletracker.NewIdleTracker(duration) + idle := idle.NewTracker(duration) server := APIServer{ Server: http.Server{ Handler: router, ReadHeaderTimeout: 20 * time.Second, - IdleTimeout: duration, + IdleTimeout: duration * 2, ConnState: idle.ConnState, ErrorLog: log.New(logrus.StandardLogger().Out, "", 0), }, diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go index 053be6528..5acfea853 100644 --- a/pkg/domain/infra/abi/network.go +++ b/pkg/domain/infra/abi/network.go @@ -12,6 +12,7 @@ import ( "github.com/containernetworking/cni/libcni" cniversion "github.com/containernetworking/cni/pkg/version" "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/network" "github.com/containers/podman/v2/pkg/util" @@ -85,7 +86,7 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o // if user passes force, we nuke containers and pods if !options.Force { // Without the force option, we return an error - return reports, errors.Errorf("%q has associated containers with it. Use -f to forcibly delete containers and pods", name) + return reports, errors.Wrapf(define.ErrNetworkInUse, "%q has associated containers with it. Use -f to forcibly delete containers and pods", name) } if c.IsInfra() { // if we have a infra container we need to remove the pod diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 981884109..61ac2141c 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -9,7 +9,6 @@ import ( "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker/reference" - "github.com/containers/podman/v2/pkg/bindings" images "github.com/containers/podman/v2/pkg/bindings/images" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/utils" @@ -139,13 +138,8 @@ func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, } func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string, options entities.ImageUntagOptions) error { - // Remove all tags if none are provided if len(tags) == 0 { - newImage, err := images.GetImage(ir.ClientCxt, nameOrID, bindings.PFalse) - if err != nil { - return err - } - tags = newImage.NamesHistory + return images.Untag(ir.ClientCxt, nameOrID, "", "") } for _, newTag := range tags { diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 147ebd61b..927e6b7fa 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -75,8 +75,8 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat if err != nil { return nil, errors.Wrap(err, "error parsing fields in containers.conf") } - if defaultEnvs["containers"] == "" { - defaultEnvs["containers"] = "podman" + if defaultEnvs["container"] == "" { + defaultEnvs["container"] = "podman" } var envs map[string]string diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 93186bc8b..f22a4c3af 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -27,7 +27,7 @@ var _ = Describe("Podman checkpoint", func() { ) BeforeEach(func() { - SkipIfRootless() //checkpoint not supported in rootless mode + SkipIfRootless("checkpoint not supported in rootless mode") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 1943020c3..f4c80d865 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -599,6 +599,24 @@ func (p *PodmanTestIntegration) CreateSeccompJson(in []byte) (string, error) { return jsonFile, nil } +func SkipIfRootlessCgroupsV1(reason string) { + if len(reason) < 5 { + panic("SkipIfRootlessCgroupsV1 must specify a reason to skip") + } + if os.Geteuid() != 0 && !CGROUPSV2 { + Skip("[rootless]: " + reason) + } +} + +func SkipIfRootless(reason string) { + if len(reason) < 5 { + panic("SkipIfRootless must specify a reason to skip") + } + if os.Geteuid() != 0 { + ginkgo.Skip("[rootless]: " + reason) + } +} + func SkipIfNotFedora() { info := GetHostDistributionInfo() if info.Distribution != "fedora" { @@ -610,21 +628,21 @@ func isRootless() bool { return os.Geteuid() != 0 } -func SkipIfCgroupV1() { - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - - if !cgroupsv2 { - Skip("Skip on systems with cgroup V1 systems") +func SkipIfCgroupV1(reason string) { + if len(reason) < 5 { + panic("SkipIfCgroupV1 must specify a reason to skip") + } + if !CGROUPSV2 { + Skip(reason) } } -func SkipIfCgroupV2() { - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - - if cgroupsv2 { - Skip("Skip on systems with cgroup V2 systems") +func SkipIfCgroupV2(reason string) { + if len(reason) < 5 { + panic("SkipIfCgroupV2 must specify a reason to skip") + } + if CGROUPSV2 { + Skip(reason) } } diff --git a/test/e2e/config.go b/test/e2e/config.go index 0e1850614..49a47c7da 100644 --- a/test/e2e/config.go +++ b/test/e2e/config.go @@ -23,8 +23,4 @@ var ( // This image has a bogus/invalid seccomp profile which should // yield a json error when being read. alpineBogusSeccomp = "docker.io/libpod/alpine-with-bogus-seccomp:label" - - // v2fail is a temporary variable to help us track - // tests that fail in v2 - v2fail = "does not pass integration tests with v2 podman" ) diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go index ddb62c327..965e51973 100644 --- a/test/e2e/containers_conf_test.go +++ b/test/e2e/containers_conf_test.go @@ -41,7 +41,7 @@ var _ = Describe("Podman run", func() { }) It("podman run limits test", func() { - SkipIfRootlessCgroupsV1() + SkipIfRootlessCgroupsV1("Setting limits not supported on cgroupv1 for rootless users") //containers.conf is set to "nofile=500:500" session := podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ulimit", "-n"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go index 57d1c3f2c..7a2267617 100644 --- a/test/e2e/create_staticip_test.go +++ b/test/e2e/create_staticip_test.go @@ -49,7 +49,7 @@ var _ = Describe("Podman create with --ip flag", func() { }) It("Podman create --ip with non-allocatable IP", func() { - SkipIfRootless() // --ip is not supported in rootless mode + SkipIfRootless("--ip is not supported in rootless mode") result := podmanTest.Podman([]string{"create", "--name", "test", "--ip", "203.0.113.124", ALPINE, "ls"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) @@ -81,7 +81,7 @@ var _ = Describe("Podman create with --ip flag", func() { }) It("Podman create two containers with the same IP", func() { - SkipIfRootless() // --ip not supported in rootless mode + SkipIfRootless("--ip not supported in rootless mode") ip := GetRandomIPAddress() result := podmanTest.Podman([]string{"create", "--name", "test1", "--ip", ip, ALPINE, "sleep", "999"}) result.WaitWithDefaultTimeout() diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 45dbe9b56..e6491ce9b 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -552,7 +552,7 @@ var _ = Describe("Podman create", func() { }) It("create container in pod with IP should fail", func() { - SkipIfRootless() //Setting IP not supported in rootless mode + SkipIfRootless("Setting IP not supported in rootless mode") name := "createwithstaticip" pod := podmanTest.RunTopContainerInPod("", "new:"+name) pod.WaitWithDefaultTimeout() @@ -564,7 +564,7 @@ var _ = Describe("Podman create", func() { }) It("create container in pod with mac should fail", func() { - SkipIfRootless() //Setting MAC Address not supported in rootless mode + SkipIfRootless("Setting MAC Address not supported in rootless mode") name := "createwithstaticmac" pod := podmanTest.RunTopContainerInPod("", "new:"+name) pod.WaitWithDefaultTimeout() diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index 0a0b2799b..fa87302ee 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -24,16 +24,10 @@ func IsRemote() bool { } func SkipIfRemote(reason string) { - ginkgo.Skip("[remote]: " + reason) -} - -func SkipIfRootlessCgroupsV1() { -} - -func SkipIfRootless() { - if os.Geteuid() != 0 { - ginkgo.Skip("This function is not enabled for rootless podman") + if len(reason) < 5 { + panic("SkipIfRemote must specify a reason to skip") } + ginkgo.Skip("[remote]: " + reason) } // Podman is the exec call to podman on the filesystem diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 00d066fea..a9da922de 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -8,8 +8,6 @@ import ( "os" "path/filepath" "strings" - - . "github.com/onsi/ginkgo" ) func IsRemote() bool { @@ -19,18 +17,6 @@ func IsRemote() bool { func SkipIfRemote(string) { } -func SkipIfRootlessCgroupsV1() { - if os.Geteuid() != 0 && !CGROUPSV2 { - Skip("Rooless requires cgroupsV2 to set limits") - } -} - -func SkipIfRootless() { - if os.Geteuid() != 0 { - Skip("This function is not enabled for rootless podman") - } -} - // Podman is the exec call to podman on the filesystem func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { podmanSession := p.PodmanBase(args, false, false) diff --git a/test/e2e/libpod_suite_varlink_test.go b/test/e2e/libpod_suite_varlink_test.go index f901cbec9..275a1115e 100644 --- a/test/e2e/libpod_suite_varlink_test.go +++ b/test/e2e/libpod_suite_varlink_test.go @@ -23,19 +23,10 @@ func IsRemote() bool { return true } -func SkipIfRootlessCgroupsV1() { -} - func SkipIfRemote(reason string) { ginkgo.Skip("[remote]: " + reason) } -func SkipIfRootless() { - if os.Geteuid() != 0 { - ginkgo.Skip("This function is not enabled for rootless podman") - } -} - // Podman is the exec call to podman on the filesystem func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { podmanSession := p.PodmanBase(args, false, false) diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index 52357b00a..b1255c00a 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -47,7 +47,7 @@ var _ = Describe("Podman login and logout", func() { se := SystemExec("setenforce", []string{"0"}) se.WaitWithDefaultTimeout() if se.ExitCode() != 0 { - Skip("Can not disable selinux, this may cause problem for reading cert files inside container.") + Skip("Cannot disable selinux, this may cause problem for reading cert files inside container.") } defer SystemExec("setenforce", []string{"1"}) } @@ -87,7 +87,7 @@ var _ = Describe("Podman login and logout", func() { Expect(session.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } }) @@ -116,8 +116,6 @@ var _ = Describe("Podman login and logout", func() { }) It("podman login and logout without registry parameter", func() { - SkipIfRootless() - registriesConf, err := ioutil.TempFile("", "TestLoginWithoutParameter") Expect(err).To(BeNil()) defer registriesConf.Close() @@ -231,7 +229,7 @@ var _ = Describe("Podman login and logout", func() { Expect(session.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry1", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", server}) diff --git a/test/e2e/mount_test.go b/test/e2e/mount_test.go index 4f60cc6df..ee2753d72 100644 --- a/test/e2e/mount_test.go +++ b/test/e2e/mount_test.go @@ -18,7 +18,7 @@ var _ = Describe("Podman mount", func() { ) BeforeEach(func() { - SkipIfRootless() + SkipIfRootless("Podman mount requires podman unshare first to work") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) @@ -189,7 +189,7 @@ var _ = Describe("Podman mount", func() { }) It("podman list running container", func() { - SkipIfRootless() // FIXME: We need to do a podman unshare before executing this code. + SkipIfRootless("FIXME: We need to do a podman unshare before executing this code.") setup := podmanTest.Podman([]string{"run", "-dt", ALPINE, "top"}) setup.WaitWithDefaultTimeout() @@ -212,7 +212,7 @@ var _ = Describe("Podman mount", func() { }) It("podman list multiple mounted containers", func() { - SkipIfRootless() // FIXME: We need to do a podman unshare before executing this code. + SkipIfRootless("FIXME: We need to do a podman unshare before executing this code.") setup := podmanTest.Podman([]string{"create", ALPINE, "ls"}) setup.WaitWithDefaultTimeout() @@ -257,7 +257,7 @@ var _ = Describe("Podman mount", func() { }) It("podman list mounted container", func() { - SkipIfRootless() // FIXME: We need to do a podman unshare before executing this code. + SkipIfRootless("FIXME: We need to do a podman unshare before executing this code.") setup := podmanTest.Podman([]string{"create", ALPINE, "ls"}) setup.WaitWithDefaultTimeout() diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index f6d9f2cc3..edd76739f 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -58,7 +58,7 @@ func genericPluginsToPortMap(plugins interface{}, pluginType string) (network.Po func (p *PodmanTestIntegration) removeCNINetwork(name string) { session := p.Podman([]string{"network", "rm", "-f", name}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(BeZero()) + Expect(session.ExitCode()).To(BeNumerically("<=", 1)) } func removeNetworkDevice(name string) { @@ -178,7 +178,7 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with name and IPv6 subnet", func() { - SkipIfRootless() // FIXME I believe this should work in rootlessmode + SkipIfRootless("FIXME I believe this should work in rootlessmode") var ( results []network.NcList diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 2ea8291fc..aae82e292 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -135,7 +135,6 @@ var _ = Describe("Podman network", func() { }) It("podman network rm", func() { - SkipIfRootless() // FIXME: This one is definitely broken in rootless mode // Setup, use uuid to prevent conflict with other tests uuid := stringid.GenerateNonCryptoID() secondPath := filepath.Join(podmanTest.CNIConfigDir, fmt.Sprintf("%s.conflist", uuid)) @@ -265,11 +264,18 @@ var _ = Describe("Podman network", func() { Expect(rmAll.ExitCode()).To(BeZero()) }) + It("podman network remove bogus", func() { + session := podmanTest.Podman([]string{"network", "rm", "bogus"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) + It("podman network remove --force with pod", func() { netName := "testnet" session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) session = podmanTest.Podman([]string{"pod", "create", "--network", netName}) session.WaitWithDefaultTimeout() @@ -280,6 +286,10 @@ var _ = Describe("Podman network", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(BeZero()) + session = podmanTest.Podman([]string{"network", "rm", netName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(2)) + session = podmanTest.Podman([]string{"network", "rm", "--force", netName}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(BeZero()) @@ -301,11 +311,13 @@ var _ = Describe("Podman network", func() { session := podmanTest.Podman([]string{"network", "create", netName1}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName1) netName2 := "net2" session = podmanTest.Podman([]string{"network", "create", netName2}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName2) session = podmanTest.Podman([]string{"network", "rm", netName1, netName2}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index a49304bbe..a90ffcc87 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -7,7 +7,6 @@ import ( "path/filepath" "strings" - "github.com/containers/podman/v2/pkg/cgroups" . "github.com/containers/podman/v2/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -24,16 +23,13 @@ var _ = Describe("Podman pause", func() { createdState := "created" BeforeEach(func() { - SkipIfRootlessCgroupsV1() // Pause is not supported in cgroups v1 + SkipIfRootlessCgroupsV1("Pause is not supported in cgroups v1") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) } - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - - if cgroupsv2 { + if CGROUPSV2 { b, err := ioutil.ReadFile("/proc/self/cgroup") if err != nil { Skip("cannot read self cgroup") diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go index 182d99d51..3dabf7b4a 100644 --- a/test/e2e/pod_pause_test.go +++ b/test/e2e/pod_pause_test.go @@ -18,7 +18,7 @@ var _ = Describe("Podman pod pause", func() { pausedState := "paused" BeforeEach(func() { - SkipIfRootlessCgroupsV1() // Pause is not supported in cgroups v1 + SkipIfRootlessCgroupsV1("Pause is not supported in cgroups v1") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go index cb9b93a15..24643e6b2 100644 --- a/test/e2e/pod_rm_test.go +++ b/test/e2e/pod_rm_test.go @@ -195,8 +195,7 @@ var _ = Describe("Podman pod rm", func() { It("podman rm bogus pod", func() { session := podmanTest.Podman([]string{"pod", "rm", "bogus"}) session.WaitWithDefaultTimeout() - // TODO: `podman rm` returns 1 for a bogus container. Should the RC be consistent? - Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ExitCode()).To(Equal(1)) }) It("podman rm bogus pod and a running pod", func() { @@ -209,11 +208,11 @@ var _ = Describe("Podman pod rm", func() { session = podmanTest.Podman([]string{"pod", "rm", "bogus", "test1"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ExitCode()).To(Equal(1)) session = podmanTest.Podman([]string{"pod", "rm", "test1", "bogus"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ExitCode()).To(Equal(1)) }) It("podman rm --ignore bogus pod and a running pod", func() { diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go index 02fb3bc57..1ffbe282b 100644 --- a/test/e2e/pod_stats_test.go +++ b/test/e2e/pod_stats_test.go @@ -17,7 +17,7 @@ var _ = Describe("Podman pod stats", func() { BeforeEach(func() { if os.Geteuid() != 0 { - SkipIfCgroupV2() + SkipIfCgroupV2("--cgroup-manager=cgroupfs which doesn't work in rootless mode") } tempdir, err = CreateTempDirInTempDir() @@ -175,7 +175,7 @@ var _ = Describe("Podman pod stats", func() { It("podman stats on net=host post", func() { // --net=host not supported for rootless pods at present - SkipIfRootlessCgroupsV1() // Pause stats not supported in cgroups v1 + SkipIfRootlessCgroupsV1("Pause stats not supported in cgroups v1") podName := "testPod" podCreate := podmanTest.Podman([]string{"pod", "create", "--net=host", "--name", podName}) podCreate.WaitWithDefaultTimeout() diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index aabec4f55..82a842146 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -206,7 +206,7 @@ var _ = Describe("Podman ps", func() { }) It("podman ps namespace flag with go template format", func() { - Skip(v2fail) + Skip("FIXME: table still not supported in podman ps command") _, ec, _ := podmanTest.RunLsContainer("test1") Expect(ec).To(Equal(0)) diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go index 9d2daaf9d..45b8769a2 100644 --- a/test/e2e/push_test.go +++ b/test/e2e/push_test.go @@ -70,7 +70,7 @@ var _ = Describe("Podman push", func() { Expect(session.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"}) @@ -87,7 +87,7 @@ var _ = Describe("Podman push", func() { }) It("podman push to local registry with authorization", func() { - SkipIfRootless() // FIXME: Creating content in certs.d we use directories in homedir + SkipIfRootless("FIXME: Creating content in certs.d we use directories in homedir") if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") } @@ -132,7 +132,7 @@ var _ = Describe("Podman push", func() { Expect(session.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } session = podmanTest.PodmanNoCache([]string{"logs", "registry"}) diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go index cc2f7daf1..7eff8c6ed 100644 --- a/test/e2e/rm_test.go +++ b/test/e2e/rm_test.go @@ -228,11 +228,11 @@ var _ = Describe("Podman rm", func() { session = podmanTest.Podman([]string{"rm", "bogus", "test1"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ExitCode()).To(Equal(1)) session = podmanTest.Podman([]string{"rm", "test1", "bogus"}) session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(125)) + Expect(session.ExitCode()).To(Equal(1)) }) It("podman rm --ignore bogus container and a running container", func() { diff --git a/test/e2e/run_cgroup_parent_test.go b/test/e2e/run_cgroup_parent_test.go index b10937953..5765d5ef6 100644 --- a/test/e2e/run_cgroup_parent_test.go +++ b/test/e2e/run_cgroup_parent_test.go @@ -18,7 +18,7 @@ var _ = Describe("Podman run with --cgroup-parent", func() { ) BeforeEach(func() { - SkipIfRootlessCgroupsV1() // cgroup parent is not supported in cgroups v1 + SkipIfRootlessCgroupsV1("cgroup parent is not supported in cgroups v1") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) @@ -48,7 +48,7 @@ var _ = Describe("Podman run with --cgroup-parent", func() { }) Specify("no --cgroup-parent", func() { - SkipIfRootless() // FIXME This seems to be broken in rootless mode + SkipIfRootless("FIXME This seems to be broken in rootless mode") cgroup := "/libpod_parent" if !Containerized() && podmanTest.CgroupManager != "cgroupfs" { cgroup = "/machine.slice" diff --git a/test/e2e/run_cleanup_test.go b/test/e2e/run_cleanup_test.go index 34b6ba4ff..5f6c9007a 100644 --- a/test/e2e/run_cleanup_test.go +++ b/test/e2e/run_cleanup_test.go @@ -34,7 +34,7 @@ var _ = Describe("Podman run exit", func() { It("podman run -d mount cleanup test", func() { SkipIfRemote("podman-remote does not support mount") - SkipIfRootless() // FIXME podman mount requires podman unshare first + SkipIfRootless("FIXME podman mount requires podman unshare first") result := podmanTest.Podman([]string{"run", "-dt", ALPINE, "top"}) result.WaitWithDefaultTimeout() diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go index 86cc9d1c5..d8b57c230 100644 --- a/test/e2e/run_cpu_test.go +++ b/test/e2e/run_cpu_test.go @@ -4,7 +4,6 @@ import ( "io/ioutil" "os" - "github.com/containers/podman/v2/pkg/cgroups" . "github.com/containers/podman/v2/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -18,17 +17,14 @@ var _ = Describe("Podman run cpu", func() { ) BeforeEach(func() { - SkipIfRootlessCgroupsV1() + SkipIfRootlessCgroupsV1("Setting CPU not supported on cgroupv1 for rootless users") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) } - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - - if cgroupsv2 { + if CGROUPSV2 { if err := ioutil.WriteFile("/sys/fs/cgroup/cgroup.subtree_control", []byte("+cpuset"), 0644); err != nil { Skip("cpuset controller not available on the current kernel") } diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go index 828da3494..1c2602631 100644 --- a/test/e2e/run_device_test.go +++ b/test/e2e/run_device_test.go @@ -72,7 +72,7 @@ var _ = Describe("Podman run device", func() { }) It("podman run device host device and container device parameter are directories", func() { - SkipIfRootless() // Can not create devices in /dev in rootless mode + SkipIfRootless("Cannot create devices in /dev in rootless mode") Expect(os.MkdirAll("/dev/foodevdir", os.ModePerm)).To(BeNil()) defer os.RemoveAll("/dev/foodevdir") diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go index a3dc9bae5..fa19b1824 100644 --- a/test/e2e/run_memory_test.go +++ b/test/e2e/run_memory_test.go @@ -3,7 +3,6 @@ package integration import ( "os" - "github.com/containers/podman/v2/pkg/cgroups" . "github.com/containers/podman/v2/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -17,9 +16,9 @@ var _ = Describe("Podman run memory", func() { ) BeforeEach(func() { - SkipIfRootlessCgroupsV1() + SkipIfRootlessCgroupsV1("Setting Memory not supported on cgroupv1 for rootless users") - SkipIfRootless() + SkipIfRootless("FIXME: This should work on cgroups V2 systems") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) @@ -37,12 +36,9 @@ var _ = Describe("Podman run memory", func() { }) It("podman run memory test", func() { - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - var session *PodmanSessionIntegration - if cgroupsv2 { + if CGROUPSV2 { session = podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.max"}) } else { session = podmanTest.Podman([]string{"run", "--memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"}) @@ -57,28 +53,21 @@ var _ = Describe("Podman run memory", func() { Skip("Unable to perform test on Ubuntu distributions due to memory management") } - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - var session *PodmanSessionIntegration - if cgroupsv2 { - session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.high"}) + if CGROUPSV2 { + session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.low"}) } else { session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"}) } session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - if cgroupsv2 { - Expect(session.OutputToString()).To(Equal("max")) - } else { - Expect(session.OutputToString()).To(Equal("41943040")) - } + Expect(session.OutputToString()).To(Equal("41943040")) }) It("podman run memory-swappiness test", func() { - SkipIfCgroupV2() + SkipIfCgroupV2("memory-swappiness not supported on cgroupV2") session := podmanTest.Podman([]string{"run", "--memory-swappiness=15", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.swappiness"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -86,8 +75,18 @@ var _ = Describe("Podman run memory", func() { }) It("podman run kernel-memory test", func() { - SkipIfCgroupV2() - session := podmanTest.Podman([]string{"run", "--kernel-memory=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes"}) + if podmanTest.Host.Distribution == "ubuntu" { + Skip("Unable to perform test on Ubuntu distributions due to memory management") + } + + var session *PodmanSessionIntegration + + if CGROUPSV2 { + session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/memory.low"}) + } else { + session = podmanTest.Podman([]string{"run", "--memory-reservation=40m", ALPINE, "cat", "/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"}) + } + session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(Equal("41943040")) diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index a67324b2b..044e56e6c 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -55,7 +55,7 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network expose port 222", func() { - SkipIfRootless() // iptables is not supported for rootless users + SkipIfRootless("iptables is not supported for rootless users") session := podmanTest.Podman([]string{"run", "-dt", "--expose", "222-223", "-P", ALPINE, "/bin/sh"}) session.Wait(30) Expect(session.ExitCode()).To(Equal(0)) @@ -252,7 +252,7 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network expose host port 80 to container port 8000", func() { - SkipIfRootless() // iptables is not supported for rootless users + SkipIfRootless("iptables is not supported for rootless users") session := podmanTest.Podman([]string{"run", "-dt", "-p", "80:8000", ALPINE, "/bin/sh"}) session.Wait(30) Expect(session.ExitCode()).To(Equal(0)) @@ -367,7 +367,7 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network expose duplicate host port results in error", func() { - SkipIfRootless() // FIXME we should be able to run this test in rootless mode with different ports + SkipIfRootless("FIXME we should be able to run this test in rootless mode with different ports") session := podmanTest.Podman([]string{"run", "--name", "test", "-dt", "-p", "80", ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() @@ -478,9 +478,9 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network in user created network namespace", func() { - SkipIfRootless() // ip netns is not supported for rootless users + SkipIfRootless("ip netns is not supported for rootless users") if Containerized() { - Skip("Can not be run within a container.") + Skip("Cannot be run within a container.") } addXXX := SystemExec("ip", []string{"netns", "add", "xxx"}) Expect(addXXX.ExitCode()).To(Equal(0)) @@ -495,9 +495,9 @@ var _ = Describe("Podman run networking", func() { }) It("podman run n user created network namespace with resolv.conf", func() { - SkipIfRootless() // ip netns is not supported for rootless users + SkipIfRootless("ip netns is not supported for rootless users") if Containerized() { - Skip("Can not be run within a container.") + Skip("Cannot be run within a container.") } addXXX2 := SystemExec("ip", []string{"netns", "add", "xxx2"}) Expect(addXXX2.ExitCode()).To(Equal(0)) @@ -527,7 +527,7 @@ var _ = Describe("Podman run networking", func() { }) It("podman run in custom CNI network with --static-ip", func() { - SkipIfRootless() //Rootless mode does not support --ip + SkipIfRootless("Rootless mode does not support --ip") netName := "podmantestnetwork" ipAddr := "10.25.30.128" create := podmanTest.Podman([]string{"network", "create", "--subnet", "10.25.30.0/24", netName}) @@ -542,7 +542,7 @@ var _ = Describe("Podman run networking", func() { }) It("podman run with new:pod and static-ip", func() { - SkipIfRootless() // Rootless does not support --ip + SkipIfRootless("Rootless does not support --ip") netName := "podmantestnetwork2" ipAddr := "10.25.40.128" podname := "testpod" diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go index a20088776..ab11128ba 100644 --- a/test/e2e/run_privileged_test.go +++ b/test/e2e/run_privileged_test.go @@ -106,7 +106,7 @@ var _ = Describe("Podman privileged container tests", func() { }) It("podman privileged should inherit host devices", func() { - SkipIfRootless() // FIXME: This seems to be broken for rootless mode, /dev/ is close to the same + SkipIfRootless("FIXME: This seems to be broken for rootless mode, /dev/ is close to the same") session := podmanTest.Podman([]string{"run", "--privileged", ALPINE, "ls", "-l", "/dev"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go index 959c823b5..8383b1812 100644 --- a/test/e2e/run_staticip_test.go +++ b/test/e2e/run_staticip_test.go @@ -19,7 +19,7 @@ var _ = Describe("Podman run with --ip flag", func() { ) BeforeEach(func() { - SkipIfRootless() //rootless does not support --ip + SkipIfRootless("rootless does not support --ip") tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 5617f50b7..2d4f3a42d 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -309,7 +309,7 @@ USER bin` }) It("podman run limits test", func() { - SkipIfRootlessCgroupsV1() + SkipIfRootlessCgroupsV1("Setting limits not supported on cgroupv1 for rootless users") if !isRootless() { session := podmanTest.Podman([]string{"run", "--rm", "--ulimit", "rtprio=99", "--cap-add=sys_nice", fedoraMinimal, "cat", "/proc/self/sched"}) @@ -368,7 +368,7 @@ USER bin` }) It("podman run sysctl test", func() { - SkipIfRootless() // Network sysclts are not avalable root rootless + SkipIfRootless("Network sysctls are not avalable root rootless") session := podmanTest.Podman([]string{"run", "--rm", "--sysctl", "net.core.somaxconn=65535", ALPINE, "sysctl", "net.core.somaxconn"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -381,8 +381,8 @@ USER bin` }) It("podman run blkio-weight test", func() { - SkipIfRootless() // FIXME: This is blowing up because of no /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control file - // SkipIfRootlessCgroupsV1() + SkipIfRootless("FIXME: This is blowing up because of no /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control file") + SkipIfRootlessCgroupsV1("Setting blkio-weight not supported on cgroupv1 for rootless users") if !CGROUPSV2 { if _, err := os.Stat("/sys/fs/cgroup/blkio/blkio.weight"); os.IsNotExist(err) { Skip("Kernel does not support blkio.weight") @@ -404,8 +404,9 @@ USER bin` }) It("podman run device-read-bps test", func() { - SkipIfRootless() // FIXME: Missing /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control - SkipIfRootlessCgroupsV1() + SkipIfRootless("FIXME: Missing /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control") + SkipIfRootlessCgroupsV1("Setting device-read-bps not supported on cgroupv1 for rootless users") + var session *PodmanSessionIntegration if CGROUPSV2 { @@ -422,8 +423,9 @@ USER bin` }) It("podman run device-write-bps test", func() { - SkipIfRootless() // FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist - SkipIfRootlessCgroupsV1() + SkipIfRootless("FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist") + SkipIfRootlessCgroupsV1("Setting device-write-bps not supported on cgroupv1 for rootless users") + var session *PodmanSessionIntegration if CGROUPSV2 { @@ -439,8 +441,8 @@ USER bin` }) It("podman run device-read-iops test", func() { - SkipIfRootless() // FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist - SkipIfRootlessCgroupsV1() + SkipIfRootless("FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist") + SkipIfRootlessCgroupsV1("Setting device-read-iops not supported on cgroupv1 for rootless users") var session *PodmanSessionIntegration if CGROUPSV2 { @@ -457,8 +459,8 @@ USER bin` }) It("podman run device-write-iops test", func() { - SkipIfRootless() // FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist - SkipIfRootlessCgroupsV1() + SkipIfRootless("FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist") + SkipIfRootlessCgroupsV1("Setting device-write-iops not supported on cgroupv1 for rootless users") var session *PodmanSessionIntegration if CGROUPSV2 { @@ -575,7 +577,7 @@ USER bin` }) It("podman run with FIPS mode secrets", func() { - SkipIfRootless() // rootless can not manipulate system-fips file + SkipIfRootless("rootless can not manipulate system-fips file") fipsFile := "/etc/system-fips" err = ioutil.WriteFile(fipsFile, []byte{}, 0755) Expect(err).To(BeNil()) @@ -894,7 +896,7 @@ USER mail` }) It("podman run --mount type=bind,bind-nonrecursive", func() { - SkipIfRootless() // rootless users are not allowed to mount bind-nonrecursive (Could this be a Kernel bug? + SkipIfRootless("FIXME: rootless users are not allowed to mount bind-nonrecursive (Could this be a Kernel bug?") session := podmanTest.Podman([]string{"run", "--mount", "type=bind,bind-nonrecursive,slave,src=/,target=/host", fedoraMinimal, "findmnt", "-nR", "/host"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -1054,8 +1056,8 @@ USER mail` }) It("podman run with cgroups=disabled runs without cgroups", func() { - SkipIfRootless() // FIXME: I believe this should work but need to fix this test - SkipIfRootlessCgroupsV1() + SkipIfRootless("FIXME: I believe this should work but need to fix this test") + SkipIfRootlessCgroupsV1("Disable cgroups not supported on cgroupv1 for rootless users") // Only works on crun if !strings.Contains(podmanTest.OCIRuntime, "crun") { Skip("Test only works on crun") @@ -1087,7 +1089,7 @@ USER mail` }) It("podman run with cgroups=enabled makes cgroups", func() { - SkipIfRootlessCgroupsV1() + SkipIfRootlessCgroupsV1("Enable cgroups not supported on cgroupv1 for rootless users") // Only works on crun if !strings.Contains(podmanTest.OCIRuntime, "crun") { Skip("Test only works on crun") @@ -1130,7 +1132,7 @@ USER mail` }) It("podman run --device-cgroup-rule", func() { - SkipIfRootless() // rootless users are not allowed to mknod + SkipIfRootless("rootless users are not allowed to mknod") deviceCgroupRule := "c 42:* rwm" session := podmanTest.Podman([]string{"run", "--name", "test", "-d", "--device-cgroup-rule", deviceCgroupRule, ALPINE, "top"}) session.WaitWithDefaultTimeout() @@ -1208,7 +1210,7 @@ USER mail` }) It("podman run verify pids-limit", func() { - SkipIfCgroupV1() + SkipIfCgroupV1("pids-limit not supported on cgroup V1") limit := "4321" session := podmanTest.Podman([]string{"run", "--pids-limit", limit, "--rm", ALPINE, "cat", "/sys/fs/cgroup/pids.max"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index fc9245e62..92d3418e3 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -227,7 +227,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman run with tmpfs named volume mounts and unmounts", func() { - SkipIfRootless() // FIXME: rootless podman mount requires you to be in a user namespace + SkipIfRootless("FIXME: rootless podman mount requires you to be in a user namespace") SkipIfRemote("podman-remote does not support --volumes this test could be simplified to be tested on Remote.") volName := "testvol" mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"}) diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index a3d56ad89..19365909d 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -186,7 +186,7 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(fakereg.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } search := podmanTest.Podman([]string{"search", @@ -213,7 +213,7 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(registry.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry3", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } podmanTest.RestoreArtifact(ALPINE) @@ -250,7 +250,7 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(registry.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry4", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } podmanTest.RestoreArtifact(ALPINE) @@ -290,7 +290,7 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(registry.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry5", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } podmanTest.RestoreArtifact(ALPINE) @@ -329,7 +329,7 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(registry.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry6", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } podmanTest.RestoreArtifact(ALPINE) @@ -371,7 +371,7 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(registryLocal.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry7", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } registryLocal = podmanTest.Podman([]string{"run", "-d", "-p", "6000:5000", "--name", "registry8", registry}) @@ -379,7 +379,7 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(registryLocal.ExitCode()).To(Equal(0)) if !WaitContainerReady(podmanTest, "registry8", "listening on", 20, 1) { - Skip("Can not start docker registry.") + Skip("Cannot start docker registry.") } podmanTest.RestoreArtifact(ALPINE) diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go index 7ab435007..c8f5efa9d 100644 --- a/test/e2e/stats_test.go +++ b/test/e2e/stats_test.go @@ -21,9 +21,7 @@ var _ = Describe("Podman stats", func() { ) BeforeEach(func() { - if os.Geteuid() != 0 { - SkipIfCgroupV1() - } + SkipIfRootlessCgroupsV1("stats not supported on cgroupv1 for rootless users") var err error tempdir, err = CreateTempDirInTempDir() if err != nil { diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index 8ef1e3ac7..4be8443e3 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -47,7 +47,7 @@ WantedBy=multi-user.target }) It("podman start container by systemd", func() { - SkipIfRootless() // rootless can not write to /etc + SkipIfRootless("rootless can not write to /etc") if os.Getenv("SKIP_USERNS") != "" { Skip("Skip userns tests.") } diff --git a/test/e2e/tree_test.go b/test/e2e/tree_test.go index c6eb0a6eb..eeb00440c 100644 --- a/test/e2e/tree_test.go +++ b/test/e2e/tree_test.go @@ -34,9 +34,7 @@ var _ = Describe("Podman image tree", func() { }) It("podman image tree", func() { - if podmanTest.RemoteTest { - Skip("Does not work on remote client") - } + SkipIfRemote("Does not work on remote client") dockerfile := `FROM docker.io/library/busybox:latest RUN mkdir hello RUN touch test.txt diff --git a/test/e2e/untag_test.go b/test/e2e/untag_test.go index 7766ce634..91a933090 100644 --- a/test/e2e/untag_test.go +++ b/test/e2e/untag_test.go @@ -33,7 +33,6 @@ var _ = Describe("Podman untag", func() { }) It("podman untag all", func() { - SkipIfRemote("FIXME This should work on podman-remote") setup := podmanTest.PodmanNoCache([]string{"pull", ALPINE}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go index 377b721d0..4a2c2d324 100644 --- a/test/e2e/volume_ls_test.go +++ b/test/e2e/volume_ls_test.go @@ -56,7 +56,7 @@ var _ = Describe("Podman volume ls", func() { }) It("podman ls volume with Go template", func() { - Skip(v2fail) + Skip("FIXME: table still not supported in podman volume command") session := podmanTest.Podman([]string{"volume", "create", "myvol"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go index a072bc824..cdced1f13 100644 --- a/test/e2e/volume_rm_test.go +++ b/test/e2e/volume_rm_test.go @@ -55,7 +55,7 @@ var _ = Describe("Podman volume rm", func() { session = podmanTest.Podman([]string{"volume", "rm", "myvol"}) session.WaitWithDefaultTimeout() - Expect(session).To(ExitWithError()) + Expect(session.ExitCode()).To(Equal(2)) Expect(session.ErrorToString()).To(ContainSubstring(cid)) session = podmanTest.Podman([]string{"volume", "rm", "-f", "myvol"}) @@ -70,6 +70,12 @@ var _ = Describe("Podman volume rm", func() { podmanTest.Cleanup() }) + It("podman volume remove bogus", func() { + session := podmanTest.Podman([]string{"volume", "rm", "bogus"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + }) + It("podman rm with --all flag", func() { session := podmanTest.Podman([]string{"volume", "create", "myvol"}) session.WaitWithDefaultTimeout() diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 354c6506d..766948ecc 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -153,8 +153,23 @@ echo $rand | 0 | $rand run_podman run --pull=always $NONLOCAL_IMAGE true is "$output" "Trying to pull .*" "--pull=always [with image PRESENT]: re-fetches" + # Very weird corner case fixed by #7770: 'podman run foo' will run 'myfoo' + # if it exists, because the string 'foo' appears in 'myfoo'. This test + # covers that, as well as making sure that our testimage (which is always + # tagged :YYYYMMDD, never :latest) doesn't match either. + run_podman tag $IMAGE my${PODMAN_TEST_IMAGE_NAME}:latest + run_podman 125 run --pull=never $PODMAN_TEST_IMAGE_NAME true + is "$output" "Error: unable to find a name and tag match for $PODMAN_TEST_IMAGE_NAME in repotags: no such image" \ + "podman run --pull=never with shortname (and implicit :latest)" + + # ...but if we add a :latest tag (without 'my'), it should now work + run_podman tag $IMAGE ${PODMAN_TEST_IMAGE_NAME}:latest + run_podman run --pull=never ${PODMAN_TEST_IMAGE_NAME} cat /home/podman/testimage-id + is "$output" "$PODMAN_TEST_IMAGE_TAG" \ + "podman run --pull=never, with shortname, succeeds if img is present" + run_podman rm -a - run_podman rmi $NONLOCAL_IMAGE + run_podman rmi $NONLOCAL_IMAGE {my,}${PODMAN_TEST_IMAGE_NAME}:latest } # 'run --rmi' deletes the image in the end unless it's used by another container @@ -393,4 +408,28 @@ json-file | f run_podman rm myctr } +@test "podman run --tz" { + # This file will always have a constant reference timestamp + local testfile=/home/podman/testimage-id + + run_podman run --rm $IMAGE date -r $testfile + is "$output" "Sun Sep 13 12:26:40 UTC 2020" "podman run with no TZ" + + run_podman run --rm --tz=MST7MDT $IMAGE date -r $testfile + is "$output" "Sun Sep 13 06:26:40 MDT 2020" "podman run with --tz=MST7MDT" + + # --tz=local pays attention to /etc/localtime, not $TZ. We set TZ anyway, + # to make sure podman ignores it; and, because this test is locale- + # dependent, we pick an obscure zone (+1245) that is unlikely to + # collide with any of our testing environments. + # + # To get a reference timestamp we run 'date' locally; note the explicit + # strftime() format. We can't use --iso=seconds because GNU date adds + # a colon to the TZ offset (eg -07:00) whereas alpine does not (-0700). + run date --date=@1600000000 +%Y-%m-%dT%H:%M:%S%z + expect="$output" + TZ=Pacific/Chatham run_podman run --rm --tz=local $IMAGE date -Iseconds -r $testfile + is "$output" "$expect" "podman run with --tz=local, matches host" +} + # vim: filetype=sh diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index d2454fbf4..150626ded 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -99,7 +99,7 @@ load helpers "Trying to create an already-existing network" run_podman network rm $mynetname - run_podman 125 network rm $mynetname + run_podman 1 network rm $mynetname # rootless CNI leaves behind an image pulled by SHA, hence with no tag. # Remove it if present; we can only remove it by ID. diff --git a/test/system/build-testimage b/test/system/build-testimage index ef14d3afd..53ade57f0 100755 --- a/test/system/build-testimage +++ b/test/system/build-testimage @@ -35,6 +35,12 @@ cd $tmpdir # 'image mount' test will confirm that this file exists and has our YMD tag echo $YMD >testimage-id +# ...but set the timestamp on the file itself to a constant well-known +# value, for use by the 'run --tz' test. Date value chosen for nerdiness +# and because it's in the past. (Much as I'd love FFFFFFFF, we can't +# use any future date because of unpredictable leap second adjustments). +touch --date=@1600000000 testimage-id + # 'pod' test will use this for --infra-command cat >pause <<EOF #!/bin/sh @@ -49,6 +55,7 @@ EOF chmod 755 pause # alpine because it's small and light and reliable +# - check for updates @ https://hub.docker.com/_/alpine # busybox-extras provides httpd needed in 500-networking.bats cat >Containerfile <<EOF FROM docker.io/library/alpine:3.12.0 diff --git a/test/system/helpers.bash b/test/system/helpers.bash index eb3e4c7ec..998db5283 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -7,7 +7,7 @@ PODMAN=${PODMAN:-podman} PODMAN_TEST_IMAGE_REGISTRY=${PODMAN_TEST_IMAGE_REGISTRY:-"quay.io"} PODMAN_TEST_IMAGE_USER=${PODMAN_TEST_IMAGE_USER:-"libpod"} PODMAN_TEST_IMAGE_NAME=${PODMAN_TEST_IMAGE_NAME:-"testimage"} -PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"20200917"} +PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"20200929"} PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG" # Because who wants to spell that out each time? diff --git a/transfer.md b/transfer.md index 49ff687e6..8ead43f63 100644 --- a/transfer.md +++ b/transfer.md @@ -89,6 +89,14 @@ There are other equivalents for these tools **** Use mount to take advantage of the entire linux tool chain rather then just cp. Read [`here`](./docs/podman-cp.1.md) for more information. +## Behavioural differences and pitfalls + +These commands behave differently from the commands in Docker: + +| Command | Description | +| :--- | :--- | +| `podman volume create` | While `docker volume create` is idempotent, `podman volume create` raises an error if the volume does already exist. See this [docker issue](https://github.com/moby/moby/issues/16068) for more information.| + ## Missing commands in podman Those Docker commands currently do not have equivalents in `podman`: |