summaryrefslogtreecommitdiff
path: root/cmd/podman/shared
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/shared')
-rw-r--r--cmd/podman/shared/container.go13
-rw-r--r--cmd/podman/shared/create.go246
-rw-r--r--cmd/podman/shared/create_cli.go11
-rw-r--r--cmd/podman/shared/create_cli_test.go51
-rw-r--r--cmd/podman/shared/funcs_linux_test.go119
-rw-r--r--cmd/podman/shared/funcs_test.go112
-rw-r--r--cmd/podman/shared/intermediate.go2
-rw-r--r--cmd/podman/shared/intermediate_varlink.go3
-rw-r--r--cmd/podman/shared/parse/parse.go35
-rw-r--r--cmd/podman/shared/parse/parse_test.go53
-rw-r--r--cmd/podman/shared/pod.go198
11 files changed, 537 insertions, 306 deletions
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index 9459247ed..b5a1e7104 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -30,6 +30,7 @@ import (
const (
cidTruncLength = 12
podTruncLength = 12
+ iidTruncLength = 12
cmdTruncLength = 17
)
@@ -66,6 +67,7 @@ type BatchContainerStruct struct {
type PsContainerOutput struct {
ID string
Image string
+ ImageID string
Command string
Created string
Ports string
@@ -203,7 +205,7 @@ func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions)
status = "Error"
}
- _, imageName := ctr.Image()
+ imageID, imageName := ctr.Image()
cid := ctr.ID()
podID := ctr.PodID()
if !opts.NoTrunc {
@@ -214,6 +216,9 @@ func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions)
if len(command) > cmdTruncLength {
command = command[0:cmdTruncLength] + "..."
}
+ if len(imageID) > iidTruncLength {
+ imageID = imageID[0:iidTruncLength]
+ }
}
ports, err := ctr.PortMappings()
@@ -223,6 +228,7 @@ func NewBatchContainer(r *libpod.Runtime, ctr *libpod.Container, opts PsOptions)
pso.ID = cid
pso.Image = imageName
+ pso.ImageID = imageID
pso.Command = command
pso.Created = created
pso.Ports = portsToString(ports)
@@ -640,6 +646,11 @@ func GetNamespaces(pid int) *Namespace {
}
}
+// GetNamespaceInfo is an exported wrapper for getNamespaceInfo
+func GetNamespaceInfo(path string) (string, error) {
+ return getNamespaceInfo(path)
+}
+
func getNamespaceInfo(path string) (string, error) {
val, err := os.Readlink(path)
if err != nil {
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 2f637694b..5fa8d6c0b 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -18,11 +18,15 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
ann "github.com/containers/libpod/pkg/annotations"
+ "github.com/containers/libpod/pkg/autoupdate"
+ envLib "github.com/containers/libpod/pkg/env"
"github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/inspect"
ns "github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/seccomp"
cc "github.com/containers/libpod/pkg/spec"
+ systemdGen "github.com/containers/libpod/pkg/systemd/generate"
"github.com/containers/libpod/pkg/util"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
@@ -31,10 +35,6 @@ import (
"github.com/sirupsen/logrus"
)
-// seccompLabelKey is the key of the image annotation embedding a seccomp
-// profile.
-const seccompLabelKey = "io.containers.seccomp.profile"
-
func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
var (
healthCheck *manifest.Schema2HealthConfig
@@ -71,6 +71,7 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
imageName := ""
+ rawImageName := ""
var imageData *inspect.ImageData = nil
// Set the storage if there is no rootfs specified
@@ -80,9 +81,8 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
writer = os.Stderr
}
- name := ""
if len(c.InputArgs) != 0 {
- name = c.InputArgs[0]
+ rawImageName = c.InputArgs[0]
} else {
return nil, nil, errors.Errorf("error, image name not provided")
}
@@ -99,21 +99,21 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
ArchitectureChoice: overrideArch,
}
- newImage, err := runtime.ImageRuntime().New(ctx, name, rtc.SignaturePolicyPath, c.String("authfile"), writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullType)
+ newImage, err := runtime.ImageRuntime().New(ctx, rawImageName, rtc.Engine.SignaturePolicyPath, c.String("authfile"), writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullType)
if err != nil {
return nil, nil, err
}
- imageData, err = newImage.Inspect(ctx)
+ imageData, err = newImage.InspectNoSize(ctx)
if err != nil {
return nil, nil, err
}
if overrideOS == "" && imageData.Os != goruntime.GOOS {
- return nil, nil, errors.Errorf("incompatible image OS %q on %q host", imageData.Os, goruntime.GOOS)
+ logrus.Infof("Using %q (OS) image on %q host", imageData.Os, goruntime.GOOS)
}
if overrideArch == "" && imageData.Architecture != goruntime.GOARCH {
- return nil, nil, errors.Errorf("incompatible image architecture %q on %q host", imageData.Architecture, goruntime.GOARCH)
+ logrus.Infof("Using %q (architecture) on %q host", imageData.Architecture, goruntime.GOARCH)
}
names := newImage.Names()
@@ -123,12 +123,13 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
imageName = newImage.ID()
}
- // if the user disabled the healthcheck with "none", we skip adding it
+ // if the user disabled the healthcheck with "none" or the no-healthcheck
+ // options is provided, we skip adding it
healthCheckCommandInput := c.String("healthcheck-command")
// the user didn't disable the healthcheck but did pass in a healthcheck command
// now we need to make a healthcheck from the commandline input
- if healthCheckCommandInput != "none" {
+ if healthCheckCommandInput != "none" && !c.Bool("no-healthcheck") {
if len(healthCheckCommandInput) > 0 {
healthCheck, err = makeHealthCheckFromCli(c)
if err != nil {
@@ -175,11 +176,32 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
}
- createConfig, err := ParseCreateOpts(ctx, c, runtime, imageName, imageData)
+ createConfig, err := ParseCreateOpts(ctx, c, runtime, imageName, rawImageName, imageData)
if err != nil {
return nil, nil, err
}
+ // (VR): Ideally we perform the checks _before_ pulling the image but that
+ // would require some bigger code refactoring of `ParseCreateOpts` and the
+ // logic here. But as the creation code will be consolidated in the future
+ // and given auto updates are experimental, we can live with that for now.
+ // In the end, the user may only need to correct the policy or the raw image
+ // name.
+ autoUpdatePolicy, autoUpdatePolicySpecified := createConfig.Labels[autoupdate.Label]
+ if autoUpdatePolicySpecified {
+ if _, err := autoupdate.LookupPolicy(autoUpdatePolicy); err != nil {
+ return nil, nil, err
+ }
+ // Now we need to make sure we're having a fully-qualified image reference.
+ if rootfs != "" {
+ return nil, nil, errors.Errorf("auto updates do not work with --rootfs")
+ }
+ // Make sure the input image is a docker.
+ if err := autoupdate.ValidateImageReference(rawImageName); err != nil {
+ return nil, nil, err
+ }
+ }
+
// Because parseCreateOpts does derive anything from the image, we add health check
// at this point. The rest is done by WithOptions.
createConfig.HealthCheck = healthCheck
@@ -271,7 +293,7 @@ func configurePod(c *GenericCLIResults, runtime *libpod.Runtime, namespaces map[
// Parses CLI options related to container creation into a config which can be
// parsed into an OCI runtime spec
-func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) {
+func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime, imageName string, rawImageName string, data *inspect.ImageData) (*cc.CreateConfig, error) {
var (
inputCommand, command []string
memoryLimit, memoryReservation, memorySwap, memoryKernel int64
@@ -309,9 +331,13 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
}
if c.String("memory-swap") != "" {
- memorySwap, err = units.RAMInBytes(c.String("memory-swap"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory-swap")
+ if c.String("memory-swap") == "-1" {
+ memorySwap = -1
+ } else {
+ memorySwap, err = units.RAMInBytes(c.String("memory-swap"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid value for memory-swap")
+ }
}
}
if c.String("kernel-memory") != "" {
@@ -471,23 +497,59 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
// ENVIRONMENT VARIABLES
- env := EnvVariablesFromData(data)
+ //
+ // Precedence order (higher index wins):
+ // 1) env-host, 2) image data, 3) env-file, 4) env
+ env := map[string]string{
+ "container": "podman",
+ }
+
+ // First transform the os env into a map. We need it for the labels later in
+ // any case.
+ osEnv, err := envLib.ParseSlice(os.Environ())
+ if err != nil {
+ return nil, errors.Wrap(err, "error parsing host environment variables")
+ }
+
+ // Start with env-host
+
if c.Bool("env-host") {
- for _, e := range os.Environ() {
- pair := strings.SplitN(e, "=", 2)
- if _, ok := env[pair[0]]; !ok {
- if len(pair) > 1 {
- env[pair[0]] = pair[1]
- }
+ env = envLib.Join(env, osEnv)
+ }
+
+ // Image data overrides any previous variables
+ if data != nil {
+ configEnv, err := envLib.ParseSlice(data.Config.Env)
+ if err != nil {
+ return nil, errors.Wrap(err, "error passing image environment variables")
+ }
+ env = envLib.Join(env, configEnv)
+ }
+
+ // env-file overrides any previous variables
+ if c.IsSet("env-file") {
+ for _, f := range c.StringSlice("env-file") {
+ fileEnv, err := envLib.ParseFile(f)
+ if err != nil {
+ return nil, err
}
+ // File env is overridden by env.
+ env = envLib.Join(env, fileEnv)
}
}
- if err := parse.ReadKVStrings(env, c.StringSlice("env-file"), c.StringArray("env")); err != nil {
- return nil, errors.Wrapf(err, "unable to process environment variables")
+
+ // env overrides any previous variables
+ cmdlineEnv := c.StringSlice("env")
+ if len(cmdlineEnv) > 0 {
+ parsedEnv, err := envLib.ParseSlice(cmdlineEnv)
+ if err != nil {
+ return nil, err
+ }
+ env = envLib.Join(env, parsedEnv)
}
// LABEL VARIABLES
- labels, err := GetAllLabels(c.StringSlice("label-file"), c.StringArray("label"))
+ labels, err := parse.GetAllLabels(c.StringSlice("label-file"), c.StringArray("label"))
if err != nil {
return nil, errors.Wrapf(err, "unable to process labels")
}
@@ -499,6 +561,10 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
}
+ if systemdUnit, exists := osEnv[systemdGen.EnvVariable]; exists {
+ labels[systemdGen.EnvVariable] = systemdUnit
+ }
+
// ANNOTATIONS
annotations := make(map[string]string)
@@ -570,7 +636,6 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
if err != nil {
return nil, errors.Wrapf(err, "unable to translate --shm-size")
}
-
// Verify the additional hosts are in correct format
for _, host := range c.StringSlice("add-host") {
if _, err := parse.ValidateExtraHost(host); err != nil {
@@ -578,24 +643,35 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
}
- // Check for . and dns-search domains
- if util.StringInSlice(".", c.StringSlice("dns-search")) && len(c.StringSlice("dns-search")) > 1 {
- return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
+ var (
+ dnsSearches []string
+ dnsServers []string
+ dnsOptions []string
+ )
+ if c.Changed("dns-search") {
+ dnsSearches = c.StringSlice("dns-search")
+ // Check for explicit dns-search domain of ''
+ if len(dnsSearches) == 0 {
+ return nil, errors.Errorf("'' is not a valid domain")
+ }
+ // Validate domains are good
+ for _, dom := range dnsSearches {
+ if dom == "." {
+ if len(dnsSearches) > 1 {
+ return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
+ }
+ continue
+ }
+ if _, err := parse.ValidateDomain(dom); err != nil {
+ return nil, err
+ }
+ }
}
-
- // Check for explicit dns-search domain of ''
- if c.Changed("dns-search") && len(c.StringSlice("dns-search")) == 0 {
- return nil, errors.Errorf("'' is not a valid domain")
+ if c.IsSet("dns") {
+ dnsServers = append(dnsServers, c.StringSlice("dns")...)
}
-
- // Validate domains are good
- for _, dom := range c.StringSlice("dns-search") {
- if dom == "." {
- continue
- }
- if _, err := parse.ValidateDomain(dom); err != nil {
- return nil, err
- }
+ if c.IsSet("dns-opt") {
+ dnsOptions = c.StringSlice("dns-opt")
}
var ImageVolumes map[string]struct{}
@@ -641,7 +717,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
pidsLimit := c.Int64("pids-limit")
if c.String("cgroups") == "disabled" && !c.Changed("pids-limit") {
- pidsLimit = 0
+ pidsLimit = -1
}
pid := &cc.PidConfig{
@@ -671,11 +747,10 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
HostAdd: c.StringSlice("add-host"),
Hostname: c.String("hostname"),
}
-
net := &cc.NetworkConfig{
- DNSOpt: c.StringSlice("dns-opt"),
- DNSSearch: c.StringSlice("dns-search"),
- DNSServers: c.StringSlice("dns"),
+ DNSOpt: dnsOptions,
+ DNSSearch: dnsSearches,
+ DNSServers: dnsServers,
HTTPProxy: c.Bool("http-proxy"),
MacAddress: c.String("mac-address"),
Network: c.String("network"),
@@ -686,9 +761,12 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
PortBindings: portBindings,
}
- sysctl, err := validateSysctl(c.StringSlice("sysctl"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for sysctl")
+ sysctl := map[string]string{}
+ if c.Changed("sysctl") {
+ sysctl, err = util.ValidateSysctls(c.StringSlice("sysctl"))
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid value for sysctl")
+ }
}
secConfig := &cc.SecurityConfig{
@@ -700,24 +778,36 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
Sysctl: sysctl,
}
- if err := secConfig.SetLabelOpts(runtime, pid, ipc); err != nil {
- return nil, err
- }
- if err := secConfig.SetSecurityOpts(runtime, c.StringArray("security-opt")); err != nil {
- return nil, err
+ if c.Changed("security-opt") {
+ if err := secConfig.SetSecurityOpts(runtime, c.StringArray("security-opt")); err != nil {
+ return nil, err
+ }
}
// SECCOMP
if data != nil {
- if value, exists := labels[seccompLabelKey]; exists {
+ if value, exists := labels[seccomp.ContainerImageLabel]; exists {
secConfig.SeccompProfileFromImage = value
}
}
- if policy, err := cc.LookupSeccompPolicy(c.String("seccomp-policy")); err != nil {
+ if policy, err := seccomp.LookupPolicy(c.String("seccomp-policy")); err != nil {
return nil, err
} else {
secConfig.SeccompPolicy = policy
}
+ rtc, err := runtime.GetConfig()
+ if err != nil {
+ return nil, err
+ }
+ volumes := rtc.Containers.Volumes
+ if c.Changed("volume") {
+ volumes = append(volumes, c.StringSlice("volume")...)
+ }
+
+ devices := rtc.Containers.Devices
+ if c.Changed("device") {
+ devices = append(devices, c.StringSlice("device")...)
+ }
config := &cc.CreateConfig{
Annotations: annotations,
@@ -728,15 +818,16 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
Command: command,
UserCommand: userCommand,
Detach: c.Bool("detach"),
- Devices: c.StringSlice("device"),
+ Devices: devices,
Entrypoint: entrypoint,
Env: env,
// ExposedPorts: ports,
- Init: c.Bool("init"),
- InitPath: c.String("init-path"),
- Image: imageName,
- ImageID: imageID,
- Interactive: c.Bool("interactive"),
+ Init: c.Bool("init"),
+ InitPath: c.String("init-path"),
+ Image: imageName,
+ RawImageName: rawImageName,
+ ImageID: imageID,
+ Interactive: c.Bool("interactive"),
// IP6Address: c.String("ipv6"), // Not implemented yet - needs CNI support for static v6
Labels: labels,
// LinkLocalIP: c.StringSlice("link-local-ip"), // Not implemented yet
@@ -757,6 +848,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
CPURtPeriod: c.Uint64("cpu-rt-period"),
CPURtRuntime: c.Int64("cpu-rt-runtime"),
CPUs: c.Float64("cpus"),
+ DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
DeviceReadBps: c.StringSlice("device-read-bps"),
DeviceReadIOps: c.StringSlice("device-read-iops"),
DeviceWriteBps: c.StringSlice("device-write-bps"),
@@ -781,7 +873,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
Tmpfs: c.StringArray("tmpfs"),
Tty: tty,
MountsFlag: c.StringArray("mount"),
- Volumes: c.StringArray("volume"),
+ Volumes: volumes,
WorkDir: workDir,
Rootfs: rootfs,
VolumesFrom: c.StringSlice("volumes-from"),
@@ -822,28 +914,6 @@ func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateC
return ctr, nil
}
-var defaultEnvVariables = map[string]string{
- "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
- "TERM": "xterm",
-}
-
-// EnvVariablesFromData gets sets the default environment variables
-// for containers, and reads the variables from the image data, if present.
-func EnvVariablesFromData(data *inspect.ImageData) map[string]string {
- env := defaultEnvVariables
- if data != nil {
- for _, e := range data.Config.Env {
- split := strings.SplitN(e, "=", 2)
- if len(split) > 1 {
- env[split[0]] = split[1]
- } else {
- env[split[0]] = ""
- }
- }
- }
- return env
-}
-
func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig, error) {
inCommand := c.String("healthcheck-command")
inInterval := c.String("healthcheck-interval")
diff --git a/cmd/podman/shared/create_cli.go b/cmd/podman/shared/create_cli.go
index 00b83906d..10e27350b 100644
--- a/cmd/podman/shared/create_cli.go
+++ b/cmd/podman/shared/create_cli.go
@@ -4,7 +4,6 @@ import (
"fmt"
"strings"
- "github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/pkg/cgroups"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/sysinfo"
@@ -12,16 +11,6 @@ import (
"github.com/sirupsen/logrus"
)
-// GetAllLabels ...
-func GetAllLabels(labelFile, inputLabels []string) (map[string]string, error) {
- labels := make(map[string]string)
- labelErr := parse.ReadKVStrings(labels, labelFile, inputLabels)
- if labelErr != nil {
- return labels, errors.Wrapf(labelErr, "unable to process labels from --label and label-file")
- }
- return labels, nil
-}
-
// validateSysctl validates a sysctl and returns it.
func validateSysctl(strSlice []string) (map[string]string, error) {
sysctl := make(map[string]string)
diff --git a/cmd/podman/shared/create_cli_test.go b/cmd/podman/shared/create_cli_test.go
index fea1a2390..a045962cb 100644
--- a/cmd/podman/shared/create_cli_test.go
+++ b/cmd/podman/shared/create_cli_test.go
@@ -1,33 +1,11 @@
package shared
import (
- "io/ioutil"
- "os"
"testing"
"github.com/stretchr/testify/assert"
)
-var (
- Var1 = []string{"ONE=1", "TWO=2"}
-)
-
-func createTmpFile(content []byte) (string, error) {
- tmpfile, err := ioutil.TempFile(os.TempDir(), "unittest")
- if err != nil {
- return "", err
- }
-
- if _, err := tmpfile.Write(content); err != nil {
- return "", err
-
- }
- if err := tmpfile.Close(); err != nil {
- return "", err
- }
- return tmpfile.Name(), nil
-}
-
func TestValidateSysctl(t *testing.T) {
strSlice := []string{"net.core.test1=4", "kernel.msgmax=2"}
result, _ := validateSysctl(strSlice)
@@ -39,32 +17,3 @@ func TestValidateSysctlBadSysctl(t *testing.T) {
_, err := validateSysctl(strSlice)
assert.Error(t, err)
}
-
-func TestGetAllLabels(t *testing.T) {
- fileLabels := []string{}
- labels, _ := GetAllLabels(fileLabels, Var1)
- assert.Equal(t, len(labels), 2)
-}
-
-func TestGetAllLabelsBadKeyValue(t *testing.T) {
- inLabels := []string{"=badValue", "="}
- fileLabels := []string{}
- _, err := GetAllLabels(fileLabels, inLabels)
- assert.Error(t, err, assert.AnError)
-}
-
-func TestGetAllLabelsBadLabelFile(t *testing.T) {
- fileLabels := []string{"/foobar5001/be"}
- _, err := GetAllLabels(fileLabels, Var1)
- assert.Error(t, err, assert.AnError)
-}
-
-func TestGetAllLabelsFile(t *testing.T) {
- content := []byte("THREE=3")
- tFile, err := createTmpFile(content)
- defer os.Remove(tFile)
- assert.NoError(t, err)
- fileLabels := []string{tFile}
- result, _ := GetAllLabels(fileLabels, Var1)
- assert.Equal(t, len(result), 3)
-}
diff --git a/cmd/podman/shared/funcs_linux_test.go b/cmd/podman/shared/funcs_linux_test.go
new file mode 100644
index 000000000..88571153f
--- /dev/null
+++ b/cmd/podman/shared/funcs_linux_test.go
@@ -0,0 +1,119 @@
+package shared
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenerateCommand(t *testing.T) {
+ inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo \"hello world\""
+ correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo hello world"
+ newCommand, err := GenerateCommand(inputCommand, "foo", "bar", "")
+ assert.Nil(t, err)
+ assert.Equal(t, "hello world", newCommand[11])
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandCheckSubstitution(t *testing.T) {
+ type subsTest struct {
+ input string
+ expected string
+ shouldFail bool
+ }
+
+ absTmpFile, err := ioutil.TempFile("", "podmanRunlabelTestAbsolutePath")
+ assert.Nil(t, err, "error creating tempfile")
+ defer os.Remove(absTmpFile.Name())
+
+ relTmpFile, err := ioutil.TempFile("./", "podmanRunlabelTestRelativePath")
+ assert.Nil(t, err, "error creating tempfile")
+ defer os.Remove(relTmpFile.Name())
+ relTmpCmd, err := filepath.Abs(relTmpFile.Name())
+ assert.Nil(t, err, "error getting absolute path for relative tmpfile")
+
+ // this has a (low) potential of race conditions but no other way
+ removedTmpFile, err := ioutil.TempFile("", "podmanRunlabelTestRemove")
+ assert.Nil(t, err, "error creating tempfile")
+ os.Remove(removedTmpFile.Name())
+
+ absTmpCmd := fmt.Sprintf("%s --flag1 --flag2 --args=foo", absTmpFile.Name())
+ tests := []subsTest{
+ {
+ input: "docker run -it alpine:latest",
+ expected: "/proc/self/exe run -it alpine:latest",
+ shouldFail: false,
+ },
+ {
+ input: "podman run -it alpine:latest",
+ expected: "/proc/self/exe run -it alpine:latest",
+ shouldFail: false,
+ },
+ {
+ input: absTmpCmd,
+ expected: absTmpCmd,
+ shouldFail: false,
+ },
+ {
+ input: "./" + relTmpFile.Name(),
+ expected: relTmpCmd,
+ shouldFail: false,
+ },
+ {
+ input: "ls -la",
+ expected: "ls -la",
+ shouldFail: false,
+ },
+ {
+ input: removedTmpFile.Name(),
+ expected: "",
+ shouldFail: true,
+ },
+ }
+
+ for _, test := range tests {
+ newCommand, err := GenerateCommand(test.input, "foo", "bar", "")
+ if test.shouldFail {
+ assert.NotNil(t, err)
+ } else {
+ assert.Nil(t, err)
+ }
+ assert.Equal(t, test.expected, strings.Join(newCommand, " "))
+ }
+}
+
+func TestGenerateCommandPath(t *testing.T) {
+ inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
+ newCommand, _ := GenerateCommand(inputCommand, "foo", "bar", "")
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandNoSetName(t *testing.T) {
+ inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "/proc/self/exe run -it --name foo -e NAME=foo -e IMAGE=foo foo echo install"
+ newCommand, err := GenerateCommand(inputCommand, "foo", "", "")
+ assert.Nil(t, err)
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandNoName(t *testing.T) {
+ inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "/proc/self/exe run -it -e IMAGE=foo foo echo install"
+ newCommand, err := GenerateCommand(inputCommand, "foo", "", "")
+ assert.Nil(t, err)
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
+
+func TestGenerateCommandAlreadyPodman(t *testing.T) {
+ inputCommand := "podman run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
+ newCommand, err := GenerateCommand(inputCommand, "foo", "bar", "")
+ assert.Nil(t, err)
+ assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
+}
diff --git a/cmd/podman/shared/funcs_test.go b/cmd/podman/shared/funcs_test.go
index c05348242..dd856166e 100644
--- a/cmd/podman/shared/funcs_test.go
+++ b/cmd/podman/shared/funcs_test.go
@@ -1,11 +1,6 @@
package shared
import (
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
"testing"
"github.com/containers/libpod/pkg/util"
@@ -17,113 +12,6 @@ var (
imageName = "bar"
)
-func TestGenerateCommand(t *testing.T) {
- inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo \"hello world\""
- correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo hello world"
- newCommand, err := GenerateCommand(inputCommand, "foo", "bar", "")
- assert.Nil(t, err)
- assert.Equal(t, "hello world", newCommand[11])
- assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
-}
-
-func TestGenerateCommandCheckSubstitution(t *testing.T) {
- type subsTest struct {
- input string
- expected string
- shouldFail bool
- }
-
- absTmpFile, err := ioutil.TempFile("", "podmanRunlabelTestAbsolutePath")
- assert.Nil(t, err, "error creating tempfile")
- defer os.Remove(absTmpFile.Name())
-
- relTmpFile, err := ioutil.TempFile("./", "podmanRunlabelTestRelativePath")
- assert.Nil(t, err, "error creating tempfile")
- defer os.Remove(relTmpFile.Name())
- relTmpCmd, err := filepath.Abs(relTmpFile.Name())
- assert.Nil(t, err, "error getting absolute path for relative tmpfile")
-
- // this has a (low) potential of race conditions but no other way
- removedTmpFile, err := ioutil.TempFile("", "podmanRunlabelTestRemove")
- assert.Nil(t, err, "error creating tempfile")
- os.Remove(removedTmpFile.Name())
-
- absTmpCmd := fmt.Sprintf("%s --flag1 --flag2 --args=foo", absTmpFile.Name())
- tests := []subsTest{
- {
- input: "docker run -it alpine:latest",
- expected: "/proc/self/exe run -it alpine:latest",
- shouldFail: false,
- },
- {
- input: "podman run -it alpine:latest",
- expected: "/proc/self/exe run -it alpine:latest",
- shouldFail: false,
- },
- {
- input: absTmpCmd,
- expected: absTmpCmd,
- shouldFail: false,
- },
- {
- input: "./" + relTmpFile.Name(),
- expected: relTmpCmd,
- shouldFail: false,
- },
- {
- input: "ls -la",
- expected: "ls -la",
- shouldFail: false,
- },
- {
- input: removedTmpFile.Name(),
- expected: "",
- shouldFail: true,
- },
- }
-
- for _, test := range tests {
- newCommand, err := GenerateCommand(test.input, "foo", "bar", "")
- if test.shouldFail {
- assert.NotNil(t, err)
- } else {
- assert.Nil(t, err)
- }
- assert.Equal(t, test.expected, strings.Join(newCommand, " "))
- }
-}
-
-func TestGenerateCommandPath(t *testing.T) {
- inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
- correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
- newCommand, _ := GenerateCommand(inputCommand, "foo", "bar", "")
- assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
-}
-
-func TestGenerateCommandNoSetName(t *testing.T) {
- inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
- correctCommand := "/proc/self/exe run -it --name foo -e NAME=foo -e IMAGE=foo foo echo install"
- newCommand, err := GenerateCommand(inputCommand, "foo", "", "")
- assert.Nil(t, err)
- assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
-}
-
-func TestGenerateCommandNoName(t *testing.T) {
- inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
- correctCommand := "/proc/self/exe run -it -e IMAGE=foo foo echo install"
- newCommand, err := GenerateCommand(inputCommand, "foo", "", "")
- assert.Nil(t, err)
- assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
-}
-
-func TestGenerateCommandAlreadyPodman(t *testing.T) {
- inputCommand := "podman run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
- correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
- newCommand, err := GenerateCommand(inputCommand, "foo", "bar", "")
- assert.Nil(t, err)
- assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
-}
-
func TestGenerateRunEnvironment(t *testing.T) {
opts := make(map[string]string)
opts["opt1"] = "one"
diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go
index cfb3f612c..e76750042 100644
--- a/cmd/podman/shared/intermediate.go
+++ b/cmd/podman/shared/intermediate.go
@@ -386,6 +386,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["detach"] = newCRBool(c, "detach")
m["detach-keys"] = newCRString(c, "detach-keys")
m["device"] = newCRStringSlice(c, "device")
+ m["device-cgroup-rule"] = newCRStringSlice(c, "device-cgroup-rule")
m["device-read-bps"] = newCRStringSlice(c, "device-read-bps")
m["device-read-iops"] = newCRStringSlice(c, "device-read-iops")
m["device-write-bps"] = newCRStringSlice(c, "device-write-bps")
@@ -424,6 +425,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["memory-swappiness"] = newCRInt64(c, "memory-swappiness")
m["name"] = newCRString(c, "name")
m["network"] = newCRString(c, "network")
+ m["no-healthcheck"] = newCRBool(c, "no-healthcheck")
m["no-hosts"] = newCRBool(c, "no-hosts")
m["oom-kill-disable"] = newCRBool(c, "oom-kill-disable")
m["oom-score-adj"] = newCRInt(c, "oom-score-adj")
diff --git a/cmd/podman/shared/intermediate_varlink.go b/cmd/podman/shared/intermediate_varlink.go
index 691c4f92d..d2b048025 100644
--- a/cmd/podman/shared/intermediate_varlink.go
+++ b/cmd/podman/shared/intermediate_varlink.go
@@ -316,6 +316,7 @@ func intFromVarlink(v *int64, flagName string, defaultValue *int) CRInt {
// structure.
func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
+ defaultContainerConfig := cliconfig.GetDefaultConfig()
// TODO | WARN
// We do not get a default network over varlink. Unlike the other default values for some cli
// elements, it seems it gets set to the default anyway.
@@ -405,7 +406,7 @@ func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults {
m["rm"] = boolFromVarlink(opts.Rm, "rm", false)
m["rootfs"] = boolFromVarlink(opts.Rootfs, "rootfs", false)
m["security-opt"] = stringArrayFromVarlink(opts.SecurityOpt, "security-opt", nil)
- m["shm-size"] = stringFromVarlink(opts.ShmSize, "shm-size", &cliconfig.DefaultShmSize)
+ m["shm-size"] = stringFromVarlink(opts.ShmSize, "shm-size", &defaultContainerConfig.Containers.ShmSize)
m["stop-signal"] = stringFromVarlink(opts.StopSignal, "stop-signal", nil)
m["stop-timeout"] = uintFromVarlink(opts.StopTimeout, "stop-timeout", nil)
m["storage-opt"] = stringSliceFromVarlink(opts.StorageOpt, "storage-opt", nil)
diff --git a/cmd/podman/shared/parse/parse.go b/cmd/podman/shared/parse/parse.go
index 3a75ff7a8..03cda268c 100644
--- a/cmd/podman/shared/parse/parse.go
+++ b/cmd/podman/shared/parse/parse.go
@@ -79,21 +79,34 @@ func ValidateDomain(val string) (string, error) {
return "", fmt.Errorf("%s is not a valid domain", val)
}
-// reads a file of line terminated key=value pairs, and overrides any keys
-// present in the file with additional pairs specified in the override parameter
-// for env-file and labels-file flags
-func ReadKVStrings(env map[string]string, files []string, override []string) error {
- for _, ef := range files {
- if err := parseEnvFile(env, ef); err != nil {
- return err
+// GetAllLabels retrieves all labels given a potential label file and a number
+// of labels provided from the command line.
+func GetAllLabels(labelFile, inputLabels []string) (map[string]string, error) {
+ labels := make(map[string]string)
+ for _, file := range labelFile {
+ // Use of parseEnvFile still seems safe, as it's missing the
+ // extra parsing logic of parseEnv.
+ // There's an argument that we SHOULD be doing that parsing for
+ // all environment variables, even those sourced from files, but
+ // that would require a substantial rework.
+ if err := parseEnvFile(labels, file); err != nil {
+ // FIXME: parseEnvFile is using parseEnv, so we need to add extra
+ // logic for labels.
+ return nil, err
}
}
- for _, line := range override {
- if err := parseEnv(env, line); err != nil {
- return err
+ for _, label := range inputLabels {
+ split := strings.SplitN(label, "=", 2)
+ if split[0] == "" {
+ return nil, errors.Errorf("invalid label format: %q", label)
}
+ value := ""
+ if len(split) > 1 {
+ value = split[1]
+ }
+ labels[split[0]] = value
}
- return nil
+ return labels, nil
}
func parseEnv(env map[string]string, line string) error {
diff --git a/cmd/podman/shared/parse/parse_test.go b/cmd/podman/shared/parse/parse_test.go
index 1359076a0..a6ddc2be9 100644
--- a/cmd/podman/shared/parse/parse_test.go
+++ b/cmd/podman/shared/parse/parse_test.go
@@ -4,9 +4,33 @@
package parse
import (
+ "io/ioutil"
+ "os"
"testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ Var1 = []string{"ONE=1", "TWO=2"}
)
+func createTmpFile(content []byte) (string, error) {
+ tmpfile, err := ioutil.TempFile(os.TempDir(), "unittest")
+ if err != nil {
+ return "", err
+ }
+
+ if _, err := tmpfile.Write(content); err != nil {
+ return "", err
+
+ }
+ if err := tmpfile.Close(); err != nil {
+ return "", err
+ }
+ return tmpfile.Name(), nil
+}
+
func TestValidateExtraHost(t *testing.T) {
type args struct {
val string
@@ -97,3 +121,32 @@ func TestValidateFileName(t *testing.T) {
})
}
}
+
+func TestGetAllLabels(t *testing.T) {
+ fileLabels := []string{}
+ labels, _ := GetAllLabels(fileLabels, Var1)
+ assert.Equal(t, len(labels), 2)
+}
+
+func TestGetAllLabelsBadKeyValue(t *testing.T) {
+ inLabels := []string{"=badValue", "="}
+ fileLabels := []string{}
+ _, err := GetAllLabels(fileLabels, inLabels)
+ assert.Error(t, err, assert.AnError)
+}
+
+func TestGetAllLabelsBadLabelFile(t *testing.T) {
+ fileLabels := []string{"/foobar5001/be"}
+ _, err := GetAllLabels(fileLabels, Var1)
+ assert.Error(t, err, assert.AnError)
+}
+
+func TestGetAllLabelsFile(t *testing.T) {
+ content := []byte("THREE=3")
+ tFile, err := createTmpFile(content)
+ defer os.Remove(tFile)
+ assert.NoError(t, err)
+ fileLabels := []string{tFile}
+ result, _ := GetAllLabels(fileLabels, Var1)
+ assert.Equal(t, len(result), 3)
+}
diff --git a/cmd/podman/shared/pod.go b/cmd/podman/shared/pod.go
index d8d69c8fc..50bd88e08 100644
--- a/cmd/podman/shared/pod.go
+++ b/cmd/podman/shared/pod.go
@@ -2,22 +2,18 @@ package shared
import (
"strconv"
+ "strings"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/util"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-connections/nat"
"github.com/pkg/errors"
)
-const (
- PodStateStopped = "Stopped"
- PodStateRunning = "Running"
- PodStatePaused = "Paused"
- PodStateExited = "Exited"
- PodStateErrored = "Error"
- PodStateCreated = "Created"
-)
+// TODO GetPodStatus and CreatePodStatusResults should removed once the adapter
+// and shared packages are reworked. It has now been duplicated in libpod proper.
// GetPodStatus determines the status of the pod based on the
// statuses of the containers in the pod.
@@ -25,7 +21,7 @@ const (
func GetPodStatus(pod *libpod.Pod) (string, error) {
ctrStatuses, err := pod.Status()
if err != nil {
- return PodStateErrored, err
+ return define.PodStateErrored, err
}
return CreatePodStatusResults(ctrStatuses)
}
@@ -33,45 +29,45 @@ func GetPodStatus(pod *libpod.Pod) (string, error) {
func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) {
ctrNum := len(ctrStatuses)
if ctrNum == 0 {
- return PodStateCreated, nil
+ return define.PodStateCreated, nil
}
statuses := map[string]int{
- PodStateStopped: 0,
- PodStateRunning: 0,
- PodStatePaused: 0,
- PodStateCreated: 0,
- PodStateErrored: 0,
+ define.PodStateStopped: 0,
+ define.PodStateRunning: 0,
+ define.PodStatePaused: 0,
+ define.PodStateCreated: 0,
+ define.PodStateErrored: 0,
}
for _, ctrStatus := range ctrStatuses {
switch ctrStatus {
case define.ContainerStateExited:
fallthrough
case define.ContainerStateStopped:
- statuses[PodStateStopped]++
+ statuses[define.PodStateStopped]++
case define.ContainerStateRunning:
- statuses[PodStateRunning]++
+ statuses[define.PodStateRunning]++
case define.ContainerStatePaused:
- statuses[PodStatePaused]++
+ statuses[define.PodStatePaused]++
case define.ContainerStateCreated, define.ContainerStateConfigured:
- statuses[PodStateCreated]++
+ statuses[define.PodStateCreated]++
default:
- statuses[PodStateErrored]++
+ statuses[define.PodStateErrored]++
}
}
switch {
- case statuses[PodStateRunning] > 0:
- return PodStateRunning, nil
- case statuses[PodStatePaused] == ctrNum:
- return PodStatePaused, nil
- case statuses[PodStateStopped] == ctrNum:
- return PodStateExited, nil
- case statuses[PodStateStopped] > 0:
- return PodStateStopped, nil
- case statuses[PodStateErrored] > 0:
- return PodStateErrored, nil
+ case statuses[define.PodStateRunning] > 0:
+ return define.PodStateRunning, nil
+ case statuses[define.PodStatePaused] == ctrNum:
+ return define.PodStatePaused, nil
+ case statuses[define.PodStateStopped] == ctrNum:
+ return define.PodStateExited, nil
+ case statuses[define.PodStateStopped] > 0:
+ return define.PodStateStopped, nil
+ case statuses[define.PodStateErrored] > 0:
+ return define.PodStateErrored, nil
default:
- return PodStateCreated, nil
+ return define.PodStateCreated, nil
}
}
@@ -140,4 +136,144 @@ func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) {
return portBindings, nil
}
+// GetPodsWithFilters uses the cliconfig to categorize if the latest pod is required.
+func GetPodsWithFilters(r *libpod.Runtime, filters string) ([]*libpod.Pod, error) {
+ filterFuncs, err := GenerateFilterFunction(r, strings.Split(filters, ","))
+ if err != nil {
+ return nil, err
+ }
+ return FilterAllPodsWithFilterFunc(r, filterFuncs...)
+}
+
+// FilterAllPodsWithFilterFunc retrieves all pods
+// Filters can be provided which will determine which pods are included in the
+// output. Multiple filters are handled by ANDing their output, so only pods
+// matching all filters are returned
+func FilterAllPodsWithFilterFunc(r *libpod.Runtime, filters ...libpod.PodFilter) ([]*libpod.Pod, error) {
+ pods, err := r.Pods(filters...)
+ if err != nil {
+ return nil, err
+ }
+ return pods, nil
+}
+
+// GenerateFilterFunction basically gets the filters based on the input by the user
+// and filter the pod list based on the criteria.
+func GenerateFilterFunction(r *libpod.Runtime, filters []string) ([]libpod.PodFilter, error) {
+ var filterFuncs []libpod.PodFilter
+ for _, f := range filters {
+ filterSplit := strings.SplitN(f, "=", 2)
+ if len(filterSplit) < 2 {
+ return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+ }
+ generatedFunc, err := generatePodFilterFuncs(filterSplit[0], filterSplit[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid filter")
+ }
+ filterFuncs = append(filterFuncs, generatedFunc)
+ }
+
+ return filterFuncs, nil
+}
+func generatePodFilterFuncs(filter, filterValue string) (
+ func(pod *libpod.Pod) bool, error) {
+ switch filter {
+ case "ctr-ids":
+ return func(p *libpod.Pod) bool {
+ ctrIds, err := p.AllContainersByID()
+ if err != nil {
+ return false
+ }
+ return util.StringInSlice(filterValue, ctrIds)
+ }, nil
+ case "ctr-names":
+ return func(p *libpod.Pod) bool {
+ ctrs, err := p.AllContainers()
+ if err != nil {
+ return false
+ }
+ for _, ctr := range ctrs {
+ if filterValue == ctr.Name() {
+ return true
+ }
+ }
+ return false
+ }, nil
+ case "ctr-number":
+ return func(p *libpod.Pod) bool {
+ ctrIds, err := p.AllContainersByID()
+ if err != nil {
+ return false
+ }
+
+ fVint, err2 := strconv.Atoi(filterValue)
+ if err2 != nil {
+ return false
+ }
+ return len(ctrIds) == fVint
+ }, nil
+ case "ctr-status":
+ if !util.StringInSlice(filterValue,
+ []string{"created", "restarting", "running", "paused",
+ "exited", "unknown"}) {
+ return nil, errors.Errorf("%s is not a valid status", filterValue)
+ }
+ return func(p *libpod.Pod) bool {
+ ctr_statuses, err := p.Status()
+ if err != nil {
+ return false
+ }
+ for _, ctr_status := range ctr_statuses {
+ state := ctr_status.String()
+ if ctr_status == define.ContainerStateConfigured {
+ state = "created"
+ }
+ if state == filterValue {
+ return true
+ }
+ }
+ return false
+ }, nil
+ case "id":
+ return func(p *libpod.Pod) bool {
+ return strings.Contains(p.ID(), filterValue)
+ }, nil
+ case "name":
+ return func(p *libpod.Pod) bool {
+ return strings.Contains(p.Name(), filterValue)
+ }, nil
+ case "status":
+ if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created"}) {
+ return nil, errors.Errorf("%s is not a valid pod status", filterValue)
+ }
+ return func(p *libpod.Pod) bool {
+ status, err := p.GetPodStatus()
+ if err != nil {
+ return false
+ }
+ if strings.ToLower(status) == filterValue {
+ return true
+ }
+ return false
+ }, nil
+ case "label":
+ var filterArray = strings.SplitN(filterValue, "=", 2)
+ var filterKey = filterArray[0]
+ if len(filterArray) > 1 {
+ filterValue = filterArray[1]
+ } else {
+ filterValue = ""
+ }
+ return func(p *libpod.Pod) bool {
+ for labelKey, labelValue := range p.Labels() {
+ if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
+ return true
+ }
+ }
+ return false
+ }, nil
+ }
+ return nil, errors.Errorf("%s is an invalid filter", filter)
+}
+
var DefaultKernelNamespaces = "cgroup,ipc,net,uts"