summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/imagefilters/filters.go24
-rw-r--r--cmd/podman/images.go3
-rw-r--r--cmd/podman/kill.go73
-rw-r--r--libpod/container_internal.go17
-rw-r--r--libpod/container_internal_linux.go48
-rw-r--r--libpod/runtime.go25
-rw-r--r--pkg/adapter/containers.go24
-rw-r--r--pkg/adapter/containers_remote.go25
-rw-r--r--pkg/rootless/rootless_linux.c4
-rw-r--r--test/e2e/images_test.go27
-rw-r--r--test/e2e/pod_infra_container_test.go17
11 files changed, 233 insertions, 54 deletions
diff --git a/cmd/podman/imagefilters/filters.go b/cmd/podman/imagefilters/filters.go
index d01eb7436..2932d61c0 100644
--- a/cmd/podman/imagefilters/filters.go
+++ b/cmd/podman/imagefilters/filters.go
@@ -2,11 +2,14 @@ package imagefilters
import (
"context"
+ "fmt"
+ "path/filepath"
"strings"
"time"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/inspect"
+ "github.com/sirupsen/logrus"
)
// ResultFilter is a mock function for image filtering
@@ -61,6 +64,27 @@ func LabelFilter(ctx context.Context, labelfilter string) ResultFilter {
}
}
+// ReferenceFilter allows you to filter by image name
+// Replacing all '/' with '|' so that filepath.Match() can work
+// '|' character is not valid in image name, so this is safe
+func ReferenceFilter(ctx context.Context, referenceFilter string) ResultFilter {
+ filter := fmt.Sprintf("*%s*", referenceFilter)
+ filter = strings.Replace(filter, "/", "|", -1)
+ return func(i *adapter.ContainerImage) bool {
+ for _, name := range i.Names() {
+ newName := strings.Replace(name, "/", "|", -1)
+ match, err := filepath.Match(filter, newName)
+ if err != nil {
+ logrus.Errorf("failed to match %s and %s, %q", name, referenceFilter, err)
+ }
+ if match {
+ return true
+ }
+ }
+ return false
+ }
+}
+
// OutputImageFilter allows you to filter by an a specific image name
func OutputImageFilter(userImage *adapter.ContainerImage) ResultFilter {
return func(i *adapter.ContainerImage) bool {
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 26e51bef7..a4f2e5e10 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -375,6 +375,9 @@ func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, filters []s
case "label":
labelFilter := strings.Join(splitFilter[1:], "=")
filterFuncs = append(filterFuncs, imagefilters.LabelFilter(ctx, labelFilter))
+ case "reference":
+ referenceFilter := strings.Join(splitFilter[1:], "=")
+ filterFuncs = append(filterFuncs, imagefilters.ReferenceFilter(ctx, referenceFilter))
default:
return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
}
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index 76d2516b7..82a257e23 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -2,16 +2,15 @@ package main
import (
"fmt"
- "syscall"
+ "reflect"
+
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/opentracing/opentracing-go"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/rootless"
"github.com/docker/docker/pkg/signal"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -51,54 +50,44 @@ func init() {
// killCmd kills one or more containers with a signal
func killCmd(c *cliconfig.KillValues) error {
- var (
- killFuncs []shared.ParallelWorkerInput
- killSignal uint = uint(syscall.SIGTERM)
- )
+ if c.Bool("trace") {
+ span, _ := opentracing.StartSpanFromContext(Ctx, "killCmd")
+ defer span.Finish()
+ }
+
+ // Check if the signalString provided by the user is valid
+ // Invalid signals will return err
+ killSignal, err := signal.ParseSignal(c.Signal)
+ if err != nil {
+ return err
+ }
rootless.SetSkipStorageSetup(true)
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
- if c.Signal != "" {
- // Check if the signalString provided by the user is valid
- // Invalid signals will return err
- sysSignal, err := signal.ParseSignal(c.Signal)
- if err != nil {
- return err
- }
- killSignal = uint(sysSignal)
- }
-
- containers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, libpod.ContainerStateRunning, "running")
+ ok, failures, err := runtime.KillContainers(getContext(), c, killSignal)
if err != nil {
- if len(containers) == 0 {
- return err
- }
- fmt.Println(err.Error())
+ return err
}
- for _, ctr := range containers {
- con := ctr
- f := func() error {
- return con.Kill(killSignal)
- }
-
- killFuncs = append(killFuncs, shared.ParallelWorkerInput{
- ContainerID: con.ID(),
- ParallelFunc: f,
- })
+ for _, id := range ok {
+ fmt.Println(id)
}
- maxWorkers := shared.Parallelize("kill")
- if c.GlobalIsSet("max-workers") {
- maxWorkers = c.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum workers to %d", maxWorkers)
+ if len(failures) > 0 {
+ keys := reflect.ValueOf(failures).MapKeys()
+ lastKey := keys[len(keys)-1].String()
+ lastErr := failures[lastKey]
+ delete(failures, lastKey)
- killErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, killFuncs)
- return printParallelOutput(killErrors, errCount)
+ for _, err := range failures {
+ outputError(err)
+ }
+ return lastErr
+ }
+ return nil
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index e3753d825..08945c410 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1231,6 +1231,23 @@ func (c *Container) writeStringToRundir(destFile, output string) (string, error)
return filepath.Join(c.state.DestinationRunDir, destFile), nil
}
+// appendStringToRundir appends the provided string to the runtimedir file
+func (c *Container) appendStringToRundir(destFile, output string) (string, error) {
+ destFileName := filepath.Join(c.state.RunDir, destFile)
+
+ f, err := os.OpenFile(destFileName, os.O_APPEND|os.O_WRONLY, 0600)
+ if err != nil {
+ return "", errors.Wrapf(err, "unable to open %s", destFileName)
+ }
+ defer f.Close()
+
+ if _, err := f.WriteString(output); err != nil {
+ return "", errors.Wrapf(err, "unable to write %s", destFileName)
+ }
+
+ return filepath.Join(c.state.DestinationRunDir, destFile), nil
+}
+
// Save OCI spec to disk, replacing any existing specs for the container
func (c *Container) saveSpec(spec *spec.Spec) error {
// If the OCI spec already exists, we need to replace it
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 0e9a5124e..5f9e5a20c 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -698,13 +698,29 @@ func (c *Container) makeBindMounts() error {
// If it doesn't, don't copy them
resolvPath, exists := bindMounts["/etc/resolv.conf"]
if exists {
-
c.state.BindMounts["/etc/resolv.conf"] = resolvPath
}
+
+ // check if dependency container has an /etc/hosts file
hostsPath, exists := bindMounts["/etc/hosts"]
- if exists {
- c.state.BindMounts["/etc/hosts"] = hostsPath
+ if !exists {
+ return errors.Errorf("error finding hosts file of dependency container %s for container %s", depCtr.ID(), c.ID())
+ }
+
+ depCtr.lock.Lock()
+ // generate a hosts file for the dependency container,
+ // based on either its old hosts file, or the default,
+ // and add the relevant information from the new container (hosts and IP)
+ hostsPath, err = depCtr.appendHosts(hostsPath, c)
+
+ if err != nil {
+ depCtr.lock.Unlock()
+ return errors.Wrapf(err, "error creating hosts file for container %s which depends on container %s", c.ID(), depCtr.ID())
}
+ depCtr.lock.Unlock()
+
+ // finally, save it in the new container
+ c.state.BindMounts["/etc/hosts"] = hostsPath
} else {
newResolv, err := c.generateResolvConf()
if err != nil {
@@ -712,7 +728,7 @@ func (c *Container) makeBindMounts() error {
}
c.state.BindMounts["/etc/resolv.conf"] = newResolv
- newHosts, err := c.generateHosts()
+ newHosts, err := c.generateHosts("/etc/hosts")
if err != nil {
return errors.Wrapf(err, "error creating hosts file for container %s", c.ID())
}
@@ -854,12 +870,28 @@ func (c *Container) generateResolvConf() (string, error) {
}
// generateHosts creates a containers hosts file
-func (c *Container) generateHosts() (string, error) {
- orig, err := ioutil.ReadFile("/etc/hosts")
+func (c *Container) generateHosts(path string) (string, error) {
+ orig, err := ioutil.ReadFile(path)
if err != nil {
- return "", errors.Wrapf(err, "unable to read /etc/hosts")
+ return "", errors.Wrapf(err, "unable to read %s", path)
}
hosts := string(orig)
+ hosts += c.getHosts()
+ return c.writeStringToRundir("hosts", hosts)
+}
+
+// appendHosts appends a container's config and state pertaining to hosts to a container's
+// local hosts file. netCtr is the container from which the netNS information is
+// taken.
+// path is the basis of the hosts file, into which netCtr's netNS information will be appended.
+func (c *Container) appendHosts(path string, netCtr *Container) (string, error) {
+ return c.appendStringToRundir("hosts", netCtr.getHosts())
+}
+
+// getHosts finds the pertinent information for a container's host file in its config and state
+// and returns a string in a format that can be written to the host file
+func (c *Container) getHosts() string {
+ var hosts string
if len(c.config.HostAdd) > 0 {
for _, host := range c.config.HostAdd {
// the host format has already been verified at this point
@@ -871,7 +903,7 @@ func (c *Container) generateHosts() (string, error) {
ipAddress := strings.Split(c.state.NetworkStatus[0].IPs[0].Address.String(), "/")[0]
hosts += fmt.Sprintf("%s\t%s\n", ipAddress, c.Hostname())
}
- return c.writeStringToRundir("hosts", hosts)
+ return hosts
}
// generatePasswd generates a container specific passwd file,
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 112b6820a..482cd9d73 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -333,7 +333,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
storageConf, err := util.GetDefaultStoreOptions()
if err != nil {
- return nil, errors.Wrapf(err, "error retrieving rootless storage config")
+ return nil, errors.Wrapf(err, "error retrieving storage config")
}
runtime.config.StorageConfig = storageConf
runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod")
@@ -365,8 +365,7 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
// containers/image uses XDG_RUNTIME_DIR to locate the auth file.
// So make sure the env variable is set.
- err = SetXdgRuntimeDir(runtimeDir)
- if err != nil {
+ if err := SetXdgRuntimeDir(runtimeDir); err != nil {
return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
}
@@ -475,13 +474,31 @@ func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime
// Set three fields not in the TOML config
runtime.config.StateType = defaultRuntimeConfig.StateType
runtime.config.OCIRuntime = defaultRuntimeConfig.OCIRuntime
- runtime.config.StorageConfig = storage.StoreOptions{}
+
+ storageConf, err := util.GetDefaultStoreOptions()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error retrieving storage config")
+ }
+ runtime.config.StorageConfig = storageConf
+ runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod")
+ runtime.config.VolumePath = filepath.Join(storageConf.GraphRoot, "volumes")
tmpDir, err := getDefaultTmpDir()
if err != nil {
return nil, err
}
runtime.config.TmpDir = tmpDir
+ if rootless.IsRootless() {
+ runtimeDir, err := util.GetRootlessRuntimeDir()
+ if err != nil {
+ return nil, err
+ }
+ // containers/image uses XDG_RUNTIME_DIR to locate the auth file.
+ // So make sure the env variable is set.
+ if err := SetXdgRuntimeDir(runtimeDir); err != nil {
+ return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
+ }
+ }
// Check to see if the given configuration file exists
if _, err := os.Stat(configPath); err != nil {
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 7514f30d2..fcce9bb86 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -4,6 +4,7 @@ package adapter
import (
"context"
+ "syscall"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
@@ -79,3 +80,26 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
}
return ok, failures, nil
}
+
+// KillContainers sends signal to container(s) based on CLI inputs.
+// Returns list of successful id(s), map of failed id(s) + error, or error not from container
+func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, c := range ctrs {
+ if err := c.Kill(uint(signal)); err == nil {
+ ok = append(ok, c.ID())
+ } else {
+ failures[c.ID()] = err
+ }
+ }
+ return ok, failures, nil
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index df40c8efd..45926ccf9 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -6,6 +6,7 @@ import (
"context"
"encoding/json"
"errors"
+ "syscall"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
@@ -148,6 +149,30 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
return ok, failures, nil
}
+// KillContainers sends signal to container(s) based on CLI inputs.
+// Returns list of successful id(s), map of failed id(s) + error, or error not from container
+func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, id := range ids {
+ killed, err := iopodman.KillContainer().Call(r.Conn, id, int64(signal))
+ if err != nil {
+ failures[id] = err
+ } else {
+ ok = append(ok, killed)
+ }
+ }
+ return ok, failures, nil
+}
+
// BatchContainerOp is wrapper func to mimic shared's function with a similar name meant for libpod
func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContainerStruct, error) {
// TODO If pod ps ever shows container's sizes, re-enable this code; otherwise it isn't needed
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index dfbc7fe33..41acd3475 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -32,7 +32,11 @@ syscall_setresgid (gid_t rgid, gid_t egid, gid_t sgid)
static int
syscall_clone (unsigned long flags, void *child_stack)
{
+#if defined(__s390__) || defined(__CRIS__)
+ return (int) syscall (__NR_clone, child_stack, flags);
+#else
return (int) syscall (__NR_clone, flags, child_stack);
+#endif
}
static char **
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index e26f4affd..4cf58e5bf 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -114,6 +114,33 @@ var _ = Describe("Podman images", func() {
Expect(len(session.OutputToStringArray())).To(Equal(1))
})
+ It("podman images filter reference", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
+ result := podmanTest.Podman([]string{"images", "-q", "-f", "reference=docker.io*"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(len(result.OutputToStringArray())).To(Equal(2))
+
+ retapline := podmanTest.Podman([]string{"images", "-f", "reference=a*pine"})
+ retapline.WaitWithDefaultTimeout()
+ Expect(retapline.ExitCode()).To(Equal(0))
+ Expect(len(retapline.OutputToStringArray())).To(Equal(2))
+ Expect(retapline.LineInOutputContains("alpine"))
+
+ retapline = podmanTest.Podman([]string{"images", "-f", "reference=alpine"})
+ retapline.WaitWithDefaultTimeout()
+ Expect(retapline.ExitCode()).To(Equal(0))
+ Expect(len(retapline.OutputToStringArray())).To(Equal(2))
+ Expect(retapline.LineInOutputContains("alpine"))
+
+ retnone := podmanTest.Podman([]string{"images", "-q", "-f", "reference=bogus"})
+ retnone.WaitWithDefaultTimeout()
+ Expect(retnone.ExitCode()).To(Equal(0))
+ Expect(len(retnone.OutputToStringArray())).To(Equal(0))
+ })
+
It("podman images filter before image", func() {
if podmanTest.RemoteTest {
Skip("Does not work on remote client")
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index ed5002ca7..d9e5d380a 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -360,4 +360,21 @@ var _ = Describe("Podman pod create", func() {
Expect(result.OutputToString()).To(ContainSubstring(infraID))
})
+
+ It("podman run --add-host in pod", func() {
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ podID := session.OutputToString()
+
+ // verify we can add a host to the infra's /etc/hosts
+ session = podmanTest.Podman([]string{"run", "--pod", podID, "--add-host", "foobar:127.0.0.1", BB, "ping", "-c", "1", "foobar"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ // verify we can see the other hosts of infra's /etc/hosts
+ session = podmanTest.Podman([]string{"run", "--pod", podID, BB, "ping", "-c", "1", "foobar"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
})