summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--cmd/podman/kill.go4
-rw-r--r--cmd/podman/pod_kill.go4
-rw-r--r--cmd/podman/ps.go12
-rw-r--r--cmd/podman/shared/create.go5
-rw-r--r--libpod/container_inspect.go7
-rw-r--r--libpod/container_internal.go14
-rw-r--r--pkg/util/utils.go21
-rw-r--r--test/e2e/inspect_test.go1
-rw-r--r--test/e2e/ps_test.go15
-rw-r--r--test/system/130-kill.bats101
11 files changed, 171 insertions, 23 deletions
diff --git a/Makefile b/Makefile
index fb6e48585..32da41ef7 100644
--- a/Makefile
+++ b/Makefile
@@ -447,12 +447,22 @@ install.systemd:
install ${SELINUXOPT} -m 644 contrib/varlink/podman.conf ${DESTDIR}${TMPFILESDIR}/podman.conf
uninstall:
+ # Remove manpages
for i in $(filter %.1,$(MANPAGES_DEST)); do \
rm -f $(DESTDIR)$(MANDIR)/man1/$$(basename $${i}); \
done; \
for i in $(filter %.5,$(MANPAGES_DEST)); do \
rm -f $(DESTDIR)$(MANDIR)/man5/$$(basename $${i}); \
done
+ # Remove podman and remote bin
+ rm -f $(DESTDIR)$(BINDIR)/podman
+ rm -f $(DESTDIR)$(BINDIR)/podman-remote
+ # Remove related config files
+ rm -f ${DESTDIR}${ETCDIR}/cni/net.d/87-podman-bridge.conflist
+ rm -f ${DESTDIR}${TMPFILESDIR}/podman.conf
+ rm -f ${DESTDIR}${SYSTEMDDIR}/io.podman.socket
+ rm -f ${DESTDIR}${USERSYSTEMDDIR}/io.podman.socket
+ rm -f ${DESTDIR}${SYSTEMDDIR}/io.podman.service
.PHONY: .gitvalidation
.gitvalidation: .gopathok
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index aba2008ca..a10546ea9 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -3,7 +3,7 @@ package main
import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
- "github.com/docker/docker/pkg/signal"
+ "github.com/containers/libpod/pkg/util"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -54,7 +54,7 @@ func killCmd(c *cliconfig.KillValues) error {
// Check if the signalString provided by the user is valid
// Invalid signals will return err
- killSignal, err := signal.ParseSignal(c.Signal)
+ killSignal, err := util.ParseSignal(c.Signal)
if err != nil {
return err
}
diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go
index 064946f72..9f696073d 100644
--- a/cmd/podman/pod_kill.go
+++ b/cmd/podman/pod_kill.go
@@ -6,7 +6,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
- "github.com/docker/docker/pkg/signal"
+ "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -60,7 +60,7 @@ func podKillCmd(c *cliconfig.PodKillValues) error {
if c.Signal != "" {
// Check if the signalString provided by the user is valid
// Invalid signals will return err
- sysSignal, err := signal.ParseSignal(c.Signal)
+ sysSignal, err := util.ParseSignal(c.Signal)
if err != nil {
return err
}
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 42d77a844..d2c5e19e2 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -205,11 +205,15 @@ func checkFlagsPassed(c *cliconfig.PsValues) error {
if c.Last >= 0 && c.Latest {
return errors.Errorf("last and latest are mutually exclusive")
}
- // Quiet conflicts with size, namespace, and format with a Go template
+ // Quiet conflicts with size and namespace and is overridden by a Go
+ // template.
if c.Quiet {
- if c.Size || c.Namespace || (c.Flag("format").Changed &&
- c.Format != formats.JSONString) {
- return errors.Errorf("quiet conflicts with size, namespace, and format with go template")
+ if c.Size || c.Namespace {
+ return errors.Errorf("quiet conflicts with size and namespace")
+ }
+ if c.Flag("format").Changed && c.Format != formats.JSONString {
+ // Quiet is overridden by Go template output.
+ c.Quiet = false
}
}
// Size and namespace conflict with each other
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index c1c5db7cb..58cf56eea 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -24,7 +24,6 @@ import (
"github.com/containers/libpod/pkg/rootless"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
- "github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
"github.com/opentracing/opentracing-go"
@@ -464,7 +463,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
signalString = c.String("stop-signal")
}
if signalString != "" {
- stopSignal, err = signal.ParseSignal(signalString)
+ stopSignal, err = util.ParseSignal(signalString)
if err != nil {
return nil, err
}
@@ -624,7 +623,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
if systemd {
if signalString == "" {
- stopSignal, err = signal.ParseSignal("RTMIN+3")
+ stopSignal, err = util.ParseSignal("RTMIN+3")
if err != nil {
return nil, errors.Wrapf(err, "error parsing systemd signal")
}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 22afc61cc..639dd6e91 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -118,7 +118,7 @@ type InspectContainerData struct {
BoundingCaps []string `json:"BoundingCaps"`
ExecIDs []string `json:"ExecIDs"`
GraphDriver *driver.Data `json:"GraphDriver"`
- SizeRw int64 `json:"SizeRw,omitempty"`
+ SizeRw *int64 `json:"SizeRw,omitempty"`
SizeRootFs int64 `json:"SizeRootFs,omitempty"`
Mounts []InspectMount `json:"Mounts"`
Dependencies []string `json:"Dependencies"`
@@ -809,12 +809,13 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
if err != nil {
logrus.Errorf("error getting rootfs size %q: %v", config.ID, err)
}
+ data.SizeRootFs = rootFsSize
+
rwSize, err := c.rwSize()
if err != nil {
logrus.Errorf("error getting rw size %q: %v", config.ID, err)
}
- data.SizeRootFs = rootFsSize
- data.SizeRw = rwSize
+ data.SizeRw = &rwSize
}
return data, nil
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 9d97ac5d6..562f783a7 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -84,7 +84,7 @@ func (c *Container) rootFsSize() (int64, error) {
return size + layerSize, err
}
-// rwSize Gets the size of the mutable top layer of the container.
+// rwSize gets the size of the mutable top layer of the container.
func (c *Container) rwSize() (int64, error) {
if c.config.Rootfs != "" {
var size int64
@@ -103,14 +103,16 @@ func (c *Container) rwSize() (int64, error) {
return 0, err
}
- // Get the size of the top layer by calculating the size of the diff
- // between the layer and its parent. The top layer of a container is
- // the only RW layer, all others are immutable
- layer, err := c.runtime.store.Layer(container.LayerID)
+ // The top layer of a container is
+ // the only readable/writeable layer, all others are immutable.
+ rwLayer, err := c.runtime.store.Layer(container.LayerID)
if err != nil {
return 0, err
}
- return c.runtime.store.DiffSize(layer.Parent, layer.ID)
+
+ // Get the size of the top layer by calculating the size of the diff
+ // between the layer and its parent.
+ return c.runtime.store.DiffSize(rwLayer.Parent, rwLayer.ID)
}
// bundlePath returns the path to the container's root filesystem - where the OCI spec will be
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 5b4dfe9fa..f7d04c73b 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"sync"
+ "syscall"
"time"
"github.com/BurntSushi/toml"
@@ -284,9 +285,7 @@ func GetImageConfig(changes []string) (ImageConfig, error) {
config.Labels[key] = val
case "STOPSIGNAL":
// Check the provided signal for validity.
- // TODO: Worth checking range? ParseSignal allows
- // negative numbers.
- killSignal, err := signal.ParseSignal(value)
+ killSignal, err := ParseSignal(value)
if err != nil {
return ImageConfig{}, errors.Wrapf(err, "invalid change %q - KILLSIGNAL must be given a valid signal", change)
}
@@ -305,6 +304,22 @@ func GetImageConfig(changes []string) (ImageConfig, error) {
return config, nil
}
+// Parse and validate a signal name or number
+func ParseSignal(rawSignal string) (syscall.Signal, error) {
+ // Strip off leading dash, to allow -1 or -HUP
+ basename := strings.TrimPrefix(rawSignal, "-")
+
+ signal, err := signal.ParseSignal(basename)
+ if err != nil {
+ return -1, err
+ }
+ // 64 is SIGRTMAX; wish we could get this from a standard Go library
+ if signal < 1 || signal > 64 {
+ return -1, errors.Errorf("valid signals are 1 through 64")
+ }
+ return signal, nil
+}
+
// ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping
func ParseIDMapping(mode namespaces.UsernsMode, UIDMapSlice, GIDMapSlice []string, subUIDMap, subGIDMap string) (*storage.IDMappingOptions, error) {
options := storage.IDMappingOptions{
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index 2d81ef0d8..9d23384ea 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -86,6 +86,7 @@ var _ = Describe("Podman inspect", func() {
Expect(result.ExitCode()).To(Equal(0))
conData := result.InspectContainerToJSON()
Expect(conData[0].SizeRootFs).To(BeNumerically(">", 0))
+ Expect(*conData[0].SizeRw).To(BeNumerically(">=", 0))
})
It("podman inspect container and image", func() {
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 17be114ba..12bfdfe41 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -383,4 +383,19 @@ var _ = Describe("Podman ps", func() {
Expect(len(output)).To(Equal(1))
Expect(output[0]).To(Equal(fullCid))
})
+
+ It("podman ps quiet template", func() {
+ ctrName := "testCtr"
+ session := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ result := podmanTest.Podman([]string{"ps", "-q", "-a", "--format", "{{ .Names }}"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+
+ output := result.OutputToStringArray()
+ Expect(len(output)).To(Equal(1))
+ Expect(output[0]).To(Equal(ctrName))
+ })
})
diff --git a/test/system/130-kill.bats b/test/system/130-kill.bats
new file mode 100644
index 000000000..aae7f114f
--- /dev/null
+++ b/test/system/130-kill.bats
@@ -0,0 +1,101 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# tests for podman kill
+#
+
+load helpers
+
+@test "podman kill - test signal handling in containers" {
+ # Start a container that will handle all signals by emitting 'got: N'
+ local -a signals=(1 2 3 4 5 6 8 10 12 13 14 15 16 20 21 22 23 24 25 26 64)
+ run_podman run -d $IMAGE sh -c "for i in ${signals[*]}; do trap \"echo got: \$i\" \$i; done; echo READY; while ! test -e /stop; do sleep 0.05; done;echo DONE"
+ cid="$output"
+
+ # Run 'logs -f' on that container, but run it in the background with
+ # redirection to a named pipe from which we (foreground job) read
+ # and confirm that signals are received. We can't use run_podman here.
+ local fifo=${PODMAN_TMPDIR}/podman-kill-fifo.$(random_string 10)
+ mkfifo $fifo
+ $PODMAN logs -f $cid >$fifo </dev/null &
+ podman_log_pid=$!
+
+ # Open the FIFO for reading, and keep it open. This prevents a race
+ # condition in which the container can exit (e.g. if for some reason
+ # it doesn't handle the signal) and we (this test) try to read from
+ # the FIFO. Since there wouldn't be an active writer, the open()
+ # would hang forever. With this exec we keep the FD open, allowing
+ # 'read -t' to time out and report a useful error.
+ exec 5<$fifo
+
+ # First container emits READY when ready; wait for it.
+ read -t 10 -u 5 ready
+ is "$ready" "READY" "first log message from container"
+
+ # Helper function: send the given signal, verify that it's received.
+ kill_and_check() {
+ local signal=$1
+ local signum=${2:-$1} # e.g. if signal=HUP, we expect to see '1'
+
+ run_podman kill -s $signal $cid
+ read -t 10 -u 5 actual || die "Timed out: no ACK for kill -s $signal"
+ is "$actual" "got: $signum" "Signal $signal handled by container"
+ }
+
+ # Send signals in random order; make sure each one is received
+ for s in $(fmt --width=2 <<< "${signals[*]}" | sort --random-sort);do
+ kill_and_check $s
+ done
+
+ # Variations: with leading dash; by name, with/without dash or SIG
+ kill_and_check -1 1
+ kill_and_check -INT 2
+ kill_and_check FPE 8
+ kill_and_check -SIGUSR1 10
+ kill_and_check SIGUSR2 12
+
+ # Done. Tell the container to stop, and wait for final DONE
+ run_podman exec $cid touch /stop
+ read -t 5 -u 5 done || die "Timed out waiting for DONE from container"
+ is "$done" "DONE" "final log message from container"
+
+ # Clean up
+ run_podman wait $cid
+ run_podman rm $cid
+ wait $podman_log_pid
+}
+
+@test "podman kill - rejects invalid args" {
+ # These errors are thrown by the imported docker/signal.ParseSignal()
+ local -a bad_signal_names=(0 SIGBADSIG SIG BADSIG %% ! "''" '""' " ")
+ for s in ${bad_signal_names[@]}; do
+ # 'nosuchcontainer' is fine: podman should bail before it gets there
+ run_podman 125 kill -s $s nosuchcontainer
+ is "$output" "Error: Invalid signal: $s" "Error from kill -s $s"
+
+ run_podman 125 pod kill -s $s nosuchpod
+ is "$output" "Error: Invalid signal: $s" "Error from pod kill -s $s"
+ done
+
+ # Special case: these too are thrown by docker/signal.ParseSignal(),
+ # but the dash sign is stripped by our wrapper in utils, so the
+ # error message doesn't include the dash.
+ local -a bad_dash_signals=(-0 -SIGBADSIG -SIG -BADSIG -)
+ for s in ${bad_dash_signals[@]}; do
+ run_podman 125 kill -s $s nosuchcontainer
+ is "$output" "Error: Invalid signal: ${s##-}" "Error from kill -s $s"
+ done
+
+ # This error (signal out of range) is thrown by our wrapper
+ local -a bad_signal_nums=(65 -65 96 999 99999999)
+ for s in ${bad_signal_nums[@]}; do
+ run_podman 125 kill -s $s nosuchcontainer
+ is "$output" "Error: valid signals are 1 through 64" \
+ "Error from kill -s $s"
+ done
+
+ # 'podman create' uses the same parsing code
+ run_podman 125 create --stop-signal=99 $IMAGE
+ is "$output" "Error: valid signals are 1 through 64" "podman create"
+}
+
+# vim: filetype=sh