summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/containers/exists.go15
-rw-r--r--cmd/podman/containers/ps.go2
-rw-r--r--cmd/podman/diff.go5
-rw-r--r--cmd/podman/utils/alias.go2
-rw-r--r--completions/bash/podman558
-rwxr-xr-xcontrib/cirrus/setup_environment.sh4
-rw-r--r--docs/source/markdown/podman-container-exists.1.md16
-rw-r--r--docs/source/markdown/podman-container-prune.1.md2
-rw-r--r--docs/source/markdown/podman-container-runlabel.1.md4
-rw-r--r--docs/source/markdown/podman-generate-kube.1.md4
-rw-r--r--docs/source/markdown/podman-generate-systemd.1.md4
-rw-r--r--docs/source/markdown/podman-image-exists.1.md2
-rw-r--r--docs/source/markdown/podman-image-prune.1.md2
-rw-r--r--docs/source/markdown/podman-play-kube.1.md4
-rw-r--r--docs/source/markdown/podman-pod-exists.1.md2
-rw-r--r--docs/source/markdown/podman-ps.1.md78
-rw-r--r--docs/source/markdown/podman-restart.1.md2
-rw-r--r--libpod/boltdb_state_internal.go30
-rw-r--r--libpod/diff.go20
-rw-r--r--libpod/network/create.go6
-rw-r--r--libpod/runtime.go19
-rw-r--r--libpod/runtime_cstorage.go4
-rw-r--r--libpod/runtime_ctr.go5
-rw-r--r--libpod/shutdown/handler.go131
-rw-r--r--pkg/api/handlers/compat/containers_create.go2
-rw-r--r--pkg/api/handlers/libpod/containers.go30
-rw-r--r--pkg/api/server/server.go24
-rw-r--r--pkg/bindings/containers/attach.go52
-rw-r--r--pkg/bindings/containers/containers.go6
-rw-r--r--pkg/bindings/test/containers_test.go12
-rw-r--r--pkg/domain/entities/containers.go5
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/infra/abi/containers.go16
-rw-r--r--pkg/domain/infra/abi/containers_runlabel.go3
-rw-r--r--pkg/domain/infra/abi/play.go2
-rw-r--r--pkg/domain/infra/abi/terminal/sigproxy_linux.go5
-rw-r--r--pkg/domain/infra/tunnel/containers.go9
-rw-r--r--pkg/specgen/generate/ports.go46
-rw-r--r--test/e2e/common_test.go9
-rw-r--r--test/e2e/play_kube_test.go19
-rw-r--r--test/e2e/runlabel_test.go5
-rw-r--r--test/endpoint/setup.go9
-rw-r--r--test/system/030-run.bats13
-rw-r--r--test/system/055-rm.bats9
-rw-r--r--test/system/140-diff.bats22
-rw-r--r--test/system/helpers.bash18
46 files changed, 726 insertions, 513 deletions
diff --git a/cmd/podman/containers/exists.go b/cmd/podman/containers/exists.go
index 283f6df18..1d79b684d 100644
--- a/cmd/podman/containers/exists.go
+++ b/cmd/podman/containers/exists.go
@@ -12,10 +12,10 @@ var (
containerExistsDescription = `If the named container exists in local storage, podman container exists exits with 0, otherwise the exit code will be 1.`
existsCommand = &cobra.Command{
- Use: "exists CONTAINER",
+ Use: "exists [flags] CONTAINER",
Short: "Check if a container exists in local storage",
Long: containerExistsDescription,
- Example: `podman container exists containerID
+ Example: `podman container exists --external containerID
podman container exists myctr || podman run --name myctr [etc...]`,
RunE: exists,
Args: cobra.ExactArgs(1),
@@ -29,10 +29,19 @@ func init() {
Command: existsCommand,
Parent: containerCmd,
})
+ flags := existsCommand.Flags()
+ flags.Bool("external", false, "Check external storage containers as well as Podman containers")
}
func exists(cmd *cobra.Command, args []string) error {
- response, err := registry.ContainerEngine().ContainerExists(context.Background(), args[0])
+ external, err := cmd.Flags().GetBool("external")
+ if err != nil {
+ return err
+ }
+ options := entities.ContainerExistsOptions{
+ External: external,
+ }
+ response, err := registry.ContainerEngine().ContainerExists(context.Background(), args[0], options)
if err != nil {
return err
}
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 65bfc97da..41d309f51 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -58,7 +58,7 @@ func init() {
func listFlagSet(flags *pflag.FlagSet) {
flags.BoolVarP(&listOpts.All, "all", "a", false, "Show all the containers, default is only running containers")
flags.StringSliceVarP(&filters, "filter", "f", []string{}, "Filter output based on conditions given")
- flags.BoolVar(&listOpts.Storage, "storage", false, "Show containers in storage not controlled by Podman")
+ flags.BoolVar(&listOpts.Storage, "external", false, "Show containers in storage not controlled by Podman")
flags.StringVar(&listOpts.Format, "format", "", "Pretty-print containers to JSON or using a Go template")
flags.IntVarP(&listOpts.Last, "last", "n", -1, "Print the n last created containers (all states)")
flags.BoolVar(&listOpts.Namespace, "ns", false, "Display namespace information")
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 51a04bf46..9d2236abe 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -48,7 +48,10 @@ func diff(cmd *cobra.Command, args []string) error {
return containers.Diff(cmd, args, diffOpts)
}
- if found, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), args[0]); err != nil {
+ options := entities.ContainerExistsOptions{
+ External: true,
+ }
+ if found, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), args[0], options); err != nil {
return err
} else if found.Value {
return containers.Diff(cmd, args, diffOpts)
diff --git a/cmd/podman/utils/alias.go b/cmd/podman/utils/alias.go
index ff31e82ea..10b96fa98 100644
--- a/cmd/podman/utils/alias.go
+++ b/cmd/podman/utils/alias.go
@@ -21,6 +21,8 @@ func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
name = "time"
case "namespace":
name = "ns"
+ case "storage":
+ name = "external"
}
return pflag.NormalizedName(name)
}
diff --git a/completions/bash/podman b/completions/bash/podman
index 564d35f67..c08bb3352 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -755,10 +755,8 @@ _podman_attach() {
--detach-keys
"
local boolean_options="
- --help
- -h
- --latest
- -l
+ --help -h
+ --latest -l
--no-stdin
--sig-proxy
"
@@ -782,18 +780,13 @@ _podman_container_checkpoint() {
--export
"
local boolean_options="
- -a
- --all
- -h
- --help
- -k
- --keep
- -l
- --latest
- -R
- --leave-running
- --tcp-established
+ --all -a
+ --help -h
--ignore-rootfs
+ --keep -k
+ --latest -l
+ --leave-running -R
+ --tcp-established
"
case "$prev" in
-e|--export)
@@ -897,18 +890,14 @@ _podman_container_restore() {
--name
"
local boolean_options="
- -a
- --all
- -h
- --help
- -k
- --keep
- -l
- --latest
- --tcp-established
+ --all -a
+ --help -h
--ignore-rootfs
--ignore-static-ip
--ignore-static-mac
+ --keep -k
+ --latest -l
+ --tcp-established
"
case "$prev" in
-i|--import)
@@ -1015,9 +1004,8 @@ _podman_network_create() {
--subnet
"
local boolean_options="
- --disable-dns
- --help
- -h
+ --disable-dns
+ --help -h
--internal
"
_complete_ "$options_with_args" "$boolean_options"
@@ -1049,9 +1037,8 @@ _podman_network_inspect() {
_podman_network_ls() {
local options_with_args="
- --format
- -f
--filter
+ --format -f
"
local boolean_options="
--help
@@ -1072,10 +1059,8 @@ _podman_network_rm() {
local options_with_args="
"
local boolean_options="
- --force
- -f
- --help
- -h
+ --force -f
+ --help -h
"
_complete_ "$options_with_args" "$boolean_options"
@@ -1222,12 +1207,9 @@ _podman_system_prune() {
"
local boolean_options="
- -a
- --all
- -f
- --force
- -h
- --help
+ --all -a
+ --force -f
+ --help -h
--volumes
"
case "$cur" in
@@ -1287,12 +1269,9 @@ _podman_commit() {
--iidfile
"
local boolean_options="
- --help
- -h
- --pause
- -p
- --quiet
- -q
+ --help -h
+ --pause -p
+ --quiet -q
"
_complete_ "$options_with_args" "$boolean_options"
@@ -1309,15 +1288,13 @@ _podman_commit() {
_podman_build() {
local boolean_options="
--force-rm
- --help
- -h
+ --help -h
--layers
--no-cache
--pull
--pull-always
--pull-never
- --quiet
- -q
+ --quiet -q
--rm
--squash
--squash-all
@@ -1340,33 +1317,29 @@ _podman_build() {
--cpuset-cpus
--cpuset-mems
--creds
- -f
- --file
+ --file -f
--format
--iidfile
--ipc
--label
- -m
- --memory
+ --memory -m
--memory-swap
+ --mount
--net
--network
--pid
--runtime-flag
--security-opt
--shm-size
- -t
- --tag
+ --tag -t
--ulimit
--userns
- --userns-uid-map
--userns-gid-map
- --userns-uid-map-user
--userns-gid-map-group
+ --userns-uid-map
+ --userns-uid-map-user
--uts
- --mount
- --volume
- -v
+ --volume -v
"
case "$prev" in
@@ -1414,13 +1387,10 @@ _podman_exec() {
-w
"
local boolean_options="
- --help
- -h
- --latest
- -l
+ --help -h
+ --latest -l
--privileged
- --tty
- -t
+ --tty -t
"
case "$cur" in
-*)
@@ -1456,8 +1426,7 @@ _podman_history() {
--format
"
local boolean_options="
- --help
- -h
+ --help -h
--human -H
--no-trunc
--quiet -q
@@ -1540,12 +1509,9 @@ _podman_image_umount() {
_podman_image_unmount() {
local boolean_options="
- --all
- -a
- --help
- -h
- --force
- -f
+ --all -a
+ --help -h
+ --force -f
"
local options_with_args="
"
@@ -1563,10 +1529,8 @@ _podman_image_unmount() {
_podman_image_mount() {
local boolean_options="
- --all
- -a
- --help
- -h
+ --all -a
+ --help -h
"
local options_with_args="
@@ -1680,21 +1644,15 @@ _podman_image() {
_podman_images() {
local boolean_options="
- -a
- --all
+ --all -a
--digests
- --digests
- -f
- --filter
- -h
- --help
+ --filter -f
+ --help -h
--history
--no-trunc
- --notruncate
- -n
--noheading
- -q
- --quiet
+ --notruncate -n
+ --quiet -q
"
local options_with_args="
--format
@@ -1715,10 +1673,8 @@ _podman_images() {
_podman_inspect() {
local boolean_options="
- --help
- -h
- --latest
- -l
+ --help -h
+ --latest -l
"
local options_with_args="
--format
@@ -1785,12 +1741,9 @@ _podman_kill() {
--signal -s
"
local boolean_options="
- --all
- -a
- --help
- -h
- --latest
- -l
+ --all -a
+ --help -h
+ --latest -l
"
case "$cur" in
-*)
@@ -1808,14 +1761,10 @@ _podman_logs() {
--tail
"
local boolean_options="
- --follow
- -f
- --help
- -h
- --latest
- -l
- --timestamps
- -t
+ --follow -f
+ --help -h
+ --latest -l
+ --timestamps -t
"
_complete_ "$options_with_args" "$boolean_options"
@@ -1856,10 +1805,10 @@ _podman_manifest() {
_podman_manifest_add() {
local options_with_args="
--annotation
+ --arch
--authfile
--cert-dir
--creds
- --arch
--features
--os
--os-version
@@ -1946,20 +1895,18 @@ _podman_manifest_push() {
--cert-dir
--creds
--digestfile
- --format
- -f
+ --format -f
--sign-by
--signature-policy,
"
local boolean_options="
--all
+ --help -h
--purge
- --help
- -h
+ --quiet
--remove-signatures
--tls-verify
- --quiet
"
_complete_ "$options_with_args" "$boolean_options"
@@ -2001,13 +1948,10 @@ _podman_pull() {
--override-variant
"
local boolean_options="
- --all-tags
- -a
+ --all-tags -a
--disable-content-trust
- --help
- -h
- --quiet
- -q
+ --help -h
+ --quiet -q
--tls-verify
"
_complete_ "$options_with_args" "$boolean_options"
@@ -2035,14 +1979,10 @@ _podman_unmount() {
_podman_umount() {
local boolean_options="
- --all
- -a
- --help
- -h
- --force
- -f
- --latest
- -l
+ --all -a
+ --help -h
+ --force -f
+ --latest -l
"
local options_with_args="
"
@@ -2060,12 +2000,9 @@ _podman_umount() {
_podman_mount() {
local boolean_options="
- --all
- -a
- --help
- -h
- -l
- --latest
+ --all -a
+ --help -h
+ --latest -l
--notruncate
"
@@ -2088,19 +2025,17 @@ _podman_push() {
local boolean_options="
--compress
--digestflag
- --help
- -h
- --quiet
- -q
+ --help -h
+ --quiet -q
--tls-verify
"
local options_with_args="
- --authfile
- --format
- --cert-dir
- --creds
- --sign-by
+ --authfile
+ --cert-dir
+ --creds
+ --format
+ --sign-by
"
local all_options="$options_with_args $boolean_options"
@@ -2125,18 +2060,18 @@ _podman_container_run() {
--builtin-volume
--cap-add
--cap-drop
- --cgroup-parent
--cgroup-conf
+ --cgroup-parent
--cidfile
--conmon-pidfile
--cpu-period
--cpu-quota
--cpu-rt-period
--cpu-rt-runtime
- --cpuset-cpus
+ --cpu-shares -c
--cpus
+ --cpuset-cpus
--cpuset-mems
- --cpu-shares -c
--device
--device-cgroup-rule
--device-read-bps
@@ -2148,8 +2083,8 @@ _podman_container_run() {
--dns-search
--entrypoint
--env -e
- --env-host
--env-file
+ --env-host
--expose
--gidmap
--group-add
@@ -2165,15 +2100,15 @@ _podman_container_run() {
--ip
--ipc
--kernel-memory
- --label-file
--label -l
+ --label-file
--log-driver
--log-opt
--mac-address
--memory -m
+ --memory-reservation
--memory-swap
--memory-swappiness
- --memory-reservation
--name
--network
--no-healthcheck
@@ -2190,8 +2125,8 @@ _podman_container_run() {
--publish -p
--pull
--restart
- --runtime
--rootfs
+ --runtime
--security-opt
--shm-size
--stop-signal
@@ -2202,21 +2137,20 @@ _podman_container_run() {
--systemd
--tmpfs
--tz
- --umask
--uidmap
--ulimit
+ --umask
--user -u
--userns
--uts
- --volumes-from
--volume -v
+ --volumes-from
--workdir -w
"
local boolean_options="
--disable-content-trust=false
- --help
- -h
+ --help -h
--init
--interactive -i
--oom-kill-disable
@@ -2234,8 +2168,8 @@ _podman_container_run() {
--health-cmd
--health-interval
--health-retries
- --health-timeout
--health-start-period
+ --health-timeout
"
boolean_options="$boolean_options
--detach -d
@@ -2437,12 +2371,9 @@ _podman_restart() {
--time -t
"
local boolean_options="
- --all
- -a
- --help
- -h
- --latest
- -l
+ --all -a
+ --help -h
+ --latest -l
--running
"
case "$cur" in
@@ -2457,20 +2388,13 @@ _podman_restart() {
_podman_rm() {
local boolean_options="
- --all
- -a
+ --all -a
--cidfile
- --force
- -f
- --help
- -h
- --ignore
- -i
- --latest
- -l
- --storage
- --volumes
- -v
+ --force -f
+ --help -h
+ --ignore -i
+ --latest -l
+ --volumes -v
"
local options_with_args="
@@ -2490,12 +2414,9 @@ _podman_rm() {
_podman_rmi() {
local boolean_options="
- --all
- -a
- --force
- -f
- --help
- -h
+ --all -a
+ --force -f
+ --help -h
"
case "$cur" in
@@ -2510,13 +2431,11 @@ _podman_rmi() {
_podman_stats() {
local boolean_options="
- --all
- -a
- --help
- -h
- --no-stream
+ --all -a
--format
+ --help -h
--no-reset
+ --no-stream
"
case "$cur" in
@@ -2619,10 +2538,8 @@ _podman_save() {
"
local boolean_options="
--compress
- --help
- -h
- -q
- --quiet
+ --help -h
+ --quiet -q
"
case "$cur" in
@@ -2659,12 +2576,9 @@ _podman_port() {
local options_with_args="
"
local boolean_options="
- --all
- -a
- --help
- -h
- -l
- --latest
+ --all -a
+ --help -h
+ --latest -l
"
case "$cur" in
-*)
@@ -2690,14 +2604,14 @@ _podman_ps() {
"
local boolean_options="
--all -a
+ --external
--help -h
--latest -l
+ --namespace --ns
--no-trunc
--pod -p
--quiet -q
--size -s
- --storage
- --namespace --ns
--sync
"
_complete_ "$options_with_args" "$boolean_options"
@@ -2730,14 +2644,10 @@ _podman_start() {
"
local boolean_options="
- --attach
- -a
- -h
- --help
- -i
- --interactive
- --latest
- -l
+ --attach -a
+ --help -h
+ --interactive -i
+ --latest -l
--sig-proxy
"
case "$cur" in
@@ -2754,15 +2664,11 @@ _podman_stop() {
--time -t
"
local boolean_options="
- --all
- -a
+ --all -a
--cidfile
- -h
- --help
- --ignore
- -i
- --latest
- -l
+ --help -h
+ --ignore -i
+ --latest -l
"
case "$cur" in
-*)
@@ -2807,12 +2713,9 @@ _podman_varlink() {
_podman_wait() {
local options_with_args=""
local boolean_options="
- --help
- -h
- -i
- -l
- --interval
- --latest
+ --help -h
+ --interval -i
+ --latest -l
"
case "$cur" in
-*)
@@ -2846,19 +2749,16 @@ _podman_load() {
--input -i
"
local boolean_options="
- --help
- -h
- --quiet
- -q
+ --help -h
+ --quiet -q
"
_complete_ "$options_with_args" "$boolean_options"
}
_podman_cp() {
local boolean_options="
- --help
- -h
--extract
+ --help -h
--pause
"
_complete_ "$boolean_options"
@@ -2866,12 +2766,10 @@ _podman_cp() {
_podman_login() {
local options_with_args="
- --username
- -u
- --password
- -p
--authfile
--get-login
+ --password -p
+ --username -u
"
local boolean_options="
--help
@@ -2979,12 +2877,10 @@ _podman_play_kube() {
"
local boolean_options="
- -h
- --help
- --quiet
- -q
- --tls-verify
+ --help -h
+ --quiet -q
--seccomp-profile-root
+ --tls-verify
"
case "$cur" in
@@ -2999,10 +2895,9 @@ _podman_play_kube() {
_podman_events() {
local options_with_args="
- --help
- --h
--filter
--format
+ --help -h
--since
--until
"
@@ -3023,10 +2918,8 @@ _podman_container_runlabel() {
local boolean_options="
--display
- --help
- -h
- -q
- --quiet
+ --help -h
+ --quiet -q
--replace
--tls-verify
"
@@ -3044,8 +2937,7 @@ _podman_container_runlabel() {
_podman_image_sign() {
local options_with_args="
--cert-dir
- -d
- --directory
+ --directory -d
--sign-by
"
local boolean_options="
@@ -3065,9 +2957,8 @@ _podman_image_sign() {
_podman_image_trust_set() {
echo hello
local options_with_args="
- -f
- --type
- --pubkeysfile
+ --pubkeysfile -f
+ --type -t
"
local boolean_options="
--help
@@ -3087,10 +2978,8 @@ _podman_image_trust_show() {
local options_with_args="
"
local boolean_options="
- --help
- -h
- -j
- --json
+ --help -h
+ --json -j
--raw
"
case "$cur" in
@@ -3133,10 +3022,8 @@ _podman_images_prune() {
"
local boolean_options="
- -a
- --all
- -h
- --help
+ --all -a
+ --help -h
"
case "$cur" in
-*)
@@ -3151,10 +3038,8 @@ _podman_container_prune() {
"
local boolean_options="
- -f
- --force
- -h
- --help
+ --force -f
+ --help -h
"
case "$cur" in
-*)
@@ -3168,7 +3053,10 @@ _podman_container_exists() {
"
local boolean_options="
- "
+ --external
+ --help -h
+ "
+
case "$cur" in
-*)
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
@@ -3221,8 +3109,7 @@ _podman_pod_create() {
"
local boolean_options="
- --help
- -h
+ --help -h
--infra
--replace
"
@@ -3234,14 +3121,10 @@ _podman_pod_kill() {
"
local boolean_options="
- --all
- -a
- --help
- -h
- --signal
- -s
- --latest
- -l
+ --all -a
+ --help -h
+ --latest -l
+ --signal -s
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
@@ -3256,8 +3139,7 @@ _podman_pod_kill() {
__podman_pod_ps() {
local options_with_args="
- -f
- --filter
+ --filter -f
--format
--sort
"
@@ -3267,14 +3149,11 @@ __podman_pod_ps() {
--ctr-ids
--ctr-names
--ctr-status
- --help
- -h
- -q
- --quiet
- --no-trunc
+ --help -h
--labels
- -l
- --latest
+ --latest -l
+ --no-trunc
+ --quiet -q
"
_complete_ "$options_with_args" "$boolean_options"
}
@@ -3312,12 +3191,9 @@ _podman_pod_restart() {
"
local boolean_options="
- --all
- -a
- --help
- -h
- --latest
- -l
+ --all -a
+ --help -h
+ --latest -l
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
@@ -3336,16 +3212,11 @@ _podman_pod_rm() {
"
local boolean_options="
- -a
- --all
- --help
- -h
- --ignore
- -i
- -f
- --force
- --latest
- -l
+ --all -a
+ --force -f
+ --help -h
+ --ignore -i
+ --latest -l
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
@@ -3364,12 +3235,9 @@ _podman_pod_start() {
"
local boolean_options="
- --all
- -a
- --help
- -h
- --latest
- -l
+ --all -a
+ --help -h
+ --latest -l
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
@@ -3384,21 +3252,16 @@ _podman_pod_start() {
_podman_pod_stop() {
local options_with_args="
- -t
- --time
--pod-id-file
+ --time -t
"
local boolean_options="
- --all
- -a
+ --all -a
--cleanup
- --help
- --ignore
- -i
- -h
- --latest
- -l
+ --help -h
+ --ignore -i
+ --latest -l
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
@@ -3416,12 +3279,9 @@ _podman_pod_pause() {
"
local boolean_options="
- --all
- -a
- --help
- -h
- --latest
- -l
+ --all -a
+ --help -h
+ --latest -l
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
@@ -3439,12 +3299,9 @@ _podman_pod_unpause() {
"
local boolean_options="
- --all
- -a
- --help
- -h
- --latest
- -l
+ --all -a
+ --help -h
+ --latest -l
"
_complete_ "$options_with_args" "$boolean_options"
case "$cur" in
@@ -3459,10 +3316,8 @@ _podman_pod_unpause() {
_podman_pod_inspect() {
local options_with_args="
- --format
- -f
- --latest
- -l
+ --format -f
+ --latest -l
"
_complete_ "$options_with_args"
@@ -3476,6 +3331,7 @@ _podman_pod() {
"
subcommands="
create
+ inspect
kill
pause
ps
@@ -3486,7 +3342,6 @@ _podman_pod() {
stop
top
unpause
- inspect
"
local aliases="
list
@@ -3507,10 +3362,8 @@ _podman_pod() {
_podman_volume_create() {
local options_with_args="
--driver
- --label
- -l
- --opt
- -o
+ --label -l
+ --opt -o
"
local boolean_options="
@@ -3524,15 +3377,12 @@ _podman_volume_create() {
_podman_volume_ls() {
local options_with_args="
--filter
- --format
- -f
+ --format -f
"
local boolean_options="
- --help
- -h
- --quiet
- -q
+ --help -h
+ --quiet -q
"
_complete_ "$options_with_args" "$boolean_options"
@@ -3545,10 +3395,8 @@ _podman_volume_inspect() {
"
local boolean_options="
- --all
- -a
- --help
- -h
+ --all -a
+ --help -h
"
_complete_ "$options_with_args" "$boolean_options"
@@ -3566,12 +3414,9 @@ _podman_volume_rm() {
local options_with_args=""
local boolean_options="
- --all
- -a
- --force
- -f
- --help
- -h
+ --all -a
+ --force -f
+ --help -h
"
_complete_ "$options_with_args" "$boolean_options"
@@ -3589,10 +3434,8 @@ _podman_volume_prune() {
local options_with_args=""
local boolean_options="
- --force
- -f
- --help
- -h
+ --force -f
+ --help -h
"
_complete_ "$options_with_args" "$boolean_options"
@@ -3600,15 +3443,14 @@ _podman_volume_prune() {
_podman_volume() {
local boolean_options="
- --help
- -h
+ --help -h
"
subcommands="
create
inspect
ls
- rm
prune
+ rm
"
local aliases="
list
@@ -3639,19 +3481,17 @@ _podman_podman() {
--network-cmd-path
--root
--runroot
+ --runtime
--storage-driver
--storage-opt
--tmpdir
- --runtime
--url
"
local boolean_options="
- --help
+ --help -h
+ --remote -r
--syslog
- --version
- -h
- -r, --remote
- -v
+ --version -v
"
commands="
attach
@@ -3682,12 +3522,12 @@ _podman_podman() {
mount
network
pause
+ play
pod
port
ps
pull
push
- play
restart
rm
rmi
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 1b992711f..3135a5e65 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -52,7 +52,7 @@ case "$CG_FS_TYPE" in
if [[ "$OS_RELEASE_ID" == "ubuntu" ]]; then
echo "export OCI_RUNTIME=/usr/lib/cri-o-runc/sbin/runc" >> /etc/environment
else
- echo "export OCI_RUNTIME=/usr/bin/runc" >> /etc/environment
+ echo "export OCI_RUNTIME=runc" >> /etc/environment
fi
fi
;;
@@ -61,7 +61,7 @@ case "$CG_FS_TYPE" in
# This is necessary since we've built/installed from source,
# which uses runc as the default.
warn "Forcing testing with crun instead of runc"
- echo "export OCI_RUNTIME=/usr/bin/crun" >> /etc/environment
+ echo "export OCI_RUNTIME=crun" >> /etc/environment
fi
;;
*) die_unknown CG_FS_TYPE
diff --git a/docs/source/markdown/podman-container-exists.1.md b/docs/source/markdown/podman-container-exists.1.md
index d24df2fc8..d81a38515 100644
--- a/docs/source/markdown/podman-container-exists.1.md
+++ b/docs/source/markdown/podman-container-exists.1.md
@@ -4,7 +4,7 @@
podman-container-exists - Check if a container exists in local storage
## SYNOPSIS
-**podman container exists** *container*
+**podman container exists** [*options*] *container*
## DESCRIPTION
**podman container exists** checks if a container exists in local storage. The **ID** or **Name**
@@ -14,17 +14,19 @@ was an issue accessing the local storage.
## OPTIONS
+**--external**=*true|false*
+Check for external containers as well as Podman containers. These external containers are generally created via other container technology such as Buildah or CRI-O.
+
**-h**, **--help**
Print usage statement
-## Examples
+## EXAMPLES
Check if an container called `webclient` exists in local storage (the container does actually exist).
```
$ podman container exists webclient
$ echo $?
0
-$
```
Check if an container called `webbackend` exists in local storage (the container does not actually exist).
@@ -32,7 +34,13 @@ Check if an container called `webbackend` exists in local storage (the container
$ podman container exists webbackend
$ echo $?
1
-$
+```
+
+Check if an container called `ubi8-working-container` created via Buildah exists in local storage (the container does not actually exist).
+```
+$ podman container exists --external ubi8-working-container
+$ echo $?
+1
```
## SEE ALSO
diff --git a/docs/source/markdown/podman-container-prune.1.md b/docs/source/markdown/podman-container-prune.1.md
index 8c05eeafe..d56a1e7f5 100644
--- a/docs/source/markdown/podman-container-prune.1.md
+++ b/docs/source/markdown/podman-container-prune.1.md
@@ -23,7 +23,7 @@ Do not provide an interactive prompt for container removal.
Print usage statement
-## Examples
+## EXAMPLES
Remove all stopped containers from local storage
```
diff --git a/docs/source/markdown/podman-container-runlabel.1.md b/docs/source/markdown/podman-container-runlabel.1.md
index 2abbf0b7f..f56fc7d7b 100644
--- a/docs/source/markdown/podman-container-runlabel.1.md
+++ b/docs/source/markdown/podman-container-runlabel.1.md
@@ -40,7 +40,7 @@ is used.
Any additional arguments will be appended to the command.
-## OPTIONS:
+## OPTIONS
**--authfile**=*path*
Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
@@ -87,7 +87,7 @@ Require HTTPS and verify certificates when contacting registries (default: true)
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf (Not available for remote commands)
-## Examples
+## EXAMPLES
Execute the run label of an image called foobar.
```
diff --git a/docs/source/markdown/podman-generate-kube.1.md b/docs/source/markdown/podman-generate-kube.1.md
index f4b4cd482..47d6e0445 100644
--- a/docs/source/markdown/podman-generate-kube.1.md
+++ b/docs/source/markdown/podman-generate-kube.1.md
@@ -12,7 +12,7 @@ of a pod or container name or ID.
Note that the generated Kubernetes YAML file can be used to re-run the deployment via podman-play-kube(1).
-## OPTIONS:
+## OPTIONS
**--filename**, **-f**=**filename**
@@ -23,7 +23,7 @@ Output to the given file, instead of STDOUT. If the file already exists, `genera
Generate a Kubernetes service object in addition to the Pods. Used to generate a Service specification for the corresponding Pod output. In particular, if the object has portmap bindings, the service specification will include a NodePort declaration to expose the service. A
random port is assigned by Podman in the specification.
-## Examples
+## EXAMPLES
Create Kubernetes Pod YAML for a container called `some-mariadb` .
```
diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md
index af8ea3c39..f95c57399 100644
--- a/docs/source/markdown/podman-generate-systemd.1.md
+++ b/docs/source/markdown/podman-generate-systemd.1.md
@@ -12,7 +12,7 @@ By default, the command will print the content of the unit files to stdout.
_Note: If you use this command with the remote client, you would still have to place the generated units on the remote system._
-## OPTIONS:
+## OPTIONS
**--files**, **-f**
@@ -53,7 +53,7 @@ Set the systemd unit name prefix for pods. The default is *pod*.
Set the systemd unit name separator between the name/id of a container/pod and the prefix. The default is *-*.
-## Examples
+## EXAMPLES
### Generate and print a systemd unit file for a container
diff --git a/docs/source/markdown/podman-image-exists.1.md b/docs/source/markdown/podman-image-exists.1.md
index 59f2145cc..877324cd1 100644
--- a/docs/source/markdown/podman-image-exists.1.md
+++ b/docs/source/markdown/podman-image-exists.1.md
@@ -18,7 +18,7 @@ was an issue accessing the local storage.
Print usage statement
-## Examples
+## EXAMPLES
Check if an image called `webclient` exists in local storage (the image does actually exist).
```
diff --git a/docs/source/markdown/podman-image-prune.1.md b/docs/source/markdown/podman-image-prune.1.md
index cf9e50366..d4fbe45c3 100644
--- a/docs/source/markdown/podman-image-prune.1.md
+++ b/docs/source/markdown/podman-image-prune.1.md
@@ -30,7 +30,7 @@ Do not provide an interactive prompt for container removal.
Print usage statement
-## Examples ##
+## EXAMPLES
Remove all dangling images from local storage
```
diff --git a/docs/source/markdown/podman-play-kube.1.md b/docs/source/markdown/podman-play-kube.1.md
index 519b153f4..00ee7c1df 100644
--- a/docs/source/markdown/podman-play-kube.1.md
+++ b/docs/source/markdown/podman-play-kube.1.md
@@ -15,7 +15,7 @@ Ideally the input file would be one created by Podman (see podman-generate-kube(
Note: HostPath volume types created by play kube will be given an SELinux private label (Z)
-## OPTIONS:
+## OPTIONS
**--authfile**=*path*
@@ -64,7 +64,7 @@ TLS verification will be used unless the target registry is listed as an insecur
Print usage statement
-## Examples
+## EXAMPLES
Recreate the pod and containers as described in a file called `demo.yml`
```
diff --git a/docs/source/markdown/podman-pod-exists.1.md b/docs/source/markdown/podman-pod-exists.1.md
index cf2852934..4c8714341 100644
--- a/docs/source/markdown/podman-pod-exists.1.md
+++ b/docs/source/markdown/podman-pod-exists.1.md
@@ -12,7 +12,7 @@ of the pod may be used as input. Podman will return an exit code
of `0` when the pod is found. A `1` will be returned otherwise. An exit code of `125` indicates there
was an issue accessing the local storage.
-## Examples ##
+## EXAMPLES
Check if a pod called `web` exists in local storage (the pod does actually exist).
```
diff --git a/docs/source/markdown/podman-ps.1.md b/docs/source/markdown/podman-ps.1.md
index 58d3358e5..90f147222 100644
--- a/docs/source/markdown/podman-ps.1.md
+++ b/docs/source/markdown/podman-ps.1.md
@@ -34,23 +34,33 @@ all the containers information. By default it lists:
Show all the containers created by Podman, default is only running containers.
-Note: Podman shares containers storage with other tools such as Buildah and CRI-O. In some cases these `external` containers might also exist in the same storage. Use the `--storage` option to see these external containers. External containers show the 'storage' status.
+Note: Podman shares containers storage with other tools such as Buildah and CRI-O. In some cases these `external` containers might also exist in the same storage. Use the `--external` option to see these external containers. External containers show the 'storage' status.
-**--pod**, **-p**
-
-Display the pods the containers are associated with
-
-**--storage**
+**--external**
Display external containers that are not controlled by Podman but are stored in containers storage. These external containers are generally created via other container technology such as Buildah or CRI-O and may depend on the same container images that Podman is also using. External containers are denoted with either a 'buildah' or 'storage' in the COMMAND and STATUS column of the ps output. Only used with the --all option.
-**--no-trunc**
+**--filter**, **-f**
-Display the extended information
+Filter what containers are shown in the output.
+Multiple filters can be given with multiple uses of the --filter flag.
+If multiple filters are given, only containers which match all of the given filters will be shown.
+Results will be drawn from all containers, regardless of whether --all was given.
-**--quiet**, **-q**
+Valid filters are listed below:
-Print the numeric IDs of the containers only
+| **Filter** | **Description** |
+| --------------- | -------------------------------------------------------------------------------- |
+| id | [ID] Container's ID |
+| name | [Name] Container's name |
+| label | [Key] or [Key=Value] Label assigned to a container |
+| exited | [Int] Container's exit code |
+| status | [Status] Container's status: 'created', 'exited', 'paused', 'running', 'unknown' |
+| ancestor | [ImageName] Image or descendant used to create container |
+| before | [ID] or [Name] Containers created before this container |
+| since | [ID] or [Name] Containers created since this container |
+| volume | [VolumeName] or [MountpointDestination] Volume mounted in container |
+| health | [Status] healthy or unhealthy |
**--format**=*format*
@@ -74,15 +84,9 @@ Valid placeholders for the Go template are listed below:
| .Labels | All the labels assigned to the container |
| .Mounts | Volumes mounted in the container |
-**--sort**
-
-Sort by command, created, id, image, names, runningfor, size, or status",
-Note: Choosing size will sort by size of rootFs, not alphabetically like the rest of the options
-Default: created
-
-**--size**, **-s**
+**--help**, **-h**
-Display the total file size
+Print usage statement
**--last**, **-n**
@@ -98,31 +102,27 @@ The latest option is not supported on the remote client.
Display namespace information
-**--filter**, **-f**
+**--no-trunc**
-Filter what containers are shown in the output.
-Multiple filters can be given with multiple uses of the --filter flag.
-If multiple filters are given, only containers which match all of the given filters will be shown.
-Results will be drawn from all containers, regardless of whether --all was given.
+Display the extended information
-Valid filters are listed below:
+**--pod**, **-p**
-| **Filter** | **Description** |
-| --------------- | -------------------------------------------------------------------------------- |
-| id | [ID] Container's ID |
-| name | [Name] Container's name |
-| label | [Key] or [Key=Value] Label assigned to a container |
-| exited | [Int] Container's exit code |
-| status | [Status] Container's status: 'created', 'exited', 'paused', 'running', 'unknown' |
-| ancestor | [ImageName] Image or descendant used to create container |
-| before | [ID] or [Name] Containers created before this container |
-| since | [ID] or [Name] Containers created since this container |
-| volume | [VolumeName] or [MountpointDestination] Volume mounted in container |
-| health | [Status] healthy or unhealthy |
+Display the pods the containers are associated with
-**--help**, **-h**
+**--quiet**, **-q**
-Print usage statement
+Print the numeric IDs of the containers only
+
+**--sort**
+
+Sort by command, created, id, image, names, runningfor, size, or status",
+Note: Choosing size will sort by size of rootFs, not alphabetically like the rest of the options
+Default: created
+
+**--size**, **-s**
+
+Display the total file size
**--sync**
@@ -181,7 +181,7 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS
```
```
-$ podman ps --storage -a
+$ podman ps --external -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69ed779d8ef9f redis:alpine "redis-server" 25 hours ago Created 6379/tcp k8s_container1_podsandbox1_redhat.test.crio_redhat-test-crio_1
38a8a78596f9 docker.io/library/busybox:latest buildah 2 hours ago storage busybox-working-container
diff --git a/docs/source/markdown/podman-restart.1.md b/docs/source/markdown/podman-restart.1.md
index 87217f096..127aaa074 100644
--- a/docs/source/markdown/podman-restart.1.md
+++ b/docs/source/markdown/podman-restart.1.md
@@ -30,7 +30,7 @@ Restart all containers that are already in the *running* state.
Timeout to wait before forcibly stopping the container.
-## EXAMPLES ##
+## EXAMPLES
Restart the latest container
```
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index 9be753d26..e195ca314 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -2,7 +2,7 @@ package libpod
import (
"bytes"
- "path/filepath"
+ "os"
"runtime"
"strings"
@@ -400,14 +400,30 @@ func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.
// Handle legacy containers which might use a literal path for
// their OCI runtime name.
runtimeName := ctr.config.OCIRuntime
- if strings.HasPrefix(runtimeName, "/") {
- runtimeName = filepath.Base(runtimeName)
- }
-
ociRuntime, ok := s.runtime.ociRuntimes[runtimeName]
if !ok {
- // Use a MissingRuntime implementation
- ociRuntime = getMissingRuntime(runtimeName, s.runtime)
+ runtimeSet := false
+
+ // If the path starts with a / and exists, make a new
+ // OCI runtime for it using the full path.
+ if strings.HasPrefix(runtimeName, "/") {
+ if stat, err := os.Stat(runtimeName); err == nil && !stat.IsDir() {
+ newOCIRuntime, err := newConmonOCIRuntime(runtimeName, []string{runtimeName}, s.runtime.conmonPath, s.runtime.runtimeFlags, s.runtime.config)
+ if err == nil {
+ // The runtime lock should
+ // protect against concurrent
+ // modification of the map.
+ ociRuntime = newOCIRuntime
+ s.runtime.ociRuntimes[runtimeName] = ociRuntime
+ runtimeSet = true
+ }
+ }
+ }
+
+ if !runtimeSet {
+ // Use a MissingRuntime implementation
+ ociRuntime = getMissingRuntime(runtimeName, s.runtime)
+ }
}
ctr.ociRuntime = ociRuntime
}
diff --git a/libpod/diff.go b/libpod/diff.go
index 5335d701c..43f4d2e96 100644
--- a/libpod/diff.go
+++ b/libpod/diff.go
@@ -62,18 +62,22 @@ func (r *Runtime) ApplyDiffTarStream(to string, diff io.Reader) error {
func (r *Runtime) getLayerID(id string) (string, error) {
var toLayer string
toImage, err := r.imageRuntime.NewFromLocal(id)
+ if err == nil {
+ return toImage.TopLayer(), nil
+ }
+
+ targetID, err := r.store.Lookup(id)
if err != nil {
- toCtr, err := r.store.Container(id)
+ targetID = id
+ }
+ toCtr, err := r.store.Container(targetID)
+ if err != nil {
+ toLayer, err = layers.FullID(r.store, targetID)
if err != nil {
- toLayer, err = layers.FullID(r.store, id)
- if err != nil {
- return "", errors.Errorf("layer, image, or container %s does not exist", id)
- }
- } else {
- toLayer = toCtr.LayerID
+ return "", errors.Errorf("layer, image, or container %s does not exist", id)
}
} else {
- toLayer = toImage.TopLayer()
+ toLayer = toCtr.LayerID
}
return toLayer, nil
}
diff --git a/libpod/network/create.go b/libpod/network/create.go
index a9ed4c4ef..bf11631bf 100644
--- a/libpod/network/create.go
+++ b/libpod/network/create.go
@@ -10,6 +10,7 @@ import (
"github.com/containernetworking/cni/pkg/version"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
)
@@ -131,8 +132,9 @@ func createBridge(r *libpod.Runtime, name string, options entities.NetworkCreate
plugins = append(plugins, bridge)
plugins = append(plugins, NewPortMapPlugin())
plugins = append(plugins, NewFirewallPlugin())
- // if we find the dnsname plugin, we add configuration for it
- if HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) && !options.DisableDNS {
+ // if we find the dnsname plugin or are rootless, we add configuration for it
+ // the rootless-cni-infra container has the dnsname plugin always installed
+ if (HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) || rootless.IsRootless()) && !options.DisableDNS {
// Note: in the future we might like to allow for dynamic domain names
plugins = append(plugins, NewDNSNamePlugin(DefaultPodmanDomainName))
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 7da8b181f..792492db6 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/libpod/lock"
+ "github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/registries"
"github.com/containers/podman/v2/pkg/rootless"
@@ -174,9 +175,21 @@ func newRuntimeFromConfig(ctx context.Context, conf *config.Config, options ...R
}
}
+ if err := shutdown.Start(); err != nil {
+ return nil, errors.Wrapf(err, "error starting shutdown signal handler")
+ }
+
if err := makeRuntime(ctx, runtime); err != nil {
return nil, err
}
+
+ if err := shutdown.Register("libpod", func(sig os.Signal) error {
+ os.Exit(1)
+ return nil
+ }); err != nil {
+ logrus.Errorf("Error registering shutdown handler for libpod: %v", err)
+ }
+
return runtime, nil
}
@@ -383,14 +396,12 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
// If the string starts with / it's a path to a runtime
// executable.
if strings.HasPrefix(runtime.config.Engine.OCIRuntime, "/") {
- name := filepath.Base(runtime.config.Engine.OCIRuntime)
-
- ociRuntime, err := newConmonOCIRuntime(name, []string{runtime.config.Engine.OCIRuntime}, runtime.conmonPath, runtime.runtimeFlags, runtime.config)
+ ociRuntime, err := newConmonOCIRuntime(runtime.config.Engine.OCIRuntime, []string{runtime.config.Engine.OCIRuntime}, runtime.conmonPath, runtime.runtimeFlags, runtime.config)
if err != nil {
return err
}
- runtime.ociRuntimes[name] = ociRuntime
+ runtime.ociRuntimes[runtime.config.Engine.OCIRuntime] = ociRuntime
runtime.defaultOCIRuntime = ociRuntime
} else {
ociRuntime, ok := runtime.ociRuntimes[runtime.config.Engine.OCIRuntime]
diff --git a/libpod/runtime_cstorage.go b/libpod/runtime_cstorage.go
index 03eebeefc..61fdd42d3 100644
--- a/libpod/runtime_cstorage.go
+++ b/libpod/runtime_cstorage.go
@@ -52,6 +52,10 @@ func (r *Runtime) ListStorageContainers() ([]*StorageContainer, error) {
return finalCtrs, nil
}
+func (r *Runtime) StorageContainer(idOrName string) (*storage.Container, error) {
+ return r.store.Container(idOrName)
+}
+
// RemoveStorageContainer removes a container from c/storage.
// The container WILL NOT be removed if it exists in libpod.
// Accepts ID or full name of container.
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 51b4c5f03..de73a9ff3 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
+ "github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
@@ -149,6 +150,10 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
return nil, err
}
+ // Inhibit shutdown until creation succeeds
+ shutdown.Inhibit()
+ defer shutdown.Uninhibit()
+
// Allocate a lock for the container
lock, err := r.lockManager.AllocateLock()
if err != nil {
diff --git a/libpod/shutdown/handler.go b/libpod/shutdown/handler.go
new file mode 100644
index 000000000..87538dec9
--- /dev/null
+++ b/libpod/shutdown/handler.go
@@ -0,0 +1,131 @@
+package shutdown
+
+import (
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+var (
+ stopped bool
+ sigChan chan os.Signal
+ cancelChan chan bool
+ // Definitions of all on-shutdown handlers
+ handlers map[string]func(os.Signal) error
+ // Ordering that on-shutdown handlers will be invoked.
+ handlerOrder []string
+ shutdownInhibit sync.RWMutex
+)
+
+// Start begins handling SIGTERM and SIGINT and will run the given on-signal
+// handlers when one is called. This can be cancelled by calling Stop().
+func Start() error {
+ if sigChan != nil {
+ // Already running, do nothing.
+ return nil
+ }
+
+ sigChan = make(chan os.Signal, 1)
+ cancelChan = make(chan bool, 1)
+ stopped = false
+
+ signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
+
+ go func() {
+ select {
+ case <-cancelChan:
+ signal.Stop(sigChan)
+ close(sigChan)
+ close(cancelChan)
+ stopped = true
+ return
+ case sig := <-sigChan:
+ logrus.Infof("Received shutdown signal %v, terminating!", sig)
+ shutdownInhibit.Lock()
+ for _, name := range handlerOrder {
+ handler, ok := handlers[name]
+ if !ok {
+ logrus.Errorf("Shutdown handler %s definition not found!", name)
+ continue
+ }
+ logrus.Infof("Invoking shutdown handler %s", name)
+ if err := handler(sig); err != nil {
+ logrus.Errorf("Error running shutdown handler %s: %v", name, err)
+ }
+ }
+ shutdownInhibit.Unlock()
+ return
+ }
+ }()
+
+ return nil
+}
+
+// Stop the shutdown signal handler.
+func Stop() error {
+ if cancelChan == nil {
+ return errors.New("shutdown signal handler has not yet been started")
+ }
+ if stopped {
+ return nil
+ }
+
+ cancelChan <- true
+
+ return nil
+}
+
+// Temporarily inhibit signals from shutting down Libpod.
+func Inhibit() {
+ shutdownInhibit.RLock()
+}
+
+// Stop inhibiting signals from shutting down Libpod.
+func Uninhibit() {
+ shutdownInhibit.RUnlock()
+}
+
+// Register registers a function that will be executed when Podman is terminated
+// by a signal. Handlers are invoked LIFO - the last handler registered is the
+// first run.
+func Register(name string, handler func(os.Signal) error) error {
+ if handlers == nil {
+ handlers = make(map[string]func(os.Signal) error)
+ }
+
+ if _, ok := handlers[name]; ok {
+ return errors.Errorf("handler with name %s already exists", name)
+ }
+
+ handlers[name] = handler
+ handlerOrder = append([]string{name}, handlerOrder...)
+
+ return nil
+}
+
+// Unregister un-registers a given shutdown handler.
+func Unregister(name string) error {
+ if handlers == nil {
+ return nil
+ }
+
+ if _, ok := handlers[name]; !ok {
+ return nil
+ }
+
+ delete(handlers, name)
+
+ newOrder := []string{}
+ for _, checkName := range handlerOrder {
+ if checkName != name {
+ newOrder = append(newOrder, checkName)
+ }
+ }
+ handlerOrder = newOrder
+
+ return nil
+}
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 4ce31cc83..8a0b3c922 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -238,7 +238,7 @@ func makeCreateConfig(ctx context.Context, containerConfig *config.Config, input
Pod: "", // podman
PodmanPath: "", // podman
Quiet: false, // front-end only
- Resources: createconfig.CreateResourceConfig{},
+ Resources: createconfig.CreateResourceConfig{MemorySwappiness: -1},
RestartPolicy: input.HostConfig.RestartPolicy.Name,
Rm: input.HostConfig.AutoRemove,
StopSignal: stopSignal,
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 7dde51102..7e6481321 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers/compat"
"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"
@@ -18,9 +19,30 @@ import (
)
func ContainerExists(w http.ResponseWriter, r *http.Request) {
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+
name := utils.GetName(r)
- _, err := runtime.LookupContainer(name)
+ query := struct {
+ External bool `schema:"external"`
+ }{
+ // override any golang type defaults
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ options := entities.ContainerExistsOptions{
+ External: query.External,
+ }
+
+ report, err := containerEngine.ContainerExists(r.Context(), name, options)
if err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
utils.ContainerNotFound(w, name, err)
@@ -30,7 +52,11 @@ func ContainerExists(w http.ResponseWriter, r *http.Request) {
return
}
- utils.WriteResponse(w, http.StatusNoContent, "")
+ if report.Value {
+ utils.WriteResponse(w, http.StatusNoContent, "")
+ } else {
+ utils.ContainerNotFound(w, name, define.ErrNoSuchCtr)
+ }
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 355a46fb7..64008767b 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -7,7 +7,6 @@ import (
"net"
"net/http"
"os"
- "os/signal"
goRuntime "runtime"
"strings"
"sync"
@@ -15,6 +14,7 @@ import (
"time"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/server/idle"
"github.com/coreos/go-systemd/v22/activation"
@@ -180,8 +180,17 @@ func setupSystemd() {
// Serve starts responding to HTTP requests.
func (s *APIServer) Serve() error {
setupSystemd()
- sigChan := make(chan os.Signal, 1)
- signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
+
+ // Start the shutdown signal handler.
+ if err := shutdown.Start(); err != nil {
+ return err
+ }
+ if err := shutdown.Register("server", func(sig os.Signal) error {
+ return s.Shutdown()
+ }); err != nil {
+ return err
+ }
+
errChan := make(chan error, 1)
go func() {
@@ -217,14 +226,7 @@ func (s *APIServer) Serve() error {
errChan <- nil
}()
- select {
- case err := <-errChan:
- return err
- case sig := <-sigChan:
- logrus.Infof("APIServer terminated by signal %v", sig)
- }
-
- return nil
+ return <-errChan
}
// Shutdown is a clean shutdown waiting on existing clients
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 3bd85fbae..7b321af93 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -19,6 +19,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings"
sig "github.com/containers/podman/v2/pkg/signal"
"github.com/containers/podman/v2/utils"
+ "github.com/moby/term"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
@@ -60,8 +61,14 @@ func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stre
}
params := url.Values{}
+ detachKeysInBytes := []byte{}
if detachKeys != nil {
params.Add("detachKeys", *detachKeys)
+
+ detachKeysInBytes, err = term.ToBytes(*detachKeys)
+ if err != nil {
+ return errors.Wrapf(err, "invalid detach keys")
+ }
}
if logs != nil {
params.Add("logs", fmt.Sprintf("%t", *logs))
@@ -141,27 +148,51 @@ func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stre
attachReady <- true
}
+ stdoutChan := make(chan error)
+ stdinChan := make(chan error)
+
if isSet.stdin {
go func() {
logrus.Debugf("Copying STDIN to socket")
- _, err := utils.CopyDetachable(socket, stdin, []byte{})
- if err != nil {
+
+ _, err := utils.CopyDetachable(socket, stdin, detachKeysInBytes)
+
+ if err != nil && err != define.ErrDetach {
logrus.Error("failed to write input to service: " + err.Error())
}
+ stdinChan <- err
}()
}
buffer := make([]byte, 1024)
if ctnr.Config.Tty {
- logrus.Debugf("Copying STDOUT of container in terminal mode")
+ go func() {
+ logrus.Debugf("Copying STDOUT of container in terminal mode")
- if !isSet.stdout {
- return fmt.Errorf("container %q requires stdout to be set", ctnr.ID)
- }
- // If not multiplex'ed, read from server and write to stdout
- _, err := io.Copy(stdout, socket)
- if err != nil {
- return err
+ if !isSet.stdout {
+ stdoutChan <- fmt.Errorf("container %q requires stdout to be set", ctnr.ID)
+ }
+ // If not multiplex'ed, read from server and write to stdout
+ _, err := io.Copy(stdout, socket)
+
+ stdoutChan <- err
+ }()
+
+ for {
+ select {
+ case err := <-stdoutChan:
+ if err != nil {
+ return err
+ }
+
+ return nil
+ case err := <-stdinChan:
+ if err != nil {
+ return err
+ }
+
+ return nil
+ }
}
} else {
logrus.Debugf("Copying standard streams of container in non-terminal mode")
@@ -205,7 +236,6 @@ func Attach(ctx context.Context, nameOrID string, detachKeys *string, logs, stre
}
}
}
- return nil
}
// DemuxHeader reads header for stream from server multiplexed stdin/stdout/stderr/2nd error channel
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 708ad06cb..b5cd2128b 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -322,12 +322,14 @@ func Wait(ctx context.Context, nameOrID string, condition *define.ContainerStatu
// Exists is a quick, light-weight way to determine if a given container
// exists in local storage. The nameOrID can be a container name
// or a partial/full ID.
-func Exists(ctx context.Context, nameOrID string) (bool, error) {
+func Exists(ctx context.Context, nameOrID string, external bool) (bool, error) {
conn, err := bindings.GetClient(ctx)
if err != nil {
return false, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", nil, nil, nameOrID)
+ params := url.Values{}
+ params.Set("external", strconv.FormatBool(external))
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", params, nil, nameOrID)
if err != nil {
return false, err
}
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index 408b4769d..0fb677768 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -405,7 +405,7 @@ var _ = Describe("Podman containers ", func() {
It("podman bogus container does not exist in local storage", func() {
// Bogus container existence check should fail
- containerExists, err := containers.Exists(bt.conn, "foobar")
+ containerExists, err := containers.Exists(bt.conn, "foobar", false)
Expect(err).To(BeNil())
Expect(containerExists).To(BeFalse())
})
@@ -415,7 +415,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- containerExists, err := containers.Exists(bt.conn, name)
+ containerExists, err := containers.Exists(bt.conn, name, false)
Expect(err).To(BeNil())
Expect(containerExists).To(BeTrue())
})
@@ -425,7 +425,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- containerExists, err := containers.Exists(bt.conn, cid)
+ containerExists, err := containers.Exists(bt.conn, cid, false)
Expect(err).To(BeNil())
Expect(containerExists).To(BeTrue())
})
@@ -435,7 +435,7 @@ var _ = Describe("Podman containers ", func() {
var name = "top"
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
Expect(err).To(BeNil())
- containerExists, err := containers.Exists(bt.conn, cid[0:12])
+ containerExists, err := containers.Exists(bt.conn, cid[0:12], false)
Expect(err).To(BeNil())
Expect(containerExists).To(BeTrue())
})
@@ -455,7 +455,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
err = containers.Kill(bt.conn, name, "SIGINT")
Expect(err).To(BeNil())
- _, err = containers.Exists(bt.conn, name)
+ _, err = containers.Exists(bt.conn, name, false)
Expect(err).To(BeNil())
})
@@ -466,7 +466,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).To(BeNil())
err = containers.Kill(bt.conn, cid, "SIGTERM")
Expect(err).To(BeNil())
- _, err = containers.Exists(bt.conn, cid)
+ _, err = containers.Exists(bt.conn, cid, false)
Expect(err).To(BeNil())
})
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 3b6dd106f..46b169284 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -246,6 +246,11 @@ type ExecOptions struct {
WorkDir string
}
+// ContainerExistsOptions describes the cli values to check if a container exists
+type ContainerExistsOptions struct {
+ External bool
+}
+
// ContainerStartOptions describes the val from the
// CLI needed to start a container
type ContainerStartOptions struct {
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 803a59932..a20d3b404 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -21,7 +21,7 @@ type ContainerEngine interface {
ContainerDiff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
ContainerExec(ctx context.Context, nameOrID string, options ExecOptions, streams define.AttachStreams) (int, error)
ContainerExecDetached(ctx context.Context, nameOrID string, options ExecOptions) (string, error)
- ContainerExists(ctx context.Context, nameOrID string) (*BoolReport, error)
+ ContainerExists(ctx context.Context, nameOrID string, options ContainerExistsOptions) (*BoolReport, error)
ContainerExport(ctx context.Context, nameOrID string, options ContainerExportOptions) error
ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error)
ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, []error, error)
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 614fd5fe0..60dbbce6c 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -74,11 +74,19 @@ func getContainersByContext(all, latest bool, names []string, runtime *libpod.Ru
return
}
-// TODO: Should return *entities.ContainerExistsReport, error
-func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+// ContainerExists returns whether the container exists in container storage
+func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
_, err := ic.Libpod.LookupContainer(nameOrID)
- if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
- return nil, err
+ if err != nil {
+ if errors.Cause(err) != define.ErrNoSuchCtr {
+ return nil, err
+ }
+ if options.External {
+ // Check if container exists in storage
+ if _, storageErr := ic.Libpod.StorageContainer(nameOrID); storageErr == nil {
+ err = nil
+ }
+ }
}
return &entities.BoolReport{Value: err == nil}, nil
}
diff --git a/pkg/domain/infra/abi/containers_runlabel.go b/pkg/domain/infra/abi/containers_runlabel.go
index 30a5a55b8..41fdf8f34 100644
--- a/pkg/domain/infra/abi/containers_runlabel.go
+++ b/pkg/domain/infra/abi/containers_runlabel.go
@@ -28,6 +28,9 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
if err != nil {
return err
}
+ if runlabel == "" {
+ return errors.Errorf("cannot find the value of label: %s in image: %s", label, imageRef)
+ }
cmd, env, err := generateRunlabelCommand(runlabel, img, args, options)
if err != nil {
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index a7c66bae6..348570a20 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -341,7 +341,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
named, err := reference.ParseNormalizedNamed(container.Image)
if err != nil {
- return nil, err
+ return nil, errors.Wrapf(err, "Failed to parse image %q", container.Image)
}
// In kube, if the image is tagged with latest, it should always pull
if tagged, isTagged := named.(reference.NamedTagged); isTagged {
diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
index f484e926c..0c586cf5c 100644
--- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go
+++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
@@ -5,12 +5,17 @@ import (
"syscall"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/signal"
"github.com/sirupsen/logrus"
)
// ProxySignals ...
func ProxySignals(ctr *libpod.Container) {
+ // Stop catching the shutdown signals (SIGINT, SIGTERM) - they're going
+ // to the container now.
+ shutdown.Stop()
+
sigBuffer := make(chan os.Signal, 128)
signal.CatchAll(sigBuffer)
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 1bb4e68ac..7913d79cd 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -29,8 +29,8 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
return errors.New("not implemented")
}
-func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
- exists, err := containers.Exists(ic.ClientCxt, nameOrID)
+func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
+ exists, err := containers.Exists(ic.ClientCxt, nameOrID, options.External)
return &entities.BoolReport{Value: exists}, err
}
@@ -500,7 +500,6 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
if err == define.ErrDetach {
// User manually detached
// Exit cleanly immediately
- report.Err = err
reports = append(reports, &report)
return reports, nil
}
@@ -573,6 +572,10 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
// Attach
if err := startAndAttach(ic, con.ID, &opts.DetachKeys, opts.InputStream, opts.OutputStream, opts.ErrorStream); err != nil {
+ if err == define.ErrDetach {
+ return &report, nil
+ }
+
report.ExitCode = define.ExitCode(err)
if opts.Rm {
if rmErr := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); rmErr != nil {
diff --git a/pkg/specgen/generate/ports.go b/pkg/specgen/generate/ports.go
index 7dd50ac0d..5c13c95b2 100644
--- a/pkg/specgen/generate/ports.go
+++ b/pkg/specgen/generate/ports.go
@@ -25,7 +25,12 @@ const (
func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping, map[string]map[string]map[uint16]uint16, map[string]map[string]map[uint16]uint16, error) {
// First, we need to validate the ports passed in the specgen, and then
// convert them into CNI port mappings.
- finalMappings := []ocicni.PortMapping{}
+ type tempMapping struct {
+ mapping ocicni.PortMapping
+ startOfRange bool
+ isInRange bool
+ }
+ tempMappings := []tempMapping{}
// To validate, we need two maps: one for host ports, one for container
// ports.
@@ -153,18 +158,32 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
Protocol: p,
HostIP: port.HostIP,
}
- finalMappings = append(finalMappings, cniPort)
+ tempMappings = append(
+ tempMappings,
+ tempMapping{
+ mapping: cniPort,
+ startOfRange: port.Range > 0 && index == 0,
+ isInRange: port.Range > 0,
+ },
+ )
}
}
}
// Handle any 0 host ports now by setting random container ports.
if postAssignHostPort {
- remadeMappings := make([]ocicni.PortMapping, 0, len(finalMappings))
+ remadeMappings := make([]ocicni.PortMapping, 0, len(tempMappings))
+
+ var (
+ candidate int
+ err error
+ )
// Iterate over all
- for _, p := range finalMappings {
- if p.HostPort != 0 {
+ for _, tmp := range tempMappings {
+ p := tmp.mapping
+
+ if p.HostPort != 0 && !tmp.isInRange {
remadeMappings = append(remadeMappings, p)
continue
}
@@ -192,9 +211,15 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
// Max retries to ensure we don't loop forever.
for i := 0; i < 15; i++ {
- candidate, err := getRandomPort()
- if err != nil {
- return nil, nil, nil, errors.Wrapf(err, "error getting candidate host port for container port %d", p.ContainerPort)
+ // Only get a random candidate for single entries or the start
+ // of a range. Otherwise we just increment the candidate.
+ if !tmp.isInRange || tmp.startOfRange {
+ candidate, err = getRandomPort()
+ if err != nil {
+ return nil, nil, nil, errors.Wrapf(err, "error getting candidate host port for container port %d", p.ContainerPort)
+ }
+ } else {
+ candidate++
}
if hostPortMap[uint16(candidate)] == 0 {
@@ -213,6 +238,11 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
return remadeMappings, containerPortValidate, hostPortValidate, nil
}
+ finalMappings := []ocicni.PortMapping{}
+ for _, m := range tempMappings {
+ finalMappings = append(finalMappings, m.mapping)
+ }
+
return finalMappings, containerPortValidate, hostPortValidate, nil
}
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index e36c86690..226b71627 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -235,14 +235,7 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
ociRuntime := os.Getenv("OCI_RUNTIME")
if ociRuntime == "" {
- var err error
- ociRuntime, err = exec.LookPath("crun")
- // If we cannot find the crun binary, setting to something static as we have no way
- // to return an error. The tests will fail and point out that the runc binary could
- // not be found nicely.
- if err != nil {
- ociRuntime = "/usr/bin/runc"
- }
+ ociRuntime = "crun"
}
os.Setenv("DISABLE_HC_SYSTEMD", "true")
CNIConfigDir := "/etc/cni/net.d"
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 3906fa49d..7ab8dc6f8 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -1447,4 +1447,23 @@ MemoryReservation: {{ .HostConfig.MemoryReservation }}`})
Expect(inspect.OutputToString()).To(ContainSubstring("Memory: " + expectedMemoryLimit))
}
})
+
+ It("podman play kube reports invalid image name", func() {
+ invalidImageName := "./myimage"
+
+ pod := getPod(
+ withCtr(
+ getCtr(
+ withImage(invalidImageName),
+ ),
+ ),
+ )
+ err := generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(125))
+ Expect(kube.ErrorToString()).To(ContainSubstring(invalidImageName))
+ })
})
diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go
index 81a746b86..7c0b8bc9b 100644
--- a/test/e2e/runlabel_test.go
+++ b/test/e2e/runlabel_test.go
@@ -88,12 +88,15 @@ var _ = Describe("podman container runlabel", func() {
result := podmanTest.Podman([]string{"container", "runlabel", "RUN", ALPINE})
result.WaitWithDefaultTimeout()
Expect(result).To(ExitWithError())
+ // should not panic when label missing the value or don't have the label
+ Expect(result.LineInOutputContains("panic")).NotTo(BeTrue())
})
It("podman container runlabel bogus label in remote image should result in non-zero exit", func() {
result := podmanTest.Podman([]string{"container", "runlabel", "RUN", "docker.io/library/ubuntu:latest"})
result.WaitWithDefaultTimeout()
Expect(result).To(ExitWithError())
-
+ // should not panic when label missing the value or don't have the label
+ Expect(result.LineInOutputContains("panic")).NotTo(BeTrue())
})
It("podman container runlabel global options", func() {
diff --git a/test/endpoint/setup.go b/test/endpoint/setup.go
index 56cab06b0..6bbc8d2bc 100644
--- a/test/endpoint/setup.go
+++ b/test/endpoint/setup.go
@@ -51,14 +51,7 @@ func Setup(tempDir string) *EndpointTestIntegration {
ociRuntime := os.Getenv("OCI_RUNTIME")
if ociRuntime == "" {
- var err error
- ociRuntime, err = exec.LookPath("runc")
- // If we cannot find the runc binary, setting to something static as we have no way
- // to return an error. The tests will fail and point out that the runc binary could
- // not be found nicely.
- if err != nil {
- ociRuntime = "/usr/bin/runc"
- }
+ ociRuntime = "runc"
}
os.Setenv("DISABLE_HC_SYSTEMD", "true")
CNIConfigDir := "/etc/cni/net.d"
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 28dc7c7a7..9f4037730 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -460,4 +460,17 @@ json-file | f
is "$output" "$expect" "podman run with --tz=local, matches host"
}
+# run with --runtime should preserve the named runtime
+@test "podman run : full path to --runtime is preserved" {
+ skip_if_cgroupsv1
+ skip_if_remote
+ run_podman run -d --runtime '/usr/bin/crun' $IMAGE sleep 60
+ cid="$output"
+
+ run_podman inspect --format '{{.OCIRuntime}}' $cid
+ is "$output" "/usr/bin/crun"
+
+ run_podman kill $cid
+}
+
# vim: filetype=sh
diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats
index 7176ae4b8..0107114b5 100644
--- a/test/system/055-rm.bats
+++ b/test/system/055-rm.bats
@@ -41,11 +41,14 @@ load helpers
run_podman create --name $rand $IMAGE /bin/true
# Create a container that podman does not know about
- run buildah from $IMAGE
- cid="$output"
+ external_cid=$(buildah from $IMAGE)
+
+ # Plain 'exists' should fail, but should succeed with --external
+ run_podman 1 container exists $external_cid
+ run_podman container exists --external $external_cid
# rm should succeed
- run_podman rm $rand $cid
+ run_podman rm $rand $external_cid
}
# I'm sorry! This test takes 13 seconds. There's not much I can do about it,
diff --git a/test/system/140-diff.bats b/test/system/140-diff.bats
index 01ec5430e..1277f9bbe 100644
--- a/test/system/140-diff.bats
+++ b/test/system/140-diff.bats
@@ -32,4 +32,26 @@ load helpers
run_podman rm $n
}
+@test "podman diff with buildah container " {
+ rand_file=$(random_string 10)
+ buildah from --name buildahctr $IMAGE
+ buildah run buildahctr sh -c "touch /$rand_file;rm /etc/services"
+
+ run_podman diff --format json buildahctr
+
+ # Expected results for each type of diff
+ declare -A expect=(
+ [added]="/$rand_file"
+ [changed]="/etc"
+ [deleted]="/etc/services"
+ )
+
+ for field in ${!expect[@]}; do
+ result=$(jq -r -c ".${field}[]" <<<"$output")
+ is "$result" "${expect[$field]}" "$field"
+ done
+
+ buildah rm buildahctr
+}
+
# vim: filetype=sh
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index 4591c9015..2cced10c2 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -34,6 +34,14 @@ function basic_setup() {
# Clean up all containers
run_podman rm --all --force
+ # ...including external (buildah) ones
+ run_podman ps --all --external --format '{{.ID}} {{.Names}}'
+ for line in "${lines[@]}"; do
+ set $line
+ echo "# setup(): removing stray external container $1 ($2)" >&3
+ run_podman rm $1
+ done
+
# Clean up all images except those desired
found_needed_image=
run_podman images --all --format '{{.Repository}}:{{.Tag}} {{.ID}}'
@@ -245,6 +253,7 @@ function is_cgroupsv1() {
! is_cgroupsv2
}
+# True if cgroups v2 are enabled
function is_cgroupsv2() {
cgroup_type=$(stat -f -c %T /sys/fs/cgroup)
test "$cgroup_type" = "cgroup2fs"
@@ -297,6 +306,15 @@ function skip_if_no_selinux() {
fi
}
+#######################
+# skip_if_cgroupsv1 # ...with an optional message
+#######################
+function skip_if_cgroupsv1() {
+ if ! is_cgroupsv2; then
+ skip "${1:-test requires cgroupsv2}"
+ fi
+}
+
#########
# die # Abort with helpful message
#########