summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml15
-rw-r--r--cmd/podman/containers/ps.go8
-rw-r--r--cmd/podman/containers/rm.go4
-rw-r--r--cmd/podman/images/build.go2
-rw-r--r--contrib/cirrus/required_host_ports.txt1
-rwxr-xr-xcontrib/cirrus/runner.sh17
-rw-r--r--contrib/rootless-cni-infra/Containerfile4
-rwxr-xr-xcontrib/rootless-cni-infra/rootless-cni-infra20
-rw-r--r--libpod/oci_conmon_exec_linux.go48
-rw-r--r--libpod/rootless_cni_linux.go34
-rw-r--r--libpod/util.go17
-rw-r--r--nix/nixpkgs.json8
-rw-r--r--pkg/api/handlers/compat/containers.go2
-rw-r--r--pkg/api/handlers/libpod/containers.go17
-rw-r--r--pkg/api/server/register_containers.go5
-rw-r--r--pkg/bindings/containers/types.go1
-rw-r--r--pkg/bindings/containers/types_list_options.go16
-rw-r--r--pkg/domain/entities/containers.go2
-rw-r--r--pkg/domain/infra/tunnel/containers.go33
-rw-r--r--pkg/ps/ps.go2
-rw-r--r--pkg/specgen/container_validate.go2
-rw-r--r--pkg/specgen/pod_validate.go2
-rw-r--r--test/e2e/common_test.go4
-rw-r--r--test/e2e/create_staticip_test.go6
-rw-r--r--test/e2e/create_staticmac_test.go8
-rw-r--r--test/e2e/create_test.go4
-rw-r--r--test/e2e/network_test.go1
-rw-r--r--test/e2e/pod_create_test.go4
-rw-r--r--test/e2e/pod_inspect_test.go2
-rw-r--r--test/e2e/ps_test.go7
-rw-r--r--test/e2e/rm_test.go2
-rw-r--r--test/e2e/run_networking_test.go6
-rw-r--r--test/e2e/run_staticip_test.go2
-rw-r--r--test/system/040-ps.bats17
-rw-r--r--test/system/070-build.bats23
-rw-r--r--test/system/075-exec.bats2
36 files changed, 238 insertions, 110 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 5a4815e1c..5b0d9ee6c 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -351,14 +351,13 @@ static_alt_build_task:
ALT_NAME: 'Static build'
# Do not use 'latest', fixed-version tag for runtime stability.
CTR_FQIN: "docker.io/nixos/nix:2.3.6"
- # This is critical, it helps to avoid a very lengthy process of
- # statically building every dependency needed to build podman.
- # Assuming the dependency and build description hasn't changed,
- # this cache ensures only the static podman binary is built.
- nix_cache:
- folder: '/var/cache/nix'
- # Cirrus will calculate/use sha of this output as the cache key
- fingerprint_script: echo "${IMAGE_SUFFIX}" && cat nix/*
+ # Authentication token for pushing the build cache to cachix.
+ # This is critical, it helps to avoid a very lengthy process of
+ # statically building every dependency needed to build podman.
+ # Assuming the pinned nix dependencies in nix/nixpkgs.json have not
+ # changed, this cache will ensure that only the static podman binary is
+ # built.
+ CACHIX_AUTH_TOKEN: ENCRYPTED[df0d4d0a67474e8ea49cc503221dcb912b7e2ba45c8ec4bf2e5fd9c49a18ac21c24bacee59b5393355ed9e4358d2baef]
setup_script: *setup
main_script: *main
always: *binary_artifacts
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index d23771fc5..31f44d92f 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -78,7 +78,7 @@ func listFlagSet(cmd *cobra.Command) {
flags := cmd.Flags()
flags.BoolVarP(&listOpts.All, "all", "a", false, "Show all the containers, default is only running containers")
- flags.BoolVar(&listOpts.Storage, "external", false, "Show containers in storage not controlled by Podman")
+ flags.BoolVar(&listOpts.External, "external", false, "Show containers in storage not controlled by Podman")
filterFlagName := "filter"
flags.StringSliceVarP(&filters, filterFlagName, "f", []string{}, "Filter output based on conditions given")
@@ -132,10 +132,10 @@ func checkFlags(c *cobra.Command) error {
}
cfg := registry.PodmanConfig()
if cfg.Engine.Namespace != "" {
- if c.Flag("storage").Changed && listOpts.Storage {
- return errors.New("--namespace and --storage flags can not both be set")
+ if c.Flag("storage").Changed && listOpts.External {
+ return errors.New("--namespace and --external flags can not both be set")
}
- listOpts.Storage = false
+ listOpts.External = false
}
return nil
diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go
index ea616b6e5..884ad05f4 100644
--- a/cmd/podman/containers/rm.go
+++ b/cmd/podman/containers/rm.go
@@ -140,6 +140,10 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit
}
func setExitCode(err error) {
+ // If error is set to no such container, do not reset
+ if registry.GetExitCode() == 1 {
+ return
+ }
cause := errors.Cause(err)
switch {
case cause == define.ErrNoSuchCtr:
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index 4219e325b..957c0ac2d 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -266,7 +266,7 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
pullPolicy := imagebuildah.PullIfMissing
if c.Flags().Changed("pull") && flags.Pull {
- pullPolicy = imagebuildah.PullAlways
+ pullPolicy = imagebuildah.PullIfNewer
}
if flags.PullAlways {
pullPolicy = imagebuildah.PullAlways
diff --git a/contrib/cirrus/required_host_ports.txt b/contrib/cirrus/required_host_ports.txt
index 9248e497a..5f066e059 100644
--- a/contrib/cirrus/required_host_ports.txt
+++ b/contrib/cirrus/required_host_ports.txt
@@ -2,3 +2,4 @@ github.com 22
docker.io 443
quay.io 443
registry.fedoraproject.org 443
+podman.cachix.org 443
diff --git a/contrib/cirrus/runner.sh b/contrib/cirrus/runner.sh
index 50bc1102f..3292cea84 100755
--- a/contrib/cirrus/runner.sh
+++ b/contrib/cirrus/runner.sh
@@ -241,15 +241,14 @@ function _run_altbuild() {
req_env_vars CTR_FQIN
[[ "$UID" -eq 0 ]] || \
die "Static build must execute nixos container as root on host"
- mkdir -p /var/cache/nix
- podman run -i --rm -v /var/cache/nix:/mnt/nix:Z \
- $CTR_FQIN cp -rfT /nix /mnt/nix
- podman run -i --rm -v /var/cache/nix:/nix:Z \
- -v $PWD:$PWD:Z -w $PWD $CTR_FQIN \
- nix --print-build-logs --option cores 4 --option max-jobs 4 \
- build --file ./nix/
- # result symlink is absolute from container perspective :(
- cp /var/cache/$(readlink result)/bin/podman ./ # for cirrus-ci artifact
+ podman run -i --rm \
+ -e CACHIX_AUTH_TOKEN \
+ -v $PWD:$PWD:Z -w $PWD $CTR_FQIN sh -c \
+ "nix-env -iA cachix -f https://cachix.org/api/v1/install && \
+ cachix use podman && \
+ nix-build nix && \
+ nix-store -qR --include-outputs \$(nix-instantiate nix/default.nix) | grep -v podman | cachix push podman && \
+ cp -R result/bin ."
rm result # makes cirrus puke
;;
*)
diff --git a/contrib/rootless-cni-infra/Containerfile b/contrib/rootless-cni-infra/Containerfile
index 871e06a6c..4324f39d2 100644
--- a/contrib/rootless-cni-infra/Containerfile
+++ b/contrib/rootless-cni-infra/Containerfile
@@ -2,7 +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
-ARG DNSNAME_VERSION=v1.0.0
+ARG DNSNAME_VERSION=v1.1.1
FROM golang:${GOLANG_VERSION}-alpine${ALPINE_VERSION} AS golang-base
RUN apk add --no-cache git
@@ -33,4 +33,4 @@ COPY rootless-cni-infra /usr/local/bin
ENV CNI_PATH=/opt/cni/bin
CMD ["sleep", "infinity"]
-ENV ROOTLESS_CNI_INFRA_VERSION=3
+ENV ROOTLESS_CNI_INFRA_VERSION=5
diff --git a/contrib/rootless-cni-infra/rootless-cni-infra b/contrib/rootless-cni-infra/rootless-cni-infra
index 463254c7f..cceb8d817 100755
--- a/contrib/rootless-cni-infra/rootless-cni-infra
+++ b/contrib/rootless-cni-infra/rootless-cni-infra
@@ -21,16 +21,19 @@ wait_unshare_net() {
done
}
-# CLI subcommand: "alloc $CONTAINER_ID $NETWORK_NAME $POD_NAME"
+# CLI subcommand: "alloc $CONTAINER_ID $NETWORK_NAME $POD_NAME $IP $MAC $CAP_ARGS"
cmd_entrypoint_alloc() {
- if [ "$#" -ne 3 ]; then
- echo >&2 "Usage: $ARG0 alloc CONTAINER_ID NETWORK_NAME POD_NAME"
+ if [ "$#" -ne 6 ]; then
+ echo >&2 "Usage: $ARG0 alloc CONTAINER_ID NETWORK_NAME POD_NAME IP MAC CAP_ARGS"
exit 1
fi
ID="$1"
NET="$2"
K8S_POD_NAME="$3"
+ IP="$4"
+ MAC="$5"
+ CAP_ARGS="$6"
dir="${BASE}/${ID}"
mkdir -p "${dir}/attached" "${dir}/attached-args"
@@ -46,9 +49,18 @@ cmd_entrypoint_alloc() {
nsenter -t "${pid}" -n ip link set lo up
fi
CNI_ARGS="IgnoreUnknown=1;K8S_POD_NAME=${K8S_POD_NAME}"
+ if [ "$IP" ]; then
+ CNI_ARGS="$CNI_ARGS;IP=${IP}"
+ fi
+ if [ "$MAC" ]; then
+ CNI_ARGS="$CNI_ARGS;MAC=${MAC}"
+ fi
+ if [ "$CAP_ARGS" ]; then
+ CAP_ARGS="$CAP_ARGS"
+ fi
nwcount=$(find "${dir}/attached" -type f | wc -l)
CNI_IFNAME="eth${nwcount}"
- export CNI_ARGS CNI_IFNAME
+ export CNI_ARGS CNI_IFNAME CAP_ARGS
cnitool add "${NET}" "/proc/${pid}/ns/net" >"${dir}/attached/${NET}"
echo "${CNI_ARGS}" >"${dir}/attached-args/${NET}"
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index dc5dd03df..faf86ea5b 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -126,20 +126,25 @@ func (r *ConmonOCIRuntime) ExecContainerHTTP(ctr *Container, sessionID string, o
}()
attachChan := make(chan error)
+ conmonPipeDataChan := make(chan conmonPipeData)
go func() {
// attachToExec is responsible for closing pipes
- attachChan <- attachExecHTTP(ctr, sessionID, req, w, streams, pipes, detachKeys, options.Terminal, cancel, hijackDone, holdConnOpen)
+ attachChan <- attachExecHTTP(ctr, sessionID, req, w, streams, pipes, detachKeys, options.Terminal, cancel, hijackDone, holdConnOpen, execCmd, conmonPipeDataChan, ociLog)
close(attachChan)
}()
- // Wait for conmon to succeed, when return.
- if err := execCmd.Wait(); err != nil {
- return -1, nil, errors.Wrapf(err, "cannot run conmon")
- }
+ // NOTE: the channel is needed to communicate conmon's data. In case
+ // of an error, the error will be written on the hijacked http
+ // connection such that remote clients will receive the error.
+ pipeData := <-conmonPipeDataChan
- pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
+ return pipeData.pid, attachChan, pipeData.err
+}
- return pid, attachChan, err
+// conmonPipeData contains the data when reading from conmon's pipe.
+type conmonPipeData struct {
+ pid int
+ err error
}
// ExecContainerDetached executes a command in a running container, but does
@@ -488,9 +493,16 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
}
// Attach to a container over HTTP
-func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.ResponseWriter, streams *HTTPAttachStreams, pipes *execPipes, detachKeys []byte, isTerminal bool, cancel <-chan bool, hijackDone chan<- bool, holdConnOpen <-chan bool) (deferredErr error) {
+func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.ResponseWriter, streams *HTTPAttachStreams, pipes *execPipes, detachKeys []byte, isTerminal bool, cancel <-chan bool, hijackDone chan<- bool, holdConnOpen <-chan bool, execCmd *exec.Cmd, conmonPipeDataChan chan<- conmonPipeData, ociLog string) (deferredErr error) {
+ // NOTE: As you may notice, the attach code is quite complex.
+ // Many things happen concurrently and yet are interdependent.
+ // If you ever change this function, make sure to write to the
+ // conmonPipeDataChan in case of an error.
+
if pipes == nil || pipes.startPipe == nil || pipes.attachPipe == nil {
- return errors.Wrapf(define.ErrInvalidArg, "must provide a start and attach pipe to finish an exec attach")
+ err := errors.Wrapf(define.ErrInvalidArg, "must provide a start and attach pipe to finish an exec attach")
+ conmonPipeDataChan <- conmonPipeData{-1, err}
+ return err
}
defer func() {
@@ -509,17 +521,20 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
// set up the socket path, such that it is the correct length and location for exec
sockPath, err := c.execAttachSocketPath(sessionID)
if err != nil {
+ conmonPipeDataChan <- conmonPipeData{-1, err}
return err
}
// 2: read from attachFd that the parent process has set up the console socket
if _, err := readConmonPipeData(pipes.attachPipe, ""); err != nil {
+ conmonPipeDataChan <- conmonPipeData{-1, err}
return err
}
// 2: then attach
conn, err := openUnixSocket(sockPath)
if err != nil {
+ conmonPipeDataChan <- conmonPipeData{-1, err}
return errors.Wrapf(err, "failed to connect to container's attach socket: %v", sockPath)
}
defer func() {
@@ -540,11 +555,13 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
// Perform hijack
hijacker, ok := w.(http.Hijacker)
if !ok {
+ conmonPipeDataChan <- conmonPipeData{-1, err}
return errors.Errorf("unable to hijack connection")
}
httpCon, httpBuf, err := hijacker.Hijack()
if err != nil {
+ conmonPipeDataChan <- conmonPipeData{-1, err}
return errors.Wrapf(err, "error hijacking connection")
}
@@ -555,10 +572,23 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
// Force a flush after the header is written.
if err := httpBuf.Flush(); err != nil {
+ conmonPipeDataChan <- conmonPipeData{-1, err}
return errors.Wrapf(err, "error flushing HTTP hijack header")
}
go func() {
+ // Wait for conmon to succeed, when return.
+ if err := execCmd.Wait(); err != nil {
+ conmonPipeDataChan <- conmonPipeData{-1, err}
+ } else {
+ pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
+ if err != nil {
+ hijackWriteError(err, c.ID(), isTerminal, httpBuf)
+ conmonPipeDataChan <- conmonPipeData{pid, err}
+ } else {
+ conmonPipeDataChan <- conmonPipeData{pid, err}
+ }
+ }
// We need to hold the connection open until the complete exec
// function has finished. This channel will be closed in a defer
// in that function, so we can wait for it here.
diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go
index 9a980750f..94ae062aa 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:304742d5d221211df4ec672807a5842ff11e3729c50bc424ea0cea858f69d7b7", // 3-amd64
+ "amd64": "quay.io/libpod/rootless-cni-infra@sha256:adf352454666f7ce9ca3e1098448b5ee18f89c4516471ec99447ec9ece917f36", // 5-amd64
}
const (
@@ -58,9 +58,33 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.
return nil, nil, err
}
k8sPodName := getCNIPodName(c) // passed to CNI as K8S_POD_NAME
+ ip := ""
+ if c.config.StaticIP != nil {
+ ip = c.config.StaticIP.String()
+ }
+ mac := ""
+ if c.config.StaticMAC != nil {
+ mac = c.config.StaticMAC.String()
+ }
+ aliases, err := c.runtime.state.GetAllNetworkAliases(c)
+ if err != nil {
+ return nil, nil, err
+ }
+ capArgs := ""
+ // add network aliases json encoded as capabilityArgs for cni
+ if len(aliases) > 0 {
+ capabilityArgs := make(map[string]interface{})
+ capabilityArgs["aliases"] = aliases
+ b, err := json.Marshal(capabilityArgs)
+ if err != nil {
+ return nil, nil, err
+ }
+ capArgs = string(b)
+ }
+
cniResults := make([]*cnitypes.Result, len(networks))
for i, nw := range networks {
- cniRes, err := rootlessCNIInfraCallAlloc(infra, c.ID(), nw, k8sPodName)
+ cniRes, err := rootlessCNIInfraCallAlloc(infra, c.ID(), nw, k8sPodName, ip, mac, capArgs)
if err != nil {
return nil, nil, err
}
@@ -137,11 +161,11 @@ func getCNIPodName(c *Container) string {
return c.Name()
}
-func rootlessCNIInfraCallAlloc(infra *Container, id, nw, k8sPodName string) (*cnitypes.Result, error) {
- logrus.Debugf("rootless CNI: alloc %q, %q, %q", id, nw, k8sPodName)
+func rootlessCNIInfraCallAlloc(infra *Container, id, nw, k8sPodName, ip, mac, capArgs string) (*cnitypes.Result, error) {
+ logrus.Debugf("rootless CNI: alloc %q, %q, %q, %q, %q, %q", id, nw, k8sPodName, ip, mac, capArgs)
var err error
- _, err = rootlessCNIInfraExec(infra, "alloc", id, nw, k8sPodName)
+ _, err = rootlessCNIInfraExec(infra, "alloc", id, nw, k8sPodName, ip, mac, capArgs)
if err != nil {
return nil, err
}
diff --git a/libpod/util.go b/libpod/util.go
index bf9bf2542..391208fb9 100644
--- a/libpod/util.go
+++ b/libpod/util.go
@@ -235,20 +235,16 @@ func checkDependencyContainer(depCtr, ctr *Container) error {
return nil
}
-// hijackWriteErrorAndClose writes an error to a hijacked HTTP session and
-// closes it. Intended to HTTPAttach function.
-// If error is nil, it will not be written; we'll only close the connection.
-func hijackWriteErrorAndClose(toWrite error, cid string, terminal bool, httpCon io.Closer, httpBuf *bufio.ReadWriter) {
+// hijackWriteError writes an error to a hijacked HTTP session.
+func hijackWriteError(toWrite error, cid string, terminal bool, httpBuf *bufio.ReadWriter) {
if toWrite != nil {
- errString := []byte(fmt.Sprintf("%v\n", toWrite))
+ errString := []byte(fmt.Sprintf("Error: %v\n", toWrite))
if !terminal {
// We need a header.
header := makeHTTPAttachHeader(2, uint32(len(errString)))
if _, err := httpBuf.Write(header); err != nil {
logrus.Errorf("Error writing header for container %s attach connection error: %v", cid, err)
}
- // TODO: May want to return immediately here to avoid
- // writing garbage to the socket?
}
if _, err := httpBuf.Write(errString); err != nil {
logrus.Errorf("Error writing error to container %s HTTP attach connection: %v", cid, err)
@@ -257,6 +253,13 @@ func hijackWriteErrorAndClose(toWrite error, cid string, terminal bool, httpCon
logrus.Errorf("Error flushing HTTP buffer for container %s HTTP attach connection: %v", cid, err)
}
}
+}
+
+// hijackWriteErrorAndClose writes an error to a hijacked HTTP session and
+// closes it. Intended to HTTPAttach function.
+// If error is nil, it will not be written; we'll only close the connection.
+func hijackWriteErrorAndClose(toWrite error, cid string, terminal bool, httpCon io.Closer, httpBuf *bufio.ReadWriter) {
+ hijackWriteError(toWrite, cid, terminal, httpBuf)
if err := httpCon.Close(); err != nil {
logrus.Errorf("Error closing container %s HTTP attach connection: %v", cid, err)
diff --git a/nix/nixpkgs.json b/nix/nixpkgs.json
index d304de536..0cfb251f2 100644
--- a/nix/nixpkgs.json
+++ b/nix/nixpkgs.json
@@ -1,9 +1,9 @@
{
"url": "https://github.com/nixos/nixpkgs",
- "rev": "4a75203f0270f96cbc87f5dfa5d5185690237d87",
- "date": "2020-12-29T03:18:48+01:00",
- "path": "/nix/store/scswsm6r4jnhp9ki0f6s81kpj5x6jkn7-nixpkgs",
- "sha256": "0h70fm9aa7s06wkalbadw70z5rscbs3p6nblb47z523nhlzgjxk9",
+ "rev": "ce7b327a52d1b82f82ae061754545b1c54b06c66",
+ "date": "2021-01-25T11:28:05+01:00",
+ "path": "/nix/store/dpsa6a1sy8hwhwjkklc52brs9z1k5fx9-nixpkgs",
+ "sha256": "1rc4if8nmy9lrig0ddihdwpzg2s8y36vf20hfywb8hph5hpsg4vj",
"fetchSubmodules": false,
"deepClone": false,
"leaveDotGit": false
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index aa12afc82..0f91a4362 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -73,7 +73,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- if report[0].Err != nil {
+ if len(report) > 0 && report[0].Err != nil {
utils.InternalServerError(w, report[0].Err)
return
}
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 6b07b1cc5..a0cb1d49e 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -12,7 +12,6 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/abi"
- "github.com/containers/podman/v2/pkg/ps"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -63,6 +62,7 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
All bool `schema:"all"`
+ External bool `schema:"external"`
Filters map[string][]string `schema:"filters"`
Last int `schema:"last"` // alias for limit
Limit int `schema:"limit"`
@@ -90,17 +90,22 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
}
runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
opts := entities.ContainerListOptions{
All: query.All,
+ External: query.External,
Filters: query.Filters,
Last: limit,
- Size: query.Size,
- Sort: "",
Namespace: query.Namespace,
- Pod: true,
- Sync: query.Sync,
+ // Always return Pod, should not be part of the API.
+ // https://github.com/containers/podman/pull/7223
+ Pod: true,
+ Size: query.Size,
+ Sync: query.Sync,
}
- pss, err := ps.GetContainerLists(runtime, opts)
+ pss, err := containerEngine.ContainerList(r.Context(), opts)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 74a04b2e6..e30747800 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -48,6 +48,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// default: false
// description: Return all containers. By default, only running containers are shown
// - in: query
+ // name: external
+ // type: boolean
+ // default: false
+ // description: Return containers in storage not controlled by Podman
+ // - in: query
// name: limit
// description: Return this number of most recently created containers, including non-running ones.
// type: integer
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 24604fa83..3fb1ab733 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -106,6 +106,7 @@ type MountedContainerPathsOptions struct{}
// ListOptions are optional options for listing containers
type ListOptions struct {
All *bool
+ External *bool
Filters map[string][]string
Last *int
Namespace *bool
diff --git a/pkg/bindings/containers/types_list_options.go b/pkg/bindings/containers/types_list_options.go
index 43326fa59..c363dcd32 100644
--- a/pkg/bindings/containers/types_list_options.go
+++ b/pkg/bindings/containers/types_list_options.go
@@ -103,6 +103,22 @@ func (o *ListOptions) GetAll() bool {
return *o.All
}
+// WithExternal
+func (o *ListOptions) WithExternal(value bool) *ListOptions {
+ v := &value
+ o.External = v
+ return o
+}
+
+// GetExternal
+func (o *ListOptions) GetExternal() bool {
+ var external bool
+ if o.External == nil {
+ return external
+ }
+ return *o.External
+}
+
// WithFilters
func (o *ListOptions) WithFilters(value map[string][]string) *ListOptions {
v := value
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 4c1bd6a7d..2c32f792f 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -297,8 +297,8 @@ type ContainerListOptions struct {
Pod bool
Quiet bool
Size bool
+ External bool
Sort string
- Storage bool
Sync bool
Watch uint
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 524b29553..0c61714c3 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -173,19 +173,32 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) {
- ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
- if err != nil {
- return nil, err
- }
// TODO there is no endpoint for container eviction. Need to discuss
- reports := make([]*entities.RmReport, 0, len(ctrs))
- options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes)
- for _, c := range ctrs {
+ options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes).WithIgnore(opts.Ignore)
+
+ if opts.All {
+ ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ reports := make([]*entities.RmReport, 0, len(ctrs))
+ for _, c := range ctrs {
+ reports = append(reports, &entities.RmReport{
+ Id: c.ID,
+ Err: containers.Remove(ic.ClientCtx, c.ID, options),
+ })
+ }
+ return reports, nil
+ }
+
+ reports := make([]*entities.RmReport, 0, len(namesOrIds))
+ for _, name := range namesOrIds {
reports = append(reports, &entities.RmReport{
- Id: c.ID,
- Err: containers.Remove(ic.ClientCtx, c.ID, options),
+ Id: name,
+ Err: containers.Remove(ic.ClientCtx, name, options),
})
}
+
return reports, nil
}
@@ -601,7 +614,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
func (ic *ContainerEngine) ContainerList(ctx context.Context, opts entities.ContainerListOptions) ([]entities.ListContainer, error) {
options := new(containers.ListOptions).WithFilters(opts.Filters).WithAll(opts.All).WithLast(opts.Last)
- options.WithNamespace(opts.Namespace).WithSize(opts.Size).WithSync(opts.Sync)
+ options.WithNamespace(opts.Namespace).WithSize(opts.Size).WithSync(opts.Sync).WithExternal(opts.External)
return containers.List(ic.ClientCtx, options)
}
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index dc577890a..42f9e1d39 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -69,7 +69,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp
pss = append(pss, listCon)
}
- if options.All && options.Storage {
+ if options.All && options.External {
externCons, err := runtime.StorageContainers()
if err != nil {
return nil, err
diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go
index a0d36f865..81cb8b78d 100644
--- a/pkg/specgen/container_validate.go
+++ b/pkg/specgen/container_validate.go
@@ -30,7 +30,7 @@ func exclusiveOptions(opt1, opt2 string) error {
// input for creating a container.
func (s *SpecGenerator) Validate() error {
- if rootless.IsRootless() {
+ if rootless.IsRootless() && len(s.CNINetworks) == 0 {
if s.StaticIP != nil || s.StaticIPv6 != nil {
return ErrNoStaticIPRootless
}
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index 7c81f3f9f..518adb32f 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -20,7 +20,7 @@ func exclusivePodOptions(opt1, opt2 string) error {
// Validate verifies the input is valid
func (p *PodSpecGenerator) Validate() error {
- if rootless.IsRootless() {
+ if rootless.IsRootless() && len(p.CNINetworks) == 0 {
if p.StaticIP != nil {
return ErrNoStaticIPRootless
}
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 2668b1e7b..781bbb6d2 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -10,6 +10,7 @@ import (
"sort"
"strconv"
"strings"
+ "sync"
"testing"
"time"
@@ -84,6 +85,7 @@ type testResultsSortedLength struct{ testResultsSorted }
func (a testResultsSorted) Less(i, j int) bool { return a[i].length < a[j].length }
var testResults []testResult
+var testResultsMutex sync.Mutex
func TestMain(m *testing.M) {
if reexec.Init() {
@@ -349,7 +351,9 @@ func (p *PodmanTestIntegration) InspectContainer(name string) []define.InspectCo
func processTestResult(f GinkgoTestDescription) {
tr := testResult{length: f.Duration.Seconds(), name: f.TestText}
+ testResultsMutex.Lock()
testResults = append(testResults, tr)
+ testResultsMutex.Unlock()
}
func GetPortLock(port string) storage.Locker {
diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go
index 7a2267617..698bbf976 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 not supported without network 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))
@@ -63,7 +63,7 @@ var _ = Describe("Podman create with --ip flag", func() {
ip := GetRandomIPAddress()
result := podmanTest.Podman([]string{"create", "--name", "test", "--ip", ip, ALPINE, "ip", "addr"})
result.WaitWithDefaultTimeout()
- // Rootless static ip assignment should error
+ // Rootless static ip assignment without network should error
if rootless.IsRootless() {
Expect(result.ExitCode()).To(Equal(125))
} else {
@@ -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 without network 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_staticmac_test.go b/test/e2e/create_staticmac_test.go
index 1ac431da2..4c8f371a4 100644
--- a/test/e2e/create_staticmac_test.go
+++ b/test/e2e/create_staticmac_test.go
@@ -56,11 +56,7 @@ var _ = Describe("Podman run with --mac-address flag", func() {
result := podmanTest.Podman([]string{"run", "--network", net, "--mac-address", "92:d0:c6:00:29:34", ALPINE, "ip", "addr"})
result.WaitWithDefaultTimeout()
- if rootless.IsRootless() {
- Expect(result.ExitCode()).To(Equal(125))
- } else {
- Expect(result.ExitCode()).To(Equal(0))
- Expect(result.OutputToString()).To(ContainSubstring("92:d0:c6:00:29:34"))
- }
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(ContainSubstring("92:d0:c6:00:29:34"))
})
})
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 73d92e5a0..67c08ac09 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -553,7 +553,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 without network")
name := "createwithstaticip"
pod := podmanTest.RunTopContainerInPod("", "new:"+name)
pod.WaitWithDefaultTimeout()
@@ -565,7 +565,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 without network")
name := "createwithstaticmac"
pod := podmanTest.RunTopContainerInPod("", "new:"+name)
pod.WaitWithDefaultTimeout()
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index e2080244b..2f5290c76 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -408,7 +408,6 @@ var _ = Describe("Podman network", func() {
Expect(lines[1]).To(Equal(netName2))
})
It("podman network with multiple aliases", func() {
- Skip("Until DNSName is updated on our CI images")
var worked bool
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index be0a2f6f0..9c448a81e 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -233,7 +233,7 @@ var _ = Describe("Podman pod create", func() {
ip := GetRandomIPAddress()
podCreate := podmanTest.Podman([]string{"pod", "create", "--ip", ip, "--name", name})
podCreate.WaitWithDefaultTimeout()
- // Rootless should error
+ // Rootless should error without network
if rootless.IsRootless() {
Expect(podCreate.ExitCode()).To(Equal(125))
} else {
@@ -246,7 +246,7 @@ var _ = Describe("Podman pod create", func() {
})
It("podman container in pod with IP address shares IP address", func() {
- SkipIfRootless("Rootless does not support --ip")
+ SkipIfRootless("Rootless does not support --ip without network")
podName := "test"
ctrName := "testCtr"
ip := GetRandomIPAddress()
diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go
index 25212991d..fd9589afe 100644
--- a/test/e2e/pod_inspect_test.go
+++ b/test/e2e/pod_inspect_test.go
@@ -101,7 +101,7 @@ var _ = Describe("Podman pod inspect", func() {
})
It("podman pod inspect outputs show correct MAC", func() {
- SkipIfRootless("--mac-address is not supported in rootless mode")
+ SkipIfRootless("--mac-address is not supported in rootless mode without network")
podName := "testPod"
macAddr := "42:43:44:00:00:01"
create := podmanTest.Podman([]string{"pod", "create", "--name", podName, "--mac-address", macAddr})
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 13701fc3b..d12534219 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -396,11 +396,14 @@ var _ = Describe("Podman ps", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"ps", "--pod", "--no-trunc"})
-
+ session = podmanTest.Podman([]string{"ps", "--no-trunc"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(Not(ContainSubstring(podid)))
+ session = podmanTest.Podman([]string{"ps", "--pod", "--no-trunc"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(podid))
})
diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go
index ca142d7f3..4c50a61ef 100644
--- a/test/e2e/rm_test.go
+++ b/test/e2e/rm_test.go
@@ -132,7 +132,7 @@ var _ = Describe("Podman rm", func() {
latest := "-l"
if IsRemote() {
- latest = "test1"
+ latest = cid
}
result := podmanTest.Podman([]string{"rm", latest})
result.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index cbaae7186..ebea2132a 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -621,7 +621,6 @@ var _ = Describe("Podman run networking", func() {
})
It("podman run in custom CNI network with --static-ip", func() {
- SkipIfRootless("Rootless mode does not support --ip")
netName := stringid.GenerateNonCryptoID()
ipAddr := "10.25.30.128"
create := podmanTest.Podman([]string{"network", "create", "--subnet", "10.25.30.0/24", netName})
@@ -633,10 +632,6 @@ var _ = Describe("Podman run networking", func() {
run.WaitWithDefaultTimeout()
Expect(run.ExitCode()).To(BeZero())
Expect(run.OutputToString()).To(ContainSubstring(ipAddr))
-
- create = podmanTest.Podman([]string{"network", "rm", netName})
- create.WaitWithDefaultTimeout()
- Expect(create.ExitCode()).To(BeZero())
})
It("podman rootless fails custom CNI network with --uidmap", func() {
@@ -658,7 +653,6 @@ var _ = Describe("Podman run networking", func() {
})
It("podman run with new:pod and static-ip", func() {
- SkipIfRootless("Rootless does not support --ip")
netName := stringid.GenerateNonCryptoID()
ipAddr := "10.25.40.128"
podname := "testpod"
diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go
index 8383b1812..aeb462ae9 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 without network")
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/system/040-ps.bats b/test/system/040-ps.bats
index 0ae8b0ce0..ae27c479f 100644
--- a/test/system/040-ps.bats
+++ b/test/system/040-ps.bats
@@ -82,11 +82,10 @@ load helpers
run_podman rm -a
}
-@test "podman ps -a --storage" {
- skip_if_remote "ps --storage does not work over remote"
+@test "podman ps -a --external" {
# Setup: ensure that we have no hidden storage containers
- run_podman ps --storage -a
+ run_podman ps --external -a
is "${#lines[@]}" "1" "setup check: no storage containers at start of test"
# Force a buildah timeout; this leaves a buildah container behind
@@ -98,18 +97,18 @@ EOF
run_podman ps -a
is "${#lines[@]}" "1" "podman ps -a does not see buildah container"
- run_podman ps --storage -a
- is "${#lines[@]}" "2" "podman ps -a --storage sees buildah container"
+ run_podman ps --external -a
+ is "${#lines[@]}" "2" "podman ps -a --external sees buildah container"
is "${lines[1]}" \
"[0-9a-f]\{12\} \+$IMAGE *buildah .* seconds ago .* storage .* ${PODMAN_TEST_IMAGE_NAME}-working-container" \
- "podman ps --storage"
+ "podman ps --external"
cid="${lines[1]:0:12}"
# 'rm -a' should be a NOP
run_podman rm -a
- run_podman ps --storage -a
- is "${#lines[@]}" "2" "podman ps -a --storage sees buildah container"
+ run_podman ps --external -a
+ is "${#lines[@]}" "2" "podman ps -a --external sees buildah container"
# We can't rm it without -f, but podman should issue a helpful message
run_podman 2 rm "$cid"
@@ -118,7 +117,7 @@ EOF
# With -f, we can remove it.
run_podman rm -f "$cid"
- run_podman ps --storage -a
+ run_podman ps --external -a
is "${#lines[@]}" "1" "storage container has been removed"
}
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index 7a42a4c18..6b5bc68fb 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -29,6 +29,29 @@ EOF
run_podman rmi -f build_test
}
+@test "podman build - basic test with --pull" {
+ rand_filename=$(random_string 20)
+ rand_content=$(random_string 50)
+
+ run_podman tag $IMAGE localhost/localonly
+
+ tmpdir=$PODMAN_TMPDIR/build-test
+ mkdir -p $tmpdir
+ dockerfile=$tmpdir/Dockerfile
+ cat >$dockerfile <<EOF
+FROM localhost/localonly
+RUN echo $rand_content > /$rand_filename
+EOF
+ # With --pull, Podman would try to pull a newer image but use the local one
+ # if present. See #9111.
+ run_podman build --pull -t build_test $tmpdir
+
+ run_podman run --rm build_test cat /$rand_filename
+ is "$output" "$rand_content" "reading generated file in image"
+
+ run_podman rmi -f build_test localhost/localonly
+}
+
@test "podman build - global runtime flags test" {
skip_if_remote "--runtime-flag flag not supported for remote"
diff --git a/test/system/075-exec.bats b/test/system/075-exec.bats
index c028e16c9..badf44c49 100644
--- a/test/system/075-exec.bats
+++ b/test/system/075-exec.bats
@@ -6,8 +6,6 @@
load helpers
@test "podman exec - basic test" {
- skip_if_remote "FIXME: pending #7241"
-
rand_filename=$(random_string 20)
rand_content=$(random_string 50)