summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/containers/cleanup.go24
-rw-r--r--cmd/podman/containers/exec.go35
-rw-r--r--cmd/podman/images/list.go14
-rw-r--r--cmd/podman/images/prune.go6
-rw-r--r--cmd/podman/pods/create.go6
-rw-r--r--docs/source/markdown/podman-container-cleanup.1.md7
-rw-r--r--docs/source/markdown/podman-exec.1.md4
-rw-r--r--docs/tutorials/podman-derivative-api.md18
-rw-r--r--go.mod4
-rw-r--r--go.sum6
-rw-r--r--libpod/container_exec.go102
-rw-r--r--libpod/container_internal.go2
-rw-r--r--libpod/container_internal_linux.go2
-rw-r--r--libpod/container_internal_test.go2
-rw-r--r--libpod/define/healthchecks.go36
-rw-r--r--libpod/healthcheck.go65
-rw-r--r--libpod/image/filters.go3
-rw-r--r--libpod/oci.go15
-rw-r--r--libpod/oci_conmon_exec_linux.go599
-rw-r--r--libpod/oci_conmon_linux.go527
-rw-r--r--libpod/oci_missing.go5
-rw-r--r--libpod/runtime_ctr.go2
-rw-r--r--pkg/api/handlers/libpod/healthcheck.go24
-rw-r--r--pkg/api/handlers/utils/images.go33
-rw-r--r--pkg/domain/entities/containers.go2
-rw-r--r--pkg/domain/entities/engine_container.go3
-rw-r--r--pkg/domain/entities/images.go11
-rw-r--r--pkg/domain/infra/abi/containers.go84
-rw-r--r--pkg/domain/infra/abi/healthcheck.go7
-rw-r--r--pkg/domain/infra/abi/images_list.go24
-rw-r--r--pkg/domain/infra/abi/terminal/terminal_linux.go14
-rw-r--r--pkg/domain/infra/tunnel/containers.go32
-rw-r--r--pkg/domain/infra/tunnel/images.go16
-rw-r--r--pkg/specgen/generate/container_create.go21
-rw-r--r--pkg/util/mountOpts_linux.go2
-rw-r--r--pkg/varlinkapi/containers.go8
-rw-r--r--test/e2e/create_test.go2
-rw-r--r--test/e2e/exec_test.go27
-rw-r--r--test/e2e/healthcheck_run_test.go3
-rw-r--r--test/e2e/images_test.go29
-rw-r--r--test/e2e/init_test.go6
-rw-r--r--test/e2e/pod_create_test.go24
-rw-r--r--test/e2e/prune_test.go31
-rw-r--r--test/e2e/run_exit_test.go1
-rw-r--r--test/e2e/run_volume_test.go2
-rw-r--r--test/e2e/untag_test.go1
-rw-r--r--test/system/160-volumes.bats11
-rw-r--r--troubleshooting.md34
-rw-r--r--vendor/github.com/opencontainers/runtime-spec/specs-go/config.go55
-rw-r--r--vendor/github.com/opencontainers/runtime-spec/specs-go/version.go2
-rw-r--r--vendor/github.com/seccomp/containers-golang/.gitignore4
-rw-r--r--vendor/github.com/seccomp/containers-golang/LICENSE190
-rw-r--r--vendor/github.com/seccomp/containers-golang/Makefile22
-rw-r--r--vendor/github.com/seccomp/containers-golang/README.md12
-rw-r--r--vendor/github.com/seccomp/containers-golang/go.mod16
-rw-r--r--vendor/github.com/seccomp/containers-golang/go.sum48
-rw-r--r--vendor/github.com/seccomp/containers-golang/seccomp.json45
-rw-r--r--vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go36
-rw-r--r--vendor/github.com/seccomp/containers-golang/seccomp_linux.go46
-rw-r--r--vendor/github.com/seccomp/containers-golang/seccomp_unsupported.go19
-rw-r--r--vendor/github.com/seccomp/containers-golang/types.go5
-rw-r--r--vendor/github.com/seccomp/containers-golang/vendor.conf9
-rw-r--r--vendor/modules.txt4
63 files changed, 1618 insertions, 831 deletions
diff --git a/cmd/podman/containers/cleanup.go b/cmd/podman/containers/cleanup.go
index 2bcd1c1e9..619031208 100644
--- a/cmd/podman/containers/cleanup.go
+++ b/cmd/podman/containers/cleanup.go
@@ -7,6 +7,8 @@ import (
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -43,6 +45,7 @@ func init() {
flags := cleanupCommand.Flags()
flags.BoolVarP(&cleanupOptions.All, "all", "a", false, "Cleans up all containers")
flags.BoolVarP(&cleanupOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.StringVar(&cleanupOptions.Exec, "exec", "", "Clean up the given exec session instead of the container")
flags.BoolVar(&cleanupOptions.Remove, "rm", false, "After cleanup, remove the container entirely")
flags.BoolVar(&cleanupOptions.RemoveImage, "rmi", false, "After cleanup, remove the image entirely")
@@ -52,8 +55,26 @@ func cleanup(cmd *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
+
+ if cleanupOptions.Exec != "" {
+ switch {
+ case cleanupOptions.All:
+ return errors.Errorf("exec and all options conflict")
+ case len(args) > 1:
+ return errors.Errorf("cannot use exec option when more than one container is given")
+ case cleanupOptions.RemoveImage:
+ return errors.Errorf("exec and rmi options conflict")
+ }
+ }
+
responses, err := registry.ContainerEngine().ContainerCleanup(registry.GetContext(), args, cleanupOptions)
if err != nil {
+ // `podman container cleanup` is almost always run in the
+ // background. Our only way of relaying information to the user
+ // is via syslog.
+ // As such, we need to logrus.Errorf our errors to ensure they
+ // are properly printed if --syslog is set.
+ logrus.Errorf("Error running container cleanup: %v", err)
return err
}
for _, r := range responses {
@@ -62,12 +83,15 @@ func cleanup(cmd *cobra.Command, args []string) error {
continue
}
if r.RmErr != nil {
+ logrus.Errorf("Error removing container: %v", r.RmErr)
errs = append(errs, r.RmErr)
}
if r.RmiErr != nil {
+ logrus.Errorf("Error removing image: %v", r.RmiErr)
errs = append(errs, r.RmiErr)
}
if r.CleanErr != nil {
+ logrus.Errorf("Error cleaning up container: %v", r.CleanErr)
errs = append(errs, r.CleanErr)
}
}
diff --git a/cmd/podman/containers/exec.go b/cmd/podman/containers/exec.go
index 0992b3862..7554d6a93 100644
--- a/cmd/podman/containers/exec.go
+++ b/cmd/podman/containers/exec.go
@@ -2,9 +2,11 @@ package containers
import (
"bufio"
+ "fmt"
"os"
"github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
envLib "github.com/containers/libpod/pkg/env"
"github.com/pkg/errors"
@@ -41,10 +43,12 @@ var (
var (
envInput, envFile []string
execOpts entities.ExecOptions
+ execDetach bool
)
func execFlags(flags *pflag.FlagSet) {
flags.SetInterspersed(false)
+ flags.BoolVarP(&execDetach, "detach", "d", false, "Run the exec session in detached mode (backgrounded)")
flags.StringVar(&execOpts.DetachKeys, "detach-keys", containerConfig.DetachKeys(), "Select the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
flags.StringArrayVarP(&envInput, "env", "e", []string{}, "Set environment variables")
flags.StringSliceVar(&envFile, "env-file", []string{}, "Read in a file of environment variables")
@@ -106,16 +110,27 @@ func exec(cmd *cobra.Command, args []string) error {
}
execOpts.Envs = envLib.Join(execOpts.Envs, cliEnv)
- execOpts.Streams.OutputStream = os.Stdout
- execOpts.Streams.ErrorStream = os.Stderr
- if execOpts.Interactive {
- execOpts.Streams.InputStream = bufio.NewReader(os.Stdin)
- execOpts.Streams.AttachInput = true
+
+ if !execDetach {
+ streams := define.AttachStreams{}
+ streams.OutputStream = os.Stdout
+ streams.ErrorStream = os.Stderr
+ if execOpts.Interactive {
+ streams.InputStream = bufio.NewReader(os.Stdin)
+ streams.AttachInput = true
+ }
+ streams.AttachOutput = true
+ streams.AttachError = true
+
+ exitCode, err := registry.ContainerEngine().ContainerExec(registry.GetContext(), nameOrId, execOpts, streams)
+ registry.SetExitCode(exitCode)
+ return err
}
- execOpts.Streams.AttachOutput = true
- execOpts.Streams.AttachError = true
- exitCode, err := registry.ContainerEngine().ContainerExec(registry.GetContext(), nameOrId, execOpts)
- registry.SetExitCode(exitCode)
- return err
+ id, err := registry.ContainerEngine().ContainerExecDetached(registry.GetContext(), nameOrId, execOpts)
+ if err != nil {
+ return err
+ }
+ fmt.Println(id)
+ return nil
}
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index 83c039ed3..022c90f71 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -85,7 +85,7 @@ func images(cmd *cobra.Command, args []string) error {
return errors.New("cannot specify an image and a filter(s)")
}
- if len(listOptions.Filter) < 1 && len(args) > 0 {
+ if len(args) > 0 {
listOptions.Filter = append(listOptions.Filter, "reference="+args[0])
}
@@ -152,10 +152,16 @@ func writeTemplate(imageS []*entities.ImageSummary) error {
)
imgs := make([]imageReporter, 0, len(imageS))
for _, e := range imageS {
- for _, tag := range e.RepoTags {
- var h imageReporter
+ var h imageReporter
+ if len(e.RepoTags) > 0 {
+ for _, tag := range e.RepoTags {
+ h.ImageSummary = *e
+ h.Repository, h.Tag = tokenRepoTag(tag)
+ imgs = append(imgs, h)
+ }
+ } else {
h.ImageSummary = *e
- h.Repository, h.Tag = tokenRepoTag(tag)
+ h.Repository = "<none>"
imgs = append(imgs, h)
}
listFlag.readOnly = e.IsReadOnly()
diff --git a/cmd/podman/images/prune.go b/cmd/podman/images/prune.go
index 7c9e3eb61..676382a99 100644
--- a/cmd/podman/images/prune.go
+++ b/cmd/podman/images/prune.go
@@ -61,12 +61,6 @@ Are you sure you want to continue? [y/N] `)
}
}
- // TODO Remove once filter refactor is finished and url.Values rules :)
- for _, f := range filter {
- t := strings.SplitN(f, "=", 2)
- pruneOpts.Filters.Add(t[0], t[1])
- }
-
results, err := registry.ImageEngine().Prune(registry.GetContext(), pruneOpts)
if err != nil {
return err
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index e24cdef98..88b615fab 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -3,6 +3,7 @@ package pods
import (
"context"
"fmt"
+ "io/ioutil"
"os"
"strings"
@@ -147,6 +148,11 @@ func create(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
+ if len(podIDFile) > 0 {
+ if err = ioutil.WriteFile(podIDFile, []byte(response.Id), 0644); err != nil {
+ return errors.Wrapf(err, "failed to write pod ID to file %q", podIDFile)
+ }
+ }
fmt.Println(response.Id)
return nil
}
diff --git a/docs/source/markdown/podman-container-cleanup.1.md b/docs/source/markdown/podman-container-cleanup.1.md
index 66a6cff62..a200c2c36 100644
--- a/docs/source/markdown/podman-container-cleanup.1.md
+++ b/docs/source/markdown/podman-container-cleanup.1.md
@@ -16,6 +16,13 @@ Sometimes container's mount points and network stacks can remain if the podman c
Cleanup all containers.
+**--exec**=_session_
+
+Clean up an exec session for a single container.
+Can only be specified if a single container is being cleaned up (conflicts with **--all** as such).
+If **--rm** is not specified, temporary files for the exec session will be cleaned up; if it is, the exec session will be removed from the container.
+Conflicts with **--rmi** as the container is not being cleaned up so the image cannot be removed.
+
**--latest**, **-l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
to run containers such as CRI-O, the last started container could be from either of those methods.
diff --git a/docs/source/markdown/podman-exec.1.md b/docs/source/markdown/podman-exec.1.md
index 1bd10f9ba..b24a1f8aa 100644
--- a/docs/source/markdown/podman-exec.1.md
+++ b/docs/source/markdown/podman-exec.1.md
@@ -13,6 +13,10 @@ podman\-exec - Execute a command in a running container
## OPTIONS
+**--detach**
+
+Start the exec session, but do not attach to it. The command will run in the background and the exec session will be automatically removed when it completes. The **podman exec** command will print the ID of the exec session and exit immediately after it starts.
+
**--detach-keys**=*sequence*
Specify the key sequence for detaching a container. Format is a single character `[a-Z]` or one or more `ctrl-<value>` characters where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. Specifying "" will disable this feature. The default is *ctrl-p,ctrl-q*.
diff --git a/docs/tutorials/podman-derivative-api.md b/docs/tutorials/podman-derivative-api.md
index 065b0c4a9..8a1f40fc0 100644
--- a/docs/tutorials/podman-derivative-api.md
+++ b/docs/tutorials/podman-derivative-api.md
@@ -4,6 +4,20 @@
libpod today is a Golang library and a CLI. The choice of interface you make has advantages and disadvantages.
+Using the REST API
+---
+
+Advantages:
+
+ - Stable, versioned API
+ - Language-agnostic
+ - [Well-documented](http://docs.podman.io/en/latest/_static/api.html) API
+
+Disadvantages:
+
+ - Error handling is less verbose than Golang API
+ - May be slower
+
Running as a subprocess
---
@@ -35,12 +49,12 @@ Disadvantages:
Varlink
---
-Some code exists for this; splits the difference. Future uncertain.
+The Varlink API is presently deprecated. We do not recommend adopting it for new projects.
Making the choice
---
A good question to ask first is: Do you want users to be able to use `podman` to manipulate the containers created by your project?
-If so, that makes it more likely that you want to run `podman` as a subprocess. If you want a separate image store and a fundamentally
+If so, that makes it more likely that you want to run `podman` as a subprocess or using the HTTP API. If you want a separate image store and a fundamentally
different experience; if what you're doing with containers is quite different from those created by the `podman` CLI,
that may drive you towards vendoring.
diff --git a/go.mod b/go.mod
index f0e95464e..38da84700 100644
--- a/go.mod
+++ b/go.mod
@@ -40,14 +40,14 @@ require (
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/opencontainers/runc v1.0.0-rc9
- github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7
+ github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.5.1
github.com/opentracing/opentracing-go v1.1.0
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
github.com/rootless-containers/rootlesskit v0.9.4
- github.com/seccomp/containers-golang v0.0.0-20190312124753-8ca8945ccf5f
+ github.com/seccomp/containers-golang v0.4.1
github.com/sirupsen/logrus v1.6.0
github.com/spf13/cobra v0.0.7
github.com/spf13/pflag v1.0.5
diff --git a/go.sum b/go.sum
index b155a6407..733fbb2fe 100644
--- a/go.sum
+++ b/go.sum
@@ -375,9 +375,12 @@ github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rm
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7 h1:Dliu5QO+4JYWu/yMshaMU7G3JN2POGpwjJN7gjy10Go=
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 h1:9mv9SC7GWmRWE0J/+oD8w3GsN2KYGKtg6uwLN7hfP5E=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/opencontainers/runtime-tools v0.9.0 h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU=
github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/opencontainers/selinux v1.4.0/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
github.com/opencontainers/selinux v1.5.1 h1:jskKwSMFYqyTrHEuJgQoUlTcId0av64S6EWObrIfn5Y=
github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g=
@@ -435,6 +438,8 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8q
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/seccomp/containers-golang v0.0.0-20190312124753-8ca8945ccf5f h1:OtU/w6sBKmXYaw2KEODxjcYi3oPSyyslhgGFgIJVGAI=
github.com/seccomp/containers-golang v0.0.0-20190312124753-8ca8945ccf5f/go.mod h1:f/98/SnvAzhAEFQJ3u836FePXvcbE8BS0YGMQNn4mhA=
+github.com/seccomp/containers-golang v0.4.1 h1:6hsmsP8Y9T6PWKJELqAkRWkc6Te60+zK64avkjInd44=
+github.com/seccomp/containers-golang v0.4.1/go.mod h1:5fP9lgyYyklJ8fg8Geq193G1QLe0ikf34z+hZKIjmnE=
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -596,6 +601,7 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190921190940-14da1ac737cc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/libpod/container_exec.go b/libpod/container_exec.go
index 6ad767b4b..f2943b73c 100644
--- a/libpod/container_exec.go
+++ b/libpod/container_exec.go
@@ -62,6 +62,13 @@ type ExecConfig struct {
// given is the number that will be passed into the exec session,
// starting at 3.
PreserveFDs uint `json:"preserveFds,omitempty"`
+ // ExitCommand is the exec session's exit command.
+ // This command will be executed when the exec session exits.
+ // If unset, no command will be executed.
+ // Two arguments will be appended to the exit command by Libpod:
+ // The ID of the exec session, and the ID of the container the exec
+ // session is a part of (in that order).
+ ExitCommand []string `json:"exitCommand,omitempty"`
}
// ExecSession contains information on a single exec session attached to a given
@@ -191,6 +198,10 @@ func (c *Container) ExecCreate(config *ExecConfig) (string, error) {
return "", errors.Wrapf(err, "error copying exec configuration into exec session")
}
+ if len(session.Config.ExitCommand) > 0 {
+ session.Config.ExitCommand = append(session.Config.ExitCommand, []string{session.ID(), c.ID()}...)
+ }
+
if c.state.ExecSessions == nil {
c.state.ExecSessions = make(map[string]*ExecSession)
}
@@ -210,11 +221,52 @@ func (c *Container) ExecCreate(config *ExecConfig) (string, error) {
}
// ExecStart starts an exec session in the container, but does not attach to it.
-// Returns immediately upon starting the exec session.
+// Returns immediately upon starting the exec session, unlike other ExecStart
+// functions, which will only return when the exec session exits.
func (c *Container) ExecStart(sessionID string) error {
- // Will be implemented in part 2, migrating Start and implementing
- // detached Start.
- return define.ErrNotImplemented
+ if !c.batched {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if err := c.syncContainer(); err != nil {
+ return err
+ }
+ }
+
+ // Verify that we are in a good state to continue
+ if !c.ensureState(define.ContainerStateRunning) {
+ return errors.Wrapf(define.ErrCtrStateInvalid, "can only start exec sessions when their container is running")
+ }
+
+ session, ok := c.state.ExecSessions[sessionID]
+ if !ok {
+ return errors.Wrapf(define.ErrNoSuchExecSession, "container %s has no exec session with ID %s", c.ID(), sessionID)
+ }
+
+ if session.State != define.ExecStateCreated {
+ return errors.Wrapf(define.ErrExecSessionStateInvalid, "can only start created exec sessions, while container %s session %s state is %q", c.ID(), session.ID(), session.State.String())
+ }
+
+ logrus.Infof("Going to start container %s exec session %s and attach to it", c.ID(), session.ID())
+
+ opts, err := prepareForExec(c, session)
+ if err != nil {
+ return err
+ }
+
+ pid, err := c.ociRuntime.ExecContainerDetached(c, session.ID(), opts, session.Config.AttachStdin)
+ if err != nil {
+ return err
+ }
+
+ c.newContainerEvent(events.Exec)
+ logrus.Debugf("Successfully started exec session %s in container %s", session.ID(), c.ID())
+
+ // Update and save session to reflect PID/running
+ session.PID = pid
+ session.State = define.ExecStateRunning
+
+ return c.save()
}
// ExecStartAndAttach starts and attaches to an exec session in a container.
@@ -511,7 +563,27 @@ func (c *Container) ExecCleanup(sessionID string) error {
}
if session.State == define.ExecStateRunning {
- return errors.Wrapf(define.ErrExecSessionStateInvalid, "cannot clean up container %s exec session %s as it is running", c.ID(), session.ID())
+ // Check if the exec session is still running.
+ alive, err := c.ociRuntime.ExecUpdateStatus(c, session.ID())
+ if err != nil {
+ return err
+ }
+
+ if alive {
+ return errors.Wrapf(define.ErrExecSessionStateInvalid, "cannot clean up container %s exec session %s as it is running", c.ID(), session.ID())
+ }
+
+ exitCode, err := c.readExecExitCode(session.ID())
+ if err != nil {
+ return err
+ }
+ session.ExitCode = exitCode
+ session.PID = 0
+ session.State = define.ExecStateStopped
+
+ if err := c.save(); err != nil {
+ return err
+ }
}
logrus.Infof("Cleaning up container %s exec session %s", c.ID(), session.ID())
@@ -541,11 +613,11 @@ func (c *Container) ExecRemove(sessionID string, force bool) error {
// Update status of exec session if running, so we cna check if it
// stopped in the meantime.
if session.State == define.ExecStateRunning {
- stopped, err := c.ociRuntime.ExecUpdateStatus(c, session.ID())
+ running, err := c.ociRuntime.ExecUpdateStatus(c, session.ID())
if err != nil {
return err
}
- if stopped {
+ if !running {
session.State = define.ExecStateStopped
// TODO: should we retrieve exit code here?
// TODO: Might be worth saving state here.
@@ -800,13 +872,6 @@ func (c *Container) getActiveExecSessions() ([]string, error) {
continue
}
if !alive {
- if err := c.cleanupExecBundle(id); err != nil {
- if lastErr != nil {
- logrus.Errorf("Error checking container %s exec sessions: %v", c.ID(), lastErr)
- }
- lastErr = err
- }
-
_, isLegacy := c.state.LegacyExecSessions[id]
if isLegacy {
delete(c.state.LegacyExecSessions, id)
@@ -826,6 +891,12 @@ func (c *Container) getActiveExecSessions() ([]string, error) {
needSave = true
}
+ if err := c.cleanupExecBundle(id); err != nil {
+ if lastErr != nil {
+ logrus.Errorf("Error checking container %s exec sessions: %v", c.ID(), lastErr)
+ }
+ lastErr = err
+ }
} else {
activeSessions = append(activeSessions, id)
}
@@ -846,6 +917,8 @@ func (c *Container) getActiveExecSessions() ([]string, error) {
func (c *Container) removeAllExecSessions() error {
knownSessions := c.getKnownExecSessions()
+ logrus.Debugf("Removing all exec sessions for container %s", c.ID())
+
var lastErr error
for _, id := range knownSessions {
if err := c.ociRuntime.ExecStopContainer(c, id, c.StopTimeout()); err != nil {
@@ -910,6 +983,7 @@ func prepareForExec(c *Container, session *ExecSession) (*ExecOptions, error) {
opts.User = user
opts.PreserveFDs = session.Config.PreserveFDs
opts.DetachKeys = session.Config.DetachKeys
+ opts.ExitCommand = session.Config.ExitCommand
return opts, nil
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 909ad9851..43e873bd6 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1169,7 +1169,7 @@ func (c *Container) start() error {
c.state.State = define.ContainerStateRunning
if c.config.HealthCheckConfig != nil {
- if err := c.updateHealthStatus(HealthCheckStarting); err != nil {
+ if err := c.updateHealthStatus(define.HealthCheckStarting); err != nil {
logrus.Error(err)
}
if err := c.startTimer(); err != nil {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 8ee0fb456..2bd6099f0 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -1236,7 +1236,7 @@ func (c *Container) makeBindMounts() error {
}
// Add Secret Mounts
- secretMounts := secrets.SecretMountsWithUIDGID(c.config.MountLabel, c.state.RunDir, c.runtime.config.Containers.DefaultMountsFile, c.state.RunDir, c.RootUID(), c.RootGID(), rootless.IsRootless(), false)
+ secretMounts := secrets.SecretMountsWithUIDGID(c.config.MountLabel, c.state.RunDir, c.runtime.config.Containers.DefaultMountsFile, c.state.Mountpoint, c.RootUID(), c.RootGID(), rootless.IsRootless(), false)
for _, mount := range secretMounts {
if _, ok := c.state.BindMounts[mount.Destination]; !ok {
c.state.BindMounts[mount.Destination] = mount.Source
diff --git a/libpod/container_internal_test.go b/libpod/container_internal_test.go
index 5428504ef..fdf7c2e20 100644
--- a/libpod/container_internal_test.go
+++ b/libpod/container_internal_test.go
@@ -60,7 +60,7 @@ func TestPostDeleteHooks(t *testing.T) {
t.Fatal(err)
}
- stateRegexp := `{"ociVersion":"1\.0\.1-dev","id":"123abc","status":"stopped","bundle":"` + strings.TrimSuffix(os.TempDir(), "/") + `/libpod_test_[0-9]*","annotations":{"a":"b"}}`
+ stateRegexp := `{"ociVersion":"1\.0\.2-dev","id":"123abc","status":"stopped","bundle":"` + strings.TrimSuffix(os.TempDir(), "/") + `/libpod_test_[0-9]*","annotations":{"a":"b"}}`
for _, p := range []string{statePath, copyPath} {
path := p
t.Run(path, func(t *testing.T) {
diff --git a/libpod/define/healthchecks.go b/libpod/define/healthchecks.go
new file mode 100644
index 000000000..4114262b6
--- /dev/null
+++ b/libpod/define/healthchecks.go
@@ -0,0 +1,36 @@
+package define
+
+const (
+ // HealthCheckHealthy describes a healthy container
+ HealthCheckHealthy string = "healthy"
+ // HealthCheckUnhealthy describes an unhealthy container
+ HealthCheckUnhealthy string = "unhealthy"
+ // HealthCheckStarting describes the time between when the container starts
+ // and the start-period (time allowed for the container to start and application
+ // to be running) expires.
+ HealthCheckStarting string = "starting"
+)
+
+// HealthCheckStatus represents the current state of a container
+type HealthCheckStatus int
+
+const (
+ // HealthCheckSuccess means the health worked
+ HealthCheckSuccess HealthCheckStatus = iota
+ // HealthCheckFailure means the health ran and failed
+ HealthCheckFailure HealthCheckStatus = iota
+ // HealthCheckContainerStopped means the health check cannot
+ // be run because the container is stopped
+ HealthCheckContainerStopped HealthCheckStatus = iota
+ // HealthCheckContainerNotFound means the container could
+ // not be found in local store
+ HealthCheckContainerNotFound HealthCheckStatus = iota
+ // HealthCheckNotDefined means the container has no health
+ // check defined in it
+ HealthCheckNotDefined HealthCheckStatus = iota
+ // HealthCheckInternalError means some something failed obtaining or running
+ // a given health check
+ HealthCheckInternalError HealthCheckStatus = iota
+ // HealthCheckDefined means the healthcheck was found on the container
+ HealthCheckDefined HealthCheckStatus = iota
+)
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
index aec5fa4e0..0006b7c06 100644
--- a/libpod/healthcheck.go
+++ b/libpod/healthcheck.go
@@ -14,43 +14,12 @@ import (
"github.com/sirupsen/logrus"
)
-// HealthCheckStatus represents the current state of a container
-type HealthCheckStatus int
-
const (
- // HealthCheckSuccess means the health worked
- HealthCheckSuccess HealthCheckStatus = iota
- // HealthCheckFailure means the health ran and failed
- HealthCheckFailure HealthCheckStatus = iota
- // HealthCheckContainerStopped means the health check cannot
- // be run because the container is stopped
- HealthCheckContainerStopped HealthCheckStatus = iota
- // HealthCheckContainerNotFound means the container could
- // not be found in local store
- HealthCheckContainerNotFound HealthCheckStatus = iota
- // HealthCheckNotDefined means the container has no health
- // check defined in it
- HealthCheckNotDefined HealthCheckStatus = iota
- // HealthCheckInternalError means some something failed obtaining or running
- // a given health check
- HealthCheckInternalError HealthCheckStatus = iota
- // HealthCheckDefined means the healthcheck was found on the container
- HealthCheckDefined HealthCheckStatus = iota
-
// MaxHealthCheckNumberLogs is the maximum number of attempts we keep
// in the healthcheck history file
MaxHealthCheckNumberLogs int = 5
// MaxHealthCheckLogLength in characters
MaxHealthCheckLogLength = 500
-
- // HealthCheckHealthy describes a healthy container
- HealthCheckHealthy string = "healthy"
- // HealthCheckUnhealthy describes an unhealthy container
- HealthCheckUnhealthy string = "unhealthy"
- // HealthCheckStarting describes the time between when the container starts
- // and the start-period (time allowed for the container to start and application
- // to be running) expires.
- HealthCheckStarting string = "starting"
)
// hcWriteCloser allows us to use bufio as a WriteCloser
@@ -65,10 +34,10 @@ func (hcwc hcWriteCloser) Close() error {
// HealthCheck verifies the state and validity of the healthcheck configuration
// on the container and then executes the healthcheck
-func (r *Runtime) HealthCheck(name string) (HealthCheckStatus, error) {
+func (r *Runtime) HealthCheck(name string) (define.HealthCheckStatus, error) {
container, err := r.LookupContainer(name)
if err != nil {
- return HealthCheckContainerNotFound, errors.Wrapf(err, "unable to lookup %s to perform a health check", name)
+ return define.HealthCheckContainerNotFound, errors.Wrapf(err, "unable to lookup %s to perform a health check", name)
}
hcStatus, err := checkHealthCheckCanBeRun(container)
if err == nil {
@@ -78,7 +47,7 @@ func (r *Runtime) HealthCheck(name string) (HealthCheckStatus, error) {
}
// runHealthCheck runs the health check as defined by the container
-func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
+func (c *Container) runHealthCheck() (define.HealthCheckStatus, error) {
var (
newCommand []string
returnCode int
@@ -87,11 +56,11 @@ func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
)
hcCommand := c.HealthCheckConfig().Test
if len(hcCommand) < 1 {
- return HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
+ return define.HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
}
switch hcCommand[0] {
case "", "NONE":
- return HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
+ return define.HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
case "CMD":
newCommand = hcCommand[1:]
case "CMD-SHELL":
@@ -102,7 +71,7 @@ func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
newCommand = hcCommand
}
if len(newCommand) < 1 || newCommand[0] == "" {
- return HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
+ return define.HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
}
captureBuffer := bufio.NewWriter(&capture)
hcw := hcWriteCloser{
@@ -120,13 +89,13 @@ func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
logrus.Debugf("executing health check command %s for %s", strings.Join(newCommand, " "), c.ID())
timeStart := time.Now()
- hcResult := HealthCheckSuccess
+ hcResult := define.HealthCheckSuccess
config := new(ExecConfig)
config.Command = newCommand
_, hcErr := c.Exec(config, streams, nil)
if hcErr != nil {
errCause := errors.Cause(hcErr)
- hcResult = HealthCheckFailure
+ hcResult = define.HealthCheckFailure
if errCause == define.ErrOCIRuntimeNotFound ||
errCause == define.ErrOCIRuntimePermissionDenied ||
errCause == define.ErrOCIRuntime {
@@ -154,7 +123,7 @@ func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
if timeEnd.Sub(timeStart) > c.HealthCheckConfig().Timeout {
returnCode = -1
- hcResult = HealthCheckFailure
+ hcResult = define.HealthCheckFailure
hcErr = errors.Errorf("healthcheck command exceeded timeout of %s", c.HealthCheckConfig().Timeout.String())
}
hcl := newHealthCheckLog(timeStart, timeEnd, returnCode, eventLog)
@@ -164,18 +133,18 @@ func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
return hcResult, hcErr
}
-func checkHealthCheckCanBeRun(c *Container) (HealthCheckStatus, error) {
+func checkHealthCheckCanBeRun(c *Container) (define.HealthCheckStatus, error) {
cstate, err := c.State()
if err != nil {
- return HealthCheckInternalError, err
+ return define.HealthCheckInternalError, err
}
if cstate != define.ContainerStateRunning {
- return HealthCheckContainerStopped, errors.Errorf("container %s is not running", c.ID())
+ return define.HealthCheckContainerStopped, errors.Errorf("container %s is not running", c.ID())
}
if !c.HasHealthCheck() {
- return HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
+ return define.HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
}
- return HealthCheckDefined, nil
+ return define.HealthCheckDefined, nil
}
func newHealthCheckLog(start, end time.Time, exitCode int, log string) define.HealthCheckLog {
@@ -210,18 +179,18 @@ func (c *Container) updateHealthCheckLog(hcl define.HealthCheckLog, inStartPerio
}
if hcl.ExitCode == 0 {
// set status to healthy, reset failing state to 0
- healthCheck.Status = HealthCheckHealthy
+ healthCheck.Status = define.HealthCheckHealthy
healthCheck.FailingStreak = 0
} else {
if len(healthCheck.Status) < 1 {
- healthCheck.Status = HealthCheckHealthy
+ healthCheck.Status = define.HealthCheckHealthy
}
if !inStartPeriod {
// increment failing streak
healthCheck.FailingStreak += 1
// if failing streak > retries, then status to unhealthy
if healthCheck.FailingStreak >= c.HealthCheckConfig().Retries {
- healthCheck.Status = HealthCheckUnhealthy
+ healthCheck.Status = define.HealthCheckUnhealthy
}
}
}
diff --git a/libpod/image/filters.go b/libpod/image/filters.go
index 8ca3526a0..747eba165 100644
--- a/libpod/image/filters.go
+++ b/libpod/image/filters.go
@@ -170,8 +170,7 @@ func (ir *Runtime) createFilterFuncs(filters []string, img *Image) ([]ResultFilt
labelFilter := strings.Join(splitFilter[1:], "=")
filterFuncs = append(filterFuncs, LabelFilter(ctx, labelFilter))
case "reference":
- referenceFilter := strings.Join(splitFilter[1:], "=")
- filterFuncs = append(filterFuncs, ReferenceFilter(ctx, referenceFilter))
+ filterFuncs = append(filterFuncs, ReferenceFilter(ctx, splitFilter[1]))
case "id":
filterFuncs = append(filterFuncs, IdFilter(splitFilter[1]))
default:
diff --git a/libpod/oci.go b/libpod/oci.go
index 6b1886f80..7c5218319 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -68,10 +68,10 @@ type OCIRuntime interface {
AttachResize(ctr *Container, newSize remotecommand.TerminalSize) error
// ExecContainer executes a command in a running container.
- // Returns an int (exit code), error channel (errors from attach), and
- // error (errors that occurred attempting to start the exec session).
- // This returns once the exec session is running - not once it has
- // completed, as one might expect. The attach session will remain
+ // Returns an int (PID of exec session), error channel (errors from
+ // attach), and error (errors that occurred attempting to start the exec
+ // session). This returns once the exec session is running - not once it
+ // has completed, as one might expect. The attach session will remain
// running, in a goroutine that will return via the chan error in the
// return signature.
ExecContainer(ctr *Container, sessionID string, options *ExecOptions, streams *define.AttachStreams) (int, chan error, error)
@@ -81,6 +81,10 @@ type OCIRuntime interface {
// start, with a goroutine running in the background to handle attach).
// The HTTP attach itself maintains the same invariants as HTTPAttach.
ExecContainerHTTP(ctr *Container, sessionID string, options *ExecOptions, httpConn net.Conn, httpBuf *bufio.ReadWriter, streams *HTTPAttachStreams, cancel <-chan bool) (int, chan error, error)
+ // ExecContainerDetached executes a command in a running container, but
+ // does not attach to it. Returns the PID of the exec session and an
+ // error (if starting the exec session failed)
+ ExecContainerDetached(ctr *Container, sessionID string, options *ExecOptions, stdin bool) (int, error)
// ExecAttachResize resizes the terminal of a running exec session. Only
// allowed with sessions that were created with a TTY.
ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error
@@ -165,6 +169,9 @@ type ExecOptions struct {
// If provided but set to "", detaching from the container will be
// disabled.
DetachKeys *string
+ // ExitCommand is a command that will be run after the exec session
+ // exits.
+ ExitCommand []string
}
// HTTPAttachStreams informs the HTTPAttach endpoint which of the container's
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
new file mode 100644
index 000000000..51819f90a
--- /dev/null
+++ b/libpod/oci_conmon_exec_linux.go
@@ -0,0 +1,599 @@
+package libpod
+
+import (
+ "bufio"
+ "fmt"
+ "net"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "syscall"
+ "time"
+
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/errorhandling"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/containers/libpod/utils"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/unix"
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+// ExecContainer executes a command in a running container
+func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options *ExecOptions, streams *define.AttachStreams) (int, chan error, error) {
+ if options == nil {
+ return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide an ExecOptions struct to ExecContainer")
+ }
+ if len(options.Cmd) == 0 {
+ return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide a command to execute")
+ }
+
+ if sessionID == "" {
+ return -1, nil, errors.Wrapf(define.ErrEmptyID, "must provide a session ID for exec")
+ }
+
+ // TODO: Should we default this to false?
+ // Or maybe make streams mandatory?
+ attachStdin := true
+ if streams != nil {
+ attachStdin = streams.AttachInput
+ }
+
+ var ociLog string
+ if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON {
+ ociLog = c.execOCILog(sessionID)
+ }
+
+ execCmd, pipes, err := r.startExec(c, sessionID, options, attachStdin, ociLog)
+ if err != nil {
+ return -1, nil, err
+ }
+
+ // Only close sync pipe. Start and attach are consumed in the attach
+ // goroutine.
+ defer func() {
+ if pipes.syncPipe != nil && !pipes.syncClosed {
+ errorhandling.CloseQuiet(pipes.syncPipe)
+ pipes.syncClosed = true
+ }
+ }()
+
+ // TODO Only create if !detach
+ // Attach to the container before starting it
+ attachChan := make(chan error)
+ go func() {
+ // attachToExec is responsible for closing pipes
+ attachChan <- c.attachToExec(streams, options.DetachKeys, sessionID, pipes.startPipe, pipes.attachPipe)
+ close(attachChan)
+ }()
+
+ if err := execCmd.Wait(); err != nil {
+ return -1, nil, errors.Wrapf(err, "cannot run conmon")
+ }
+
+ pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
+
+ return pid, attachChan, err
+}
+
+// ExecContainerHTTP executes a new command in an existing container and
+// forwards its standard streams over an attach
+func (r *ConmonOCIRuntime) ExecContainerHTTP(ctr *Container, sessionID string, options *ExecOptions, httpConn net.Conn, httpBuf *bufio.ReadWriter, streams *HTTPAttachStreams, cancel <-chan bool) (int, chan error, error) {
+ if streams != nil {
+ if !streams.Stdin && !streams.Stdout && !streams.Stderr {
+ return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
+ }
+ }
+
+ if options == nil {
+ return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide exec options to ExecContainerHTTP")
+ }
+
+ detachString := config.DefaultDetachKeys
+ if options.DetachKeys != nil {
+ detachString = *options.DetachKeys
+ }
+ detachKeys, err := processDetachKeys(detachString)
+ if err != nil {
+ return -1, nil, err
+ }
+
+ // TODO: Should we default this to false?
+ // Or maybe make streams mandatory?
+ attachStdin := true
+ if streams != nil {
+ attachStdin = streams.Stdin
+ }
+
+ var ociLog string
+ if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON {
+ ociLog = ctr.execOCILog(sessionID)
+ }
+
+ execCmd, pipes, err := r.startExec(ctr, sessionID, options, attachStdin, ociLog)
+ if err != nil {
+ return -1, nil, err
+ }
+
+ // Only close sync pipe. Start and attach are consumed in the attach
+ // goroutine.
+ defer func() {
+ if pipes.syncPipe != nil && !pipes.syncClosed {
+ errorhandling.CloseQuiet(pipes.syncPipe)
+ pipes.syncClosed = true
+ }
+ }()
+
+ attachChan := make(chan error)
+ go func() {
+ // attachToExec is responsible for closing pipes
+ attachChan <- attachExecHTTP(ctr, sessionID, httpBuf, streams, pipes, detachKeys, options.Terminal, cancel)
+ close(attachChan)
+ }()
+
+ // Wait for conmon to succeed, when return.
+ if err := execCmd.Wait(); err != nil {
+ return -1, nil, errors.Wrapf(err, "cannot run conmon")
+ }
+
+ pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
+
+ return pid, attachChan, err
+}
+
+// ExecContainerDetached executes a command in a running container, but does
+// not attach to it.
+func (r *ConmonOCIRuntime) ExecContainerDetached(ctr *Container, sessionID string, options *ExecOptions, stdin bool) (int, error) {
+ if options == nil {
+ return -1, errors.Wrapf(define.ErrInvalidArg, "must provide exec options to ExecContainerHTTP")
+ }
+
+ var ociLog string
+ if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON {
+ ociLog = ctr.execOCILog(sessionID)
+ }
+
+ execCmd, pipes, err := r.startExec(ctr, sessionID, options, stdin, ociLog)
+ if err != nil {
+ return -1, err
+ }
+
+ defer func() {
+ pipes.cleanup()
+ }()
+
+ // Wait for Conmon to tell us we're ready to attach.
+ // We aren't actually *going* to attach, but this means that we're good
+ // to proceed.
+ if _, err := readConmonPipeData(pipes.attachPipe, ""); err != nil {
+ return -1, err
+ }
+
+ // Start the exec session
+ if err := writeConmonPipeData(pipes.startPipe); err != nil {
+ return -1, err
+ }
+
+ // Wait for conmon to succeed, when return.
+ if err := execCmd.Wait(); err != nil {
+ return -1, errors.Wrapf(err, "cannot run conmon")
+ }
+
+ pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
+
+ return pid, err
+}
+
+// ExecAttachResize resizes the TTY of the given exec session.
+func (r *ConmonOCIRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
+ controlFile, err := openControlFile(ctr, ctr.execBundlePath(sessionID))
+ if err != nil {
+ return err
+ }
+ defer controlFile.Close()
+
+ if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, newSize.Height, newSize.Width); err != nil {
+ return errors.Wrapf(err, "failed to write to ctl file to resize terminal")
+ }
+
+ return nil
+}
+
+// ExecStopContainer stops a given exec session in a running container.
+func (r *ConmonOCIRuntime) ExecStopContainer(ctr *Container, sessionID string, timeout uint) error {
+ pid, err := ctr.getExecSessionPID(sessionID)
+ if err != nil {
+ return err
+ }
+
+ logrus.Debugf("Going to stop container %s exec session %s", ctr.ID(), sessionID)
+
+ // Is the session dead?
+ // Ping the PID with signal 0 to see if it still exists.
+ if err := unix.Kill(pid, 0); err != nil {
+ if err == unix.ESRCH {
+ return nil
+ }
+ return errors.Wrapf(err, "error pinging container %s exec session %s PID %d with signal 0", ctr.ID(), sessionID, pid)
+ }
+
+ if timeout > 0 {
+ // Use SIGTERM by default, then SIGSTOP after timeout.
+ logrus.Debugf("Killing exec session %s (PID %d) of container %s with SIGTERM", sessionID, pid, ctr.ID())
+ if err := unix.Kill(pid, unix.SIGTERM); err != nil {
+ if err == unix.ESRCH {
+ return nil
+ }
+ return errors.Wrapf(err, "error killing container %s exec session %s PID %d with SIGTERM", ctr.ID(), sessionID, pid)
+ }
+
+ // Wait for the PID to stop
+ if err := waitPidStop(pid, time.Duration(timeout)*time.Second); err != nil {
+ logrus.Warnf("Timed out waiting for container %s exec session %s to stop, resorting to SIGKILL", ctr.ID(), sessionID)
+ } else {
+ // No error, container is dead
+ return nil
+ }
+ }
+
+ // SIGTERM did not work. On to SIGKILL.
+ logrus.Debugf("Killing exec session %s (PID %d) of container %s with SIGKILL", sessionID, pid, ctr.ID())
+ if err := unix.Kill(pid, unix.SIGTERM); err != nil {
+ if err == unix.ESRCH {
+ return nil
+ }
+ return errors.Wrapf(err, "error killing container %s exec session %s PID %d with SIGKILL", ctr.ID(), sessionID, pid)
+ }
+
+ // Wait for the PID to stop
+ if err := waitPidStop(pid, killContainerTimeout*time.Second); err != nil {
+ return errors.Wrapf(err, "timed out waiting for container %s exec session %s PID %d to stop after SIGKILL", ctr.ID(), sessionID, pid)
+ }
+
+ return nil
+}
+
+// ExecUpdateStatus checks if the given exec session is still running.
+func (r *ConmonOCIRuntime) ExecUpdateStatus(ctr *Container, sessionID string) (bool, error) {
+ pid, err := ctr.getExecSessionPID(sessionID)
+ if err != nil {
+ return false, err
+ }
+
+ logrus.Debugf("Checking status of container %s exec session %s", ctr.ID(), sessionID)
+
+ // Is the session dead?
+ // Ping the PID with signal 0 to see if it still exists.
+ if err := unix.Kill(pid, 0); err != nil {
+ if err == unix.ESRCH {
+ return false, nil
+ }
+ return false, errors.Wrapf(err, "error pinging container %s exec session %s PID %d with signal 0", ctr.ID(), sessionID, pid)
+ }
+
+ return true, nil
+}
+
+// ExecContainerCleanup cleans up files created when a command is run via
+// ExecContainer. This includes the attach socket for the exec session.
+func (r *ConmonOCIRuntime) ExecContainerCleanup(ctr *Container, sessionID string) error {
+ // Clean up the sockets dir. Issue #3962
+ // Also ignore if it doesn't exist for some reason; hence the conditional return below
+ if err := os.RemoveAll(filepath.Join(r.socketsDir, sessionID)); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ return nil
+}
+
+// ExecAttachSocketPath is the path to a container's exec session attach socket.
+func (r *ConmonOCIRuntime) ExecAttachSocketPath(ctr *Container, sessionID string) (string, error) {
+ // We don't even use container, so don't validity check it
+ if sessionID == "" {
+ return "", errors.Wrapf(define.ErrInvalidArg, "must provide a valid session ID to get attach socket path")
+ }
+
+ return filepath.Join(r.socketsDir, sessionID, "attach"), nil
+}
+
+// This contains pipes used by the exec API.
+type execPipes struct {
+ syncPipe *os.File
+ syncClosed bool
+ startPipe *os.File
+ startClosed bool
+ attachPipe *os.File
+ attachClosed bool
+}
+
+func (p *execPipes) cleanup() {
+ if p.syncPipe != nil && !p.syncClosed {
+ errorhandling.CloseQuiet(p.syncPipe)
+ p.syncClosed = true
+ }
+ if p.startPipe != nil && !p.startClosed {
+ errorhandling.CloseQuiet(p.startPipe)
+ p.startClosed = true
+ }
+ if p.attachPipe != nil && !p.attachClosed {
+ errorhandling.CloseQuiet(p.attachPipe)
+ p.attachClosed = true
+ }
+}
+
+// Start an exec session's conmon parent from the given options.
+func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *ExecOptions, attachStdin bool, ociLog string) (_ *exec.Cmd, _ *execPipes, deferredErr error) {
+ pipes := new(execPipes)
+
+ if options == nil {
+ return nil, nil, errors.Wrapf(define.ErrInvalidArg, "must provide an ExecOptions struct to ExecContainer")
+ }
+ if len(options.Cmd) == 0 {
+ return nil, nil, errors.Wrapf(define.ErrInvalidArg, "must provide a command to execute")
+ }
+
+ if sessionID == "" {
+ return nil, nil, errors.Wrapf(define.ErrEmptyID, "must provide a session ID for exec")
+ }
+
+ // create sync pipe to receive the pid
+ parentSyncPipe, childSyncPipe, err := newPipe()
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "error creating socket pair")
+ }
+ pipes.syncPipe = parentSyncPipe
+
+ defer func() {
+ if deferredErr != nil {
+ pipes.cleanup()
+ }
+ }()
+
+ // create start pipe to set the cgroup before running
+ // attachToExec is responsible for closing parentStartPipe
+ childStartPipe, parentStartPipe, err := newPipe()
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "error creating socket pair")
+ }
+ pipes.startPipe = parentStartPipe
+
+ // create the attach pipe to allow attach socket to be created before
+ // $RUNTIME exec starts running. This is to make sure we can capture all output
+ // from the process through that socket, rather than half reading the log, half attaching to the socket
+ // attachToExec is responsible for closing parentAttachPipe
+ parentAttachPipe, childAttachPipe, err := newPipe()
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "error creating socket pair")
+ }
+ pipes.attachPipe = parentAttachPipe
+
+ childrenClosed := false
+ defer func() {
+ if !childrenClosed {
+ errorhandling.CloseQuiet(childSyncPipe)
+ errorhandling.CloseQuiet(childAttachPipe)
+ errorhandling.CloseQuiet(childStartPipe)
+ }
+ }()
+
+ runtimeDir, err := util.GetRuntimeDir()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ finalEnv := make([]string, 0, len(options.Env))
+ for k, v := range options.Env {
+ finalEnv = append(finalEnv, fmt.Sprintf("%s=%s", k, v))
+ }
+
+ processFile, err := prepareProcessExec(c, options.Cmd, finalEnv, options.Terminal, options.Cwd, options.User, sessionID)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ args := r.sharedConmonArgs(c, sessionID, c.execBundlePath(sessionID), c.execPidPath(sessionID), c.execLogPath(sessionID), c.execExitFileDir(sessionID), ociLog, "")
+
+ if options.PreserveFDs > 0 {
+ args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", options.PreserveFDs))...)
+ }
+
+ for _, capability := range options.CapAdd {
+ args = append(args, formatRuntimeOpts("--cap", capability)...)
+ }
+
+ if options.Terminal {
+ args = append(args, "-t")
+ }
+
+ if attachStdin {
+ args = append(args, "-i")
+ }
+
+ // Append container ID and command
+ args = append(args, "-e")
+ // TODO make this optional when we can detach
+ args = append(args, "--exec-attach")
+ args = append(args, "--exec-process-spec", processFile.Name())
+
+ if len(options.ExitCommand) > 0 {
+ args = append(args, "--exit-command", options.ExitCommand[0])
+ for _, arg := range options.ExitCommand[1:] {
+ args = append(args, []string{"--exit-command-arg", arg}...)
+ }
+ }
+
+ logrus.WithFields(logrus.Fields{
+ "args": args,
+ }).Debugf("running conmon: %s", r.conmonPath)
+ // TODO: Need to pass this back so we can wait on it.
+ execCmd := exec.Command(r.conmonPath, args...)
+
+ // TODO: This is commented because it doesn't make much sense in HTTP
+ // attach, and I'm not certain it does for non-HTTP attach as well.
+ // if streams != nil {
+ // // Don't add the InputStream to the execCmd. Instead, the data should be passed
+ // // through CopyDetachable
+ // if streams.AttachOutput {
+ // execCmd.Stdout = options.Streams.OutputStream
+ // }
+ // if streams.AttachError {
+ // execCmd.Stderr = options.Streams.ErrorStream
+ // }
+ // }
+
+ conmonEnv, extraFiles, err := r.configureConmonEnv(runtimeDir)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if options.PreserveFDs > 0 {
+ for fd := 3; fd < int(3+options.PreserveFDs); fd++ {
+ execCmd.ExtraFiles = append(execCmd.ExtraFiles, os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)))
+ }
+ }
+
+ // we don't want to step on users fds they asked to preserve
+ // Since 0-2 are used for stdio, start the fds we pass in at preserveFDs+3
+ execCmd.Env = r.conmonEnv
+ execCmd.Env = append(execCmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", options.PreserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", options.PreserveFDs+4), fmt.Sprintf("_OCI_ATTACHPIPE=%d", options.PreserveFDs+5))
+ execCmd.Env = append(execCmd.Env, conmonEnv...)
+
+ execCmd.ExtraFiles = append(execCmd.ExtraFiles, childSyncPipe, childStartPipe, childAttachPipe)
+ execCmd.ExtraFiles = append(execCmd.ExtraFiles, extraFiles...)
+ execCmd.Dir = c.execBundlePath(sessionID)
+ execCmd.SysProcAttr = &syscall.SysProcAttr{
+ Setpgid: true,
+ }
+
+ err = startCommandGivenSelinux(execCmd)
+
+ // We don't need children pipes on the parent side
+ errorhandling.CloseQuiet(childSyncPipe)
+ errorhandling.CloseQuiet(childAttachPipe)
+ errorhandling.CloseQuiet(childStartPipe)
+ childrenClosed = true
+
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "cannot start container %s", c.ID())
+ }
+ if err := r.moveConmonToCgroupAndSignal(c, execCmd, parentStartPipe); err != nil {
+ return nil, nil, err
+ }
+
+ if options.PreserveFDs > 0 {
+ for fd := 3; fd < int(3+options.PreserveFDs); fd++ {
+ // These fds were passed down to the runtime. Close them
+ // and not interfere
+ if err := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close(); err != nil {
+ logrus.Debugf("unable to close file fd-%d", fd)
+ }
+ }
+ }
+
+ return execCmd, pipes, nil
+}
+
+// Attach to a container over HTTP
+func attachExecHTTP(c *Container, sessionID string, httpBuf *bufio.ReadWriter, streams *HTTPAttachStreams, pipes *execPipes, detachKeys []byte, isTerminal bool, cancel <-chan bool) error {
+ if pipes == nil || pipes.startPipe == nil || pipes.attachPipe == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "must provide a start and attach pipe to finish an exec attach")
+ }
+
+ defer func() {
+ if !pipes.startClosed {
+ errorhandling.CloseQuiet(pipes.startPipe)
+ pipes.startClosed = true
+ }
+ if !pipes.attachClosed {
+ errorhandling.CloseQuiet(pipes.attachPipe)
+ pipes.attachClosed = true
+ }
+ }()
+
+ logrus.Debugf("Attaching to container %s exec session %s", c.ID(), sessionID)
+
+ // set up the socket path, such that it is the correct length and location for exec
+ sockPath, err := c.execAttachSocketPath(sessionID)
+ if err != nil {
+ return err
+ }
+ socketPath := buildSocketPath(sockPath)
+
+ // 2: read from attachFd that the parent process has set up the console socket
+ if _, err := readConmonPipeData(pipes.attachPipe, ""); err != nil {
+ return err
+ }
+
+ // 2: then attach
+ conn, err := net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: socketPath, Net: "unixpacket"})
+ if err != nil {
+ return errors.Wrapf(err, "failed to connect to container's attach socket: %v", socketPath)
+ }
+ defer func() {
+ if err := conn.Close(); err != nil {
+ logrus.Errorf("unable to close socket: %q", err)
+ }
+ }()
+
+ // Make a channel to pass errors back
+ errChan := make(chan error)
+
+ attachStdout := true
+ attachStderr := true
+ attachStdin := true
+ if streams != nil {
+ attachStdout = streams.Stdout
+ attachStderr = streams.Stderr
+ attachStdin = streams.Stdin
+ }
+
+ // Next, STDIN. Avoid entirely if attachStdin unset.
+ if attachStdin {
+ go func() {
+ logrus.Debugf("Beginning STDIN copy")
+ _, err := utils.CopyDetachable(conn, httpBuf, detachKeys)
+ logrus.Debugf("STDIN copy completed")
+ errChan <- err
+ }()
+ }
+
+ // 4: send start message to child
+ if err := writeConmonPipeData(pipes.startPipe); err != nil {
+ return err
+ }
+
+ // Handle STDOUT/STDERR *after* start message is sent
+ go func() {
+ var err error
+ if isTerminal {
+ // Hack: return immediately if attachStdout not set to
+ // emulate Docker.
+ // Basically, when terminal is set, STDERR goes nowhere.
+ // Everything does over STDOUT.
+ // Therefore, if not attaching STDOUT - we'll never copy
+ // anything from here.
+ logrus.Debugf("Performing terminal HTTP attach for container %s", c.ID())
+ if attachStdout {
+ err = httpAttachTerminalCopy(conn, httpBuf, c.ID())
+ }
+ } else {
+ logrus.Debugf("Performing non-terminal HTTP attach for container %s", c.ID())
+ err = httpAttachNonTerminalCopy(conn, httpBuf, c.ID(), attachStdin, attachStdout, attachStderr)
+ }
+ errChan <- err
+ logrus.Debugf("STDOUT/ERR copy completed")
+ }()
+
+ if cancel != nil {
+ select {
+ case err := <-errChan:
+ return err
+ case <-cancel:
+ return nil
+ }
+ } else {
+ var connErr error = <-errChan
+ return connErr
+ }
+}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 7ba36fe7c..9c92b036e 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -635,229 +635,6 @@ func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize remotecommand.Te
return nil
}
-// ExecContainer executes a command in a running container
-func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options *ExecOptions, streams *define.AttachStreams) (int, chan error, error) {
- if options == nil {
- return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide an ExecOptions struct to ExecContainer")
- }
- if len(options.Cmd) == 0 {
- return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide a command to execute")
- }
-
- if sessionID == "" {
- return -1, nil, errors.Wrapf(define.ErrEmptyID, "must provide a session ID for exec")
- }
-
- // TODO: Should we default this to false?
- // Or maybe make streams mandatory?
- attachStdin := true
- if streams != nil {
- attachStdin = streams.AttachInput
- }
-
- var ociLog string
- if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON {
- ociLog = c.execOCILog(sessionID)
- }
-
- execCmd, pipes, err := r.startExec(c, sessionID, options, attachStdin, ociLog)
- if err != nil {
- return -1, nil, err
- }
-
- // Only close sync pipe. Start and attach are consumed in the attach
- // goroutine.
- defer func() {
- if pipes.syncPipe != nil && !pipes.syncClosed {
- errorhandling.CloseQuiet(pipes.syncPipe)
- pipes.syncClosed = true
- }
- }()
-
- // TODO Only create if !detach
- // Attach to the container before starting it
- attachChan := make(chan error)
- go func() {
- // attachToExec is responsible for closing pipes
- attachChan <- c.attachToExec(streams, options.DetachKeys, sessionID, pipes.startPipe, pipes.attachPipe)
- close(attachChan)
- }()
-
- if err := execCmd.Wait(); err != nil {
- return -1, nil, errors.Wrapf(err, "cannot run conmon")
- }
-
- pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
-
- return pid, attachChan, err
-}
-
-// ExecContainerHTTP executes a new command in an existing container and
-// forwards its standard streams over an attach
-func (r *ConmonOCIRuntime) ExecContainerHTTP(ctr *Container, sessionID string, options *ExecOptions, httpConn net.Conn, httpBuf *bufio.ReadWriter, streams *HTTPAttachStreams, cancel <-chan bool) (int, chan error, error) {
- if streams != nil {
- if !streams.Stdin && !streams.Stdout && !streams.Stderr {
- return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
- }
- }
-
- if options == nil {
- return -1, nil, errors.Wrapf(define.ErrInvalidArg, "must provide exec options to ExecContainerHTTP")
- }
-
- detachString := config.DefaultDetachKeys
- if options.DetachKeys != nil {
- detachString = *options.DetachKeys
- }
- detachKeys, err := processDetachKeys(detachString)
- if err != nil {
- return -1, nil, err
- }
-
- // TODO: Should we default this to false?
- // Or maybe make streams mandatory?
- attachStdin := true
- if streams != nil {
- attachStdin = streams.Stdin
- }
-
- var ociLog string
- if logrus.GetLevel() != logrus.DebugLevel && r.supportsJSON {
- ociLog = ctr.execOCILog(sessionID)
- }
-
- execCmd, pipes, err := r.startExec(ctr, sessionID, options, attachStdin, ociLog)
- if err != nil {
- return -1, nil, err
- }
-
- // Only close sync pipe. Start and attach are consumed in the attach
- // goroutine.
- defer func() {
- if pipes.syncPipe != nil && !pipes.syncClosed {
- errorhandling.CloseQuiet(pipes.syncPipe)
- pipes.syncClosed = true
- }
- }()
-
- attachChan := make(chan error)
- go func() {
- // attachToExec is responsible for closing pipes
- attachChan <- attachExecHTTP(ctr, sessionID, httpBuf, streams, pipes, detachKeys, options.Terminal, cancel)
- close(attachChan)
- }()
-
- // Wait for conmon to succeed, when return.
- if err := execCmd.Wait(); err != nil {
- return -1, nil, errors.Wrapf(err, "cannot run conmon")
- }
-
- pid, err := readConmonPipeData(pipes.syncPipe, ociLog)
-
- return pid, attachChan, err
-}
-
-// ExecAttachResize resizes the TTY of the given exec session.
-func (r *ConmonOCIRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
- controlFile, err := openControlFile(ctr, ctr.execBundlePath(sessionID))
- if err != nil {
- return err
- }
- defer controlFile.Close()
-
- if _, err = fmt.Fprintf(controlFile, "%d %d %d\n", 1, newSize.Height, newSize.Width); err != nil {
- return errors.Wrapf(err, "failed to write to ctl file to resize terminal")
- }
-
- return nil
-}
-
-// ExecStopContainer stops a given exec session in a running container.
-func (r *ConmonOCIRuntime) ExecStopContainer(ctr *Container, sessionID string, timeout uint) error {
- pid, err := ctr.getExecSessionPID(sessionID)
- if err != nil {
- return err
- }
-
- logrus.Debugf("Going to stop container %s exec session %s", ctr.ID(), sessionID)
-
- // Is the session dead?
- // Ping the PID with signal 0 to see if it still exists.
- if err := unix.Kill(pid, 0); err != nil {
- if err == unix.ESRCH {
- return nil
- }
- return errors.Wrapf(err, "error pinging container %s exec session %s PID %d with signal 0", ctr.ID(), sessionID, pid)
- }
-
- if timeout > 0 {
- // Use SIGTERM by default, then SIGSTOP after timeout.
- logrus.Debugf("Killing exec session %s (PID %d) of container %s with SIGTERM", sessionID, pid, ctr.ID())
- if err := unix.Kill(pid, unix.SIGTERM); err != nil {
- if err == unix.ESRCH {
- return nil
- }
- return errors.Wrapf(err, "error killing container %s exec session %s PID %d with SIGTERM", ctr.ID(), sessionID, pid)
- }
-
- // Wait for the PID to stop
- if err := waitPidStop(pid, time.Duration(timeout)*time.Second); err != nil {
- logrus.Warnf("Timed out waiting for container %s exec session %s to stop, resorting to SIGKILL", ctr.ID(), sessionID)
- } else {
- // No error, container is dead
- return nil
- }
- }
-
- // SIGTERM did not work. On to SIGKILL.
- logrus.Debugf("Killing exec session %s (PID %d) of container %s with SIGKILL", sessionID, pid, ctr.ID())
- if err := unix.Kill(pid, unix.SIGTERM); err != nil {
- if err == unix.ESRCH {
- return nil
- }
- return errors.Wrapf(err, "error killing container %s exec session %s PID %d with SIGKILL", ctr.ID(), sessionID, pid)
- }
-
- // Wait for the PID to stop
- if err := waitPidStop(pid, killContainerTimeout*time.Second); err != nil {
- return errors.Wrapf(err, "timed out waiting for container %s exec session %s PID %d to stop after SIGKILL", ctr.ID(), sessionID, pid)
- }
-
- return nil
-}
-
-// ExecUpdateStatus checks if the given exec session is still running.
-func (r *ConmonOCIRuntime) ExecUpdateStatus(ctr *Container, sessionID string) (bool, error) {
- pid, err := ctr.getExecSessionPID(sessionID)
- if err != nil {
- return false, err
- }
-
- logrus.Debugf("Checking status of container %s exec session %s", ctr.ID(), sessionID)
-
- // Is the session dead?
- // Ping the PID with signal 0 to see if it still exists.
- if err := unix.Kill(pid, 0); err != nil {
- if err == unix.ESRCH {
- return false, nil
- }
- return false, errors.Wrapf(err, "error pinging container %s exec session %s PID %d with signal 0", ctr.ID(), sessionID, pid)
- }
-
- return true, nil
-}
-
-// ExecContainerCleanup cleans up files created when a command is run via
-// ExecContainer. This includes the attach socket for the exec session.
-func (r *ConmonOCIRuntime) ExecContainerCleanup(ctr *Container, sessionID string) error {
- // Clean up the sockets dir. Issue #3962
- // Also ignore if it doesn't exist for some reason; hence the conditional return below
- if err := os.RemoveAll(filepath.Join(r.socketsDir, sessionID)); err != nil && !os.IsNotExist(err) {
- return err
- }
- return nil
-}
-
// CheckpointContainer checkpoints the given container.
func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options ContainerCheckpointOptions) error {
if err := label.SetSocketLabel(ctr.ProcessLabel()); err != nil {
@@ -934,16 +711,6 @@ func (r *ConmonOCIRuntime) AttachSocketPath(ctr *Container) (string, error) {
return filepath.Join(r.socketsDir, ctr.ID(), "attach"), nil
}
-// ExecAttachSocketPath is the path to a container's exec session attach socket.
-func (r *ConmonOCIRuntime) ExecAttachSocketPath(ctr *Container, sessionID string) (string, error) {
- // We don't even use container, so don't validity check it
- if sessionID == "" {
- return "", errors.Wrapf(define.ErrInvalidArg, "must provide a valid session ID to get attach socket path")
- }
-
- return filepath.Join(r.socketsDir, sessionID, "attach"), nil
-}
-
// ExitFilePath is the path to a container's exit file.
func (r *ConmonOCIRuntime) ExitFilePath(ctr *Container) (string, error) {
if ctr == nil {
@@ -1765,297 +1532,3 @@ func httpAttachNonTerminalCopy(container *net.UnixConn, http *bufio.ReadWriter,
}
}
-
-// This contains pipes used by the exec API.
-type execPipes struct {
- syncPipe *os.File
- syncClosed bool
- startPipe *os.File
- startClosed bool
- attachPipe *os.File
- attachClosed bool
-}
-
-func (p *execPipes) cleanup() {
- if p.syncPipe != nil && !p.syncClosed {
- errorhandling.CloseQuiet(p.syncPipe)
- p.syncClosed = true
- }
- if p.startPipe != nil && !p.startClosed {
- errorhandling.CloseQuiet(p.startPipe)
- p.startClosed = true
- }
- if p.attachPipe != nil && !p.attachClosed {
- errorhandling.CloseQuiet(p.attachPipe)
- p.attachClosed = true
- }
-}
-
-// Start an exec session's conmon parent from the given options.
-func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *ExecOptions, attachStdin bool, ociLog string) (_ *exec.Cmd, _ *execPipes, deferredErr error) {
- pipes := new(execPipes)
-
- if options == nil {
- return nil, nil, errors.Wrapf(define.ErrInvalidArg, "must provide an ExecOptions struct to ExecContainer")
- }
- if len(options.Cmd) == 0 {
- return nil, nil, errors.Wrapf(define.ErrInvalidArg, "must provide a command to execute")
- }
-
- if sessionID == "" {
- return nil, nil, errors.Wrapf(define.ErrEmptyID, "must provide a session ID for exec")
- }
-
- // create sync pipe to receive the pid
- parentSyncPipe, childSyncPipe, err := newPipe()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "error creating socket pair")
- }
- pipes.syncPipe = parentSyncPipe
-
- defer func() {
- if deferredErr != nil {
- pipes.cleanup()
- }
- }()
-
- // create start pipe to set the cgroup before running
- // attachToExec is responsible for closing parentStartPipe
- childStartPipe, parentStartPipe, err := newPipe()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "error creating socket pair")
- }
- pipes.startPipe = parentStartPipe
-
- // create the attach pipe to allow attach socket to be created before
- // $RUNTIME exec starts running. This is to make sure we can capture all output
- // from the process through that socket, rather than half reading the log, half attaching to the socket
- // attachToExec is responsible for closing parentAttachPipe
- parentAttachPipe, childAttachPipe, err := newPipe()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "error creating socket pair")
- }
- pipes.attachPipe = parentAttachPipe
-
- childrenClosed := false
- defer func() {
- if !childrenClosed {
- errorhandling.CloseQuiet(childSyncPipe)
- errorhandling.CloseQuiet(childAttachPipe)
- errorhandling.CloseQuiet(childStartPipe)
- }
- }()
-
- runtimeDir, err := util.GetRuntimeDir()
- if err != nil {
- return nil, nil, err
- }
-
- finalEnv := make([]string, 0, len(options.Env))
- for k, v := range options.Env {
- finalEnv = append(finalEnv, fmt.Sprintf("%s=%s", k, v))
- }
-
- processFile, err := prepareProcessExec(c, options.Cmd, finalEnv, options.Terminal, options.Cwd, options.User, sessionID)
- if err != nil {
- return nil, nil, err
- }
-
- args := r.sharedConmonArgs(c, sessionID, c.execBundlePath(sessionID), c.execPidPath(sessionID), c.execLogPath(sessionID), c.execExitFileDir(sessionID), ociLog, "")
-
- if options.PreserveFDs > 0 {
- args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", options.PreserveFDs))...)
- }
-
- for _, capability := range options.CapAdd {
- args = append(args, formatRuntimeOpts("--cap", capability)...)
- }
-
- if options.Terminal {
- args = append(args, "-t")
- }
-
- if attachStdin {
- args = append(args, "-i")
- }
-
- // Append container ID and command
- args = append(args, "-e")
- // TODO make this optional when we can detach
- args = append(args, "--exec-attach")
- args = append(args, "--exec-process-spec", processFile.Name())
-
- logrus.WithFields(logrus.Fields{
- "args": args,
- }).Debugf("running conmon: %s", r.conmonPath)
- // TODO: Need to pass this back so we can wait on it.
- execCmd := exec.Command(r.conmonPath, args...)
-
- // TODO: This is commented because it doesn't make much sense in HTTP
- // attach, and I'm not certain it does for non-HTTP attach as well.
- // if streams != nil {
- // // Don't add the InputStream to the execCmd. Instead, the data should be passed
- // // through CopyDetachable
- // if streams.AttachOutput {
- // execCmd.Stdout = options.Streams.OutputStream
- // }
- // if streams.AttachError {
- // execCmd.Stderr = options.Streams.ErrorStream
- // }
- // }
-
- conmonEnv, extraFiles, err := r.configureConmonEnv(runtimeDir)
- if err != nil {
- return nil, nil, err
- }
-
- if options.PreserveFDs > 0 {
- for fd := 3; fd < int(3+options.PreserveFDs); fd++ {
- execCmd.ExtraFiles = append(execCmd.ExtraFiles, os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)))
- }
- }
-
- // we don't want to step on users fds they asked to preserve
- // Since 0-2 are used for stdio, start the fds we pass in at preserveFDs+3
- execCmd.Env = r.conmonEnv
- execCmd.Env = append(execCmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", options.PreserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", options.PreserveFDs+4), fmt.Sprintf("_OCI_ATTACHPIPE=%d", options.PreserveFDs+5))
- execCmd.Env = append(execCmd.Env, conmonEnv...)
-
- execCmd.ExtraFiles = append(execCmd.ExtraFiles, childSyncPipe, childStartPipe, childAttachPipe)
- execCmd.ExtraFiles = append(execCmd.ExtraFiles, extraFiles...)
- execCmd.Dir = c.execBundlePath(sessionID)
- execCmd.SysProcAttr = &syscall.SysProcAttr{
- Setpgid: true,
- }
-
- err = startCommandGivenSelinux(execCmd)
-
- // We don't need children pipes on the parent side
- errorhandling.CloseQuiet(childSyncPipe)
- errorhandling.CloseQuiet(childAttachPipe)
- errorhandling.CloseQuiet(childStartPipe)
- childrenClosed = true
-
- if err != nil {
- return nil, nil, errors.Wrapf(err, "cannot start container %s", c.ID())
- }
- if err := r.moveConmonToCgroupAndSignal(c, execCmd, parentStartPipe); err != nil {
- return nil, nil, err
- }
-
- if options.PreserveFDs > 0 {
- for fd := 3; fd < int(3+options.PreserveFDs); fd++ {
- // These fds were passed down to the runtime. Close them
- // and not interfere
- if err := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close(); err != nil {
- logrus.Debugf("unable to close file fd-%d", fd)
- }
- }
- }
-
- return execCmd, pipes, nil
-}
-
-// Attach to a container over HTTP
-func attachExecHTTP(c *Container, sessionID string, httpBuf *bufio.ReadWriter, streams *HTTPAttachStreams, pipes *execPipes, detachKeys []byte, isTerminal bool, cancel <-chan bool) error {
- if pipes == nil || pipes.startPipe == nil || pipes.attachPipe == nil {
- return errors.Wrapf(define.ErrInvalidArg, "must provide a start and attach pipe to finish an exec attach")
- }
-
- defer func() {
- if !pipes.startClosed {
- errorhandling.CloseQuiet(pipes.startPipe)
- pipes.startClosed = true
- }
- if !pipes.attachClosed {
- errorhandling.CloseQuiet(pipes.attachPipe)
- pipes.attachClosed = true
- }
- }()
-
- logrus.Debugf("Attaching to container %s exec session %s", c.ID(), sessionID)
-
- // set up the socket path, such that it is the correct length and location for exec
- sockPath, err := c.execAttachSocketPath(sessionID)
- if err != nil {
- return err
- }
- socketPath := buildSocketPath(sockPath)
-
- // 2: read from attachFd that the parent process has set up the console socket
- if _, err := readConmonPipeData(pipes.attachPipe, ""); err != nil {
- return err
- }
-
- // 2: then attach
- conn, err := net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: socketPath, Net: "unixpacket"})
- if err != nil {
- return errors.Wrapf(err, "failed to connect to container's attach socket: %v", socketPath)
- }
- defer func() {
- if err := conn.Close(); err != nil {
- logrus.Errorf("unable to close socket: %q", err)
- }
- }()
-
- // Make a channel to pass errors back
- errChan := make(chan error)
-
- attachStdout := true
- attachStderr := true
- attachStdin := true
- if streams != nil {
- attachStdout = streams.Stdout
- attachStderr = streams.Stderr
- attachStdin = streams.Stdin
- }
-
- // Next, STDIN. Avoid entirely if attachStdin unset.
- if attachStdin {
- go func() {
- logrus.Debugf("Beginning STDIN copy")
- _, err := utils.CopyDetachable(conn, httpBuf, detachKeys)
- logrus.Debugf("STDIN copy completed")
- errChan <- err
- }()
- }
-
- // 4: send start message to child
- if err := writeConmonPipeData(pipes.startPipe); err != nil {
- return err
- }
-
- // Handle STDOUT/STDERR *after* start message is sent
- go func() {
- var err error
- if isTerminal {
- // Hack: return immediately if attachStdout not set to
- // emulate Docker.
- // Basically, when terminal is set, STDERR goes nowhere.
- // Everything does over STDOUT.
- // Therefore, if not attaching STDOUT - we'll never copy
- // anything from here.
- logrus.Debugf("Performing terminal HTTP attach for container %s", c.ID())
- if attachStdout {
- err = httpAttachTerminalCopy(conn, httpBuf, c.ID())
- }
- } else {
- logrus.Debugf("Performing non-terminal HTTP attach for container %s", c.ID())
- err = httpAttachNonTerminalCopy(conn, httpBuf, c.ID(), attachStdin, attachStdout, attachStderr)
- }
- errChan <- err
- logrus.Debugf("STDOUT/ERR copy completed")
- }()
-
- if cancel != nil {
- select {
- case err := <-errChan:
- return err
- case <-cancel:
- return nil
- }
- } else {
- var connErr error = <-errChan
- return connErr
- }
-}
diff --git a/libpod/oci_missing.go b/libpod/oci_missing.go
index 626740f72..4da16876c 100644
--- a/libpod/oci_missing.go
+++ b/libpod/oci_missing.go
@@ -130,6 +130,11 @@ func (r *MissingRuntime) ExecContainerHTTP(ctr *Container, sessionID string, opt
return -1, nil, r.printError()
}
+// ExecContainerDetached is not available as the runtime is missing
+func (r *MissingRuntime) ExecContainerDetached(ctr *Container, sessionID string, options *ExecOptions, stdin bool) (int, error) {
+ return -1, r.printError()
+}
+
// ExecAttachResize is not available as the runtime is missing.
func (r *MissingRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
return r.printError()
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index c670822a0..655b42e51 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -390,6 +390,8 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
}
+ logrus.Debugf("Removing container %s", c.ID())
+
// We need to lock the pod before we lock the container.
// To avoid races around removing a container and the pod it is in.
// Don't need to do this in pod removal case - we're evicting the entire
diff --git a/pkg/api/handlers/libpod/healthcheck.go b/pkg/api/handlers/libpod/healthcheck.go
index 6eb2ab0e3..0ca3574b7 100644
--- a/pkg/api/handlers/libpod/healthcheck.go
+++ b/pkg/api/handlers/libpod/healthcheck.go
@@ -4,6 +4,7 @@ import (
"net/http"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers/utils"
)
@@ -12,32 +13,27 @@ func RunHealthCheck(w http.ResponseWriter, r *http.Request) {
name := utils.GetName(r)
status, err := runtime.HealthCheck(name)
if err != nil {
- if status == libpod.HealthCheckContainerNotFound {
+ if status == define.HealthCheckContainerNotFound {
utils.ContainerNotFound(w, name, err)
return
}
- if status == libpod.HealthCheckNotDefined {
+ if status == define.HealthCheckNotDefined {
utils.Error(w, "no healthcheck defined", http.StatusConflict, err)
return
}
- if status == libpod.HealthCheckContainerStopped {
+ if status == define.HealthCheckContainerStopped {
utils.Error(w, "container not running", http.StatusConflict, err)
return
}
utils.InternalServerError(w, err)
return
}
- ctr, err := runtime.LookupContainer(name)
- if err != nil {
- utils.InternalServerError(w, err)
- return
+ hcStatus := define.HealthCheckUnhealthy
+ if status == define.HealthCheckSuccess {
+ hcStatus = define.HealthCheckHealthy
}
-
- hcLog, err := ctr.GetHealthCheckLog()
- if err != nil {
- utils.InternalServerError(w, err)
- return
+ report := define.HealthCheckResults{
+ Status: hcStatus,
}
-
- utils.WriteResponse(w, http.StatusOK, hcLog)
+ utils.WriteResponse(w, http.StatusOK, report)
}
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index 1c67de9db..7fb31a177 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -62,7 +62,6 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
}{
// This is where you can override the golang default value for one of fields
}
- // TODO I think all is implemented with a filter?
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
return nil, err
@@ -71,6 +70,10 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
if _, found := r.URL.Query()["digests"]; found && query.Digests {
UnSupportedParameter("digests")
}
+ var (
+ images []*image.Image
+ err error
+ )
if len(query.Filters) > 0 {
for k, v := range query.Filters {
@@ -78,11 +81,33 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
filters = append(filters, fmt.Sprintf("%s=%s", k, val))
}
}
- return runtime.ImageRuntime().GetImagesWithFilters(filters)
+ images, err = runtime.ImageRuntime().GetImagesWithFilters(filters)
+ if err != nil {
+ return images, err
+ }
} else {
- return runtime.ImageRuntime().GetImages()
+ images, err = runtime.ImageRuntime().GetImages()
+ if err != nil {
+ return images, err
+ }
}
-
+ if query.All {
+ return images, nil
+ }
+ var returnImages []*image.Image
+ for _, img := range images {
+ if len(img.Names()) == 0 {
+ parent, err := img.IsParent(r.Context())
+ if err != nil {
+ return nil, err
+ }
+ if parent {
+ continue
+ }
+ }
+ returnImages = append(returnImages, img)
+ }
+ return returnImages, nil
}
func GetImage(r *http.Request, name string) (*image.Image, error) {
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 3cc4b6db1..8d85a9b23 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -242,7 +242,6 @@ type ExecOptions struct {
Latest bool
PreserveFDs uint
Privileged bool
- Streams define.AttachStreams
Tty bool
User string
WorkDir string
@@ -311,6 +310,7 @@ type ContainerRunReport struct {
// cleanup command
type ContainerCleanupOptions struct {
All bool
+ Exec string
Latest bool
Remove bool
RemoveImage bool
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index e77f0758b..3d5161745 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -19,7 +19,8 @@ type ContainerEngine interface {
ContainerCp(ctx context.Context, source, dest string, options ContainerCpOptions) (*ContainerCpReport, error)
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
ContainerDiff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error)
- ContainerExec(ctx context.Context, nameOrId string, options ExecOptions) (int, 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)
ContainerExport(ctx context.Context, nameOrId string, options ContainerExportOptions) error
ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index cce3001eb..0f909ab37 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -1,7 +1,6 @@
package entities
import (
- "net/url"
"time"
"github.com/containers/image/v5/manifest"
@@ -221,15 +220,13 @@ type ImageSearchReport struct {
// Image List Options
type ImageListOptions struct {
- All bool `json:"all" schema:"all"`
- Filter []string `json:"Filter,omitempty"`
- Filters url.Values `json:"filters" schema:"filters"`
+ All bool `json:"all" schema:"all"`
+ Filter []string `json:"Filter,omitempty"`
}
type ImagePruneOptions struct {
- All bool `json:"all" schema:"all"`
- Filter []string `json:"filter" schema:"filter"`
- Filters url.Values `json:"filters" schema:"filters"`
+ All bool `json:"all" schema:"all"`
+ Filter []string `json:"filter" schema:"filter"`
}
type ImagePruneReport struct {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 035efe575..b4e38ca23 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -536,7 +536,22 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string,
return nil
}
-func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) {
+func makeExecConfig(options entities.ExecOptions) *libpod.ExecConfig {
+ execConfig := new(libpod.ExecConfig)
+ execConfig.Command = options.Cmd
+ execConfig.Terminal = options.Tty
+ execConfig.Privileged = options.Privileged
+ execConfig.Environment = options.Envs
+ execConfig.User = options.User
+ execConfig.WorkDir = options.WorkDir
+ execConfig.DetachKeys = &options.DetachKeys
+ execConfig.PreserveFDs = options.PreserveFDs
+ execConfig.AttachStdin = options.Interactive
+
+ return execConfig
+}
+
+func checkExecPreserveFDs(options entities.ExecOptions) (int, error) {
ec := define.ExecErrorCodeGeneric
if options.PreserveFDs > 0 {
entries, err := ioutil.ReadDir("/proc/self/fd")
@@ -559,15 +574,66 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, o
}
}
}
+ return ec, nil
+}
+
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
+ ec, err := checkExecPreserveFDs(options)
+ if err != nil {
+ return ec, err
+ }
ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
if err != nil {
return ec, err
}
ctr := ctrs[0]
- ec, err = terminal.ExecAttachCtr(ctx, ctr, options.Tty, options.Privileged, options.Envs, options.Cmd, options.User, options.WorkDir, &options.Streams, options.PreserveFDs, options.DetachKeys)
+
+ execConfig := makeExecConfig(options)
+
+ ec, err = terminal.ExecAttachCtr(ctx, ctr, execConfig, &streams)
return define.TranslateExecErrorToExitCode(ec, err), err
}
+func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrId string, options entities.ExecOptions) (string, error) {
+ _, err := checkExecPreserveFDs(options)
+ if err != nil {
+ return "", err
+ }
+ ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
+ if err != nil {
+ return "", err
+ }
+ ctr := ctrs[0]
+
+ execConfig := makeExecConfig(options)
+
+ // Make an exit command
+ storageConfig := ic.Libpod.StorageConfig()
+ runtimeConfig, err := ic.Libpod.GetConfig()
+ if err != nil {
+ return "", errors.Wrapf(err, "error retrieving Libpod configuration to build exec exit command")
+ }
+ podmanPath, err := os.Executable()
+ if err != nil {
+ return "", errors.Wrapf(err, "error retrieving executable to build exec exit command")
+ }
+ // TODO: Add some ability to toggle syslog
+ exitCommandArgs := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, podmanPath, false, true, true)
+ execConfig.ExitCommand = exitCommandArgs
+
+ // Create and start the exec session
+ id, err := ctr.ExecCreate(execConfig)
+ if err != nil {
+ return "", err
+ }
+
+ // TODO: we should try and retrieve exit code if this fails.
+ if err := ctr.ExecStart(id); err != nil {
+ return "", err
+ }
+ return id, nil
+}
+
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
var reports []*entities.ContainerStartReport
var exitCode = define.ExecErrorCodeGeneric
@@ -836,6 +902,20 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
for _, ctr := range ctrs {
var err error
report := entities.ContainerCleanupReport{Id: ctr.ID()}
+
+ if options.Exec != "" {
+ if options.Remove {
+ if err := ctr.ExecRemove(options.Exec, false); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := ctr.ExecCleanup(options.Exec); err != nil {
+ return nil, err
+ }
+ }
+ return []*entities.ContainerCleanupReport{}, nil
+ }
+
if options.Remove {
err = ic.Libpod.RemoveContainer(ctx, ctr, false, true)
if err != nil {
diff --git a/pkg/domain/infra/abi/healthcheck.go b/pkg/domain/infra/abi/healthcheck.go
index 351bf4f7e..4e925ef56 100644
--- a/pkg/domain/infra/abi/healthcheck.go
+++ b/pkg/domain/infra/abi/healthcheck.go
@@ -3,7 +3,6 @@ package abi
import (
"context"
- "github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
)
@@ -13,9 +12,9 @@ func (ic *ContainerEngine) HealthCheckRun(ctx context.Context, nameOrId string,
if err != nil {
return nil, err
}
- hcStatus := "unhealthy"
- if status == libpod.HealthCheckSuccess {
- hcStatus = "healthy"
+ hcStatus := define.HealthCheckUnhealthy
+ if status == define.HealthCheckSuccess {
+ hcStatus = define.HealthCheckHealthy
}
report := define.HealthCheckResults{
Status: hcStatus,
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index c559e250c..3034e36ec 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -13,14 +13,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
err error
)
- // TODO: Future work support for domain.Filters
- // filters := utils.ToLibpodFilters(opts.Filters)
-
- if len(opts.Filter) > 0 {
- images, err = ir.Libpod.ImageRuntime().GetImagesWithFilters(opts.Filter)
- } else {
- images, err = ir.Libpod.ImageRuntime().GetImages()
- }
+ images, err = ir.Libpod.ImageRuntime().GetImagesWithFilters(opts.Filter)
if err != nil {
return nil, err
}
@@ -40,9 +33,18 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
}
}
} else {
- repoTags, _ = img.RepoTags()
- if len(repoTags) == 0 {
- continue
+ repoTags, err = img.RepoTags()
+ if err != nil {
+ return nil, err
+ }
+ if len(img.Names()) == 0 {
+ parent, err := img.IsParent(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if parent {
+ continue
+ }
}
}
diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go
index 15701342f..8d9cdde03 100644
--- a/pkg/domain/infra/abi/terminal/terminal_linux.go
+++ b/pkg/domain/infra/abi/terminal/terminal_linux.go
@@ -15,13 +15,13 @@ import (
)
// ExecAttachCtr execs and attaches to a container
-func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *define.AttachStreams, preserveFDs uint, detachKeys string) (int, error) {
+func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpod.ExecConfig, streams *define.AttachStreams) (int, error) {
resize := make(chan remotecommand.TerminalSize)
haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
// Check if we are attached to a terminal. If we are, generate resize
// events, and set the terminal to raw mode
- if haveTerminal && tty {
+ if haveTerminal && execConfig.Terminal {
cancel, oldTermState, err := handleTerminalAttach(ctx, resize)
if err != nil {
return -1, err
@@ -34,16 +34,6 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged b
}()
}
- execConfig := new(libpod.ExecConfig)
- execConfig.Command = cmd
- execConfig.Terminal = tty
- execConfig.Privileged = privileged
- execConfig.Environment = env
- execConfig.User = user
- execConfig.WorkDir = workDir
- execConfig.DetachKeys = &detachKeys
- execConfig.PreserveFDs = preserveFDs
-
return ctr.Exec(execConfig, streams, resize)
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 828bfae5b..d02c54e76 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -4,6 +4,7 @@ import (
"context"
"io"
"os"
+ "strings"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
@@ -329,10 +330,14 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string,
return containers.Attach(ic.ClientCxt, nameOrId, &options.DetachKeys, nil, bindings.PTrue, options.Stdin, options.Stdout, options.Stderr, nil)
}
-func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) {
+func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
return 125, errors.New("not implemented")
}
+func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
+ return "", errors.New("not implemented")
+}
+
func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input, output, errput *os.File) error { //nolint
attachErr := make(chan error)
attachReady := make(chan bool)
@@ -355,10 +360,19 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
report := entities.ContainerStartReport{Id: name}
if options.Attach {
report.Err = startAndAttach(ic, name, &options.DetachKeys, options.Stdin, options.Stdout, options.Stderr)
+ if report.Err == nil {
+ exitCode, err := containers.Wait(ic.ClientCxt, name, nil)
+ if err == nil {
+ report.ExitCode = int(exitCode)
+ }
+ } else {
+ report.ExitCode = define.ExitCode(report.Err)
+ }
reports = append(reports, &report)
return reports, nil
}
report.Err = containers.Start(ic.ClientCxt, name, &options.DetachKeys)
+ report.ExitCode = define.ExitCode(report.Err)
reports = append(reports, &report)
}
return reports, nil
@@ -380,11 +394,18 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
// Attach
if !opts.Detach {
err = startAndAttach(ic, con.ID, &opts.DetachKeys, opts.InputStream, opts.OutputStream, opts.ErrorStream)
-
+ if err == nil {
+ exitCode, err := containers.Wait(ic.ClientCxt, con.ID, nil)
+ if err == nil {
+ report.ExitCode = int(exitCode)
+ }
+ }
} else {
err = containers.Start(ic.ClientCxt, con.ID, nil)
}
- report.ExitCode = define.ExitCode(err)
+ if err != nil {
+ report.ExitCode = define.ExitCode(err)
+ }
return &report, err
}
@@ -405,6 +426,11 @@ func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []strin
}
for _, ctr := range ctrs {
err := containers.ContainerInit(ic.ClientCxt, ctr.ID)
+ // When using all, it is NOT considered an error if a container
+ // has already been init'd.
+ if err != nil && options.All && strings.Contains(errors.Cause(err).Error(), define.ErrCtrStateInvalid.Error()) {
+ err = nil
+ }
reports = append(reports, &entities.ContainerInitReport{
Err: err,
Id: ctr.ID,
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 4d00d331b..3d5626c45 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -4,6 +4,7 @@ import (
"context"
"io/ioutil"
"os"
+ "strings"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
@@ -25,8 +26,13 @@ func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts enti
}
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
- images, err := images.List(ir.ClientCxt, &opts.All, opts.Filters)
+ filters := make(map[string][]string, len(opts.Filter))
+ for _, filter := range opts.Filter {
+ f := strings.Split(filter, "=")
+ filters[f[0]] = f[1:]
+ }
+ images, err := images.List(ir.ClientCxt, &opts.All, filters)
if err != nil {
return nil, err
}
@@ -61,7 +67,13 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entiti
}
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
- results, err := images.Prune(ir.ClientCxt, &opts.All, opts.Filters)
+ filters := make(map[string][]string, len(opts.Filter))
+ for _, filter := range opts.Filter {
+ f := strings.Split(filter, "=")
+ filters[f[0]] = f[1:]
+ }
+
+ results, err := images.Prune(ir.ClientCxt, &opts.All, filters)
if err != nil {
return nil, err
}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index f3aaf96bf..ffd7fd4dd 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -111,7 +111,8 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
if err != nil {
return nil, err
}
- options = append(options, createExitCommandOption(s, rt.StorageConfig(), rtc, podmanPath))
+ // TODO: Enable syslog support - we'll need to put this in SpecGen.
+ options = append(options, libpod.WithExitCommand(CreateExitCommandArgs(rt.StorageConfig(), rtc, podmanPath, false, s.Remove, false)))
runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts)
if err != nil {
@@ -228,7 +229,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
return options, nil
}
-func createExitCommandOption(s *specgen.SpecGenerator, storageConfig storage.StoreOptions, config *config.Config, podmanPath string) libpod.CtrCreateOption {
+func CreateExitCommandArgs(storageConfig storage.StoreOptions, config *config.Config, podmanPath string, syslog, rm bool, exec bool) []string {
// We need a cleanup process for containers in the current model.
// But we can't assume that the caller is Podman - it could be another
// user of the API.
@@ -255,14 +256,18 @@ func createExitCommandOption(s *specgen.SpecGenerator, storageConfig storage.Sto
command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...)
}
- // TODO Mheon wants to leave this for now
- //if s.sys {
- // command = append(command, "--syslog", "true")
- //}
+ if syslog {
+ command = append(command, "--syslog", "true")
+ }
command = append(command, []string{"container", "cleanup"}...)
- if s.Remove {
+ if rm {
command = append(command, "--rm")
}
- return libpod.WithExitCommand(command)
+
+ if exec {
+ command = append(command, "--exec")
+ }
+
+ return command
}
diff --git a/pkg/util/mountOpts_linux.go b/pkg/util/mountOpts_linux.go
index 3eac4dd25..bc7c675f3 100644
--- a/pkg/util/mountOpts_linux.go
+++ b/pkg/util/mountOpts_linux.go
@@ -7,7 +7,7 @@ import (
)
func getDefaultMountOptions(path string) (defaultMountOptions, error) {
- opts := defaultMountOptions{true, true, true}
+ opts := defaultMountOptions{false, true, true}
if path == "" {
return opts, nil
}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index 258cb8652..291353cad 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -901,12 +901,12 @@ func (i *VarlinkAPI) ExecContainer(call iopodman.VarlinkCall, opts iopodman.Exec
// HealthCheckRun executes defined container's healthcheck command and returns the container's health status.
func (i *VarlinkAPI) HealthCheckRun(call iopodman.VarlinkCall, nameOrID string) error {
hcStatus, err := i.Runtime.HealthCheck(nameOrID)
- if err != nil && hcStatus != libpod.HealthCheckFailure {
+ if err != nil && hcStatus != define.HealthCheckFailure {
return call.ReplyErrorOccurred(err.Error())
}
- status := libpod.HealthCheckUnhealthy
- if hcStatus == libpod.HealthCheckSuccess {
- status = libpod.HealthCheckHealthy
+ status := define.HealthCheckUnhealthy
+ if hcStatus == define.HealthCheckSuccess {
+ status = define.HealthCheckHealthy
}
return call.ReplyHealthCheckRun(status)
}
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 7d4858551..0a6373bfa 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -207,7 +207,7 @@ var _ = Describe("Podman create", func() {
session = podmanTest.Podman([]string{"logs", "test_tmpfs"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(ContainSubstring("/create/test rw,nosuid,nodev,noexec,relatime - tmpfs"))
+ Expect(session.OutputToString()).To(ContainSubstring("/create/test rw,nosuid,nodev,relatime - tmpfs"))
})
It("podman create --pod automatically", func() {
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index da80bba47..87dddb233 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -283,4 +283,31 @@ var _ = Describe("Podman exec", func() {
Expect(exec.ExitCode()).To(Equal(0))
Expect(strings.Contains(exec.OutputToString(), fmt.Sprintf("%s(%s)", gid, groupName))).To(BeTrue())
})
+
+ It("podman exec --detach", func() {
+ ctrName := "testctr"
+ ctr := podmanTest.Podman([]string{"run", "-t", "-i", "-d", "--name", ctrName, ALPINE, "top"})
+ ctr.WaitWithDefaultTimeout()
+ Expect(ctr.ExitCode()).To(Equal(0))
+
+ exec1 := podmanTest.Podman([]string{"exec", "-t", "-i", "-d", ctrName, "top"})
+ exec1.WaitWithDefaultTimeout()
+ Expect(ctr.ExitCode()).To(Equal(0))
+
+ data := podmanTest.InspectContainer(ctrName)
+ Expect(len(data)).To(Equal(1))
+ Expect(len(data[0].ExecIDs)).To(Equal(1))
+ Expect(strings.Contains(exec1.OutputToString(), data[0].ExecIDs[0])).To(BeTrue())
+
+ exec2 := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "ps", "-a"})
+ exec2.WaitWithDefaultTimeout()
+ Expect(ctr.ExitCode()).To(Equal(0))
+ Expect(strings.Count(exec2.OutputToString(), "top")).To(Equal(2))
+
+ // Ensure that stop with a running detached exec session is
+ // clean.
+ stop := podmanTest.Podman([]string{"stop", ctrName})
+ stop.WaitWithDefaultTimeout()
+ Expect(stop.ExitCode()).To(Equal(0))
+ })
})
diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go
index f434836d3..8e63d9f4c 100644
--- a/test/e2e/healthcheck_run_test.go
+++ b/test/e2e/healthcheck_run_test.go
@@ -83,7 +83,6 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman healthcheck that should fail", func() {
- Skip(v2remotefail)
session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "docker.io/libpod/badhealthcheck:latest"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -122,7 +121,6 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman healthcheck failed checks in start-period should not change status", func() {
- Skip(v2remotefail)
session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-start-period", "2m", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -144,7 +142,6 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman healthcheck failed checks must reach retries before unhealthy ", func() {
- Skip(v2remotefail)
session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index cd281e3c7..1715cf8c1 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -152,9 +152,7 @@ var _ = Describe("Podman images", func() {
})
It("podman images filter reference", func() {
- if podmanTest.RemoteTest {
- Skip("Does not work on remote client")
- }
+ SkipIfRemote()
podmanTest.RestoreAllArtifacts()
result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "reference=docker.io*"})
result.WaitWithDefaultTimeout()
@@ -180,9 +178,7 @@ var _ = Describe("Podman images", func() {
})
It("podman images filter before image", func() {
- if podmanTest.RemoteTest {
- Skip("Does not work on remote client")
- }
+ SkipIfRemote()
dockerfile := `FROM docker.io/library/alpine:latest
RUN apk update && apk add man
`
@@ -194,9 +190,7 @@ RUN apk update && apk add man
})
It("podman images filter after image", func() {
- if podmanTest.RemoteTest {
- Skip("Does not work on remote client")
- }
+ SkipIfRemote()
podmanTest.RestoreAllArtifacts()
rmi := podmanTest.PodmanNoCache([]string{"rmi", "busybox"})
rmi.WaitWithDefaultTimeout()
@@ -212,9 +206,7 @@ RUN apk update && apk add man
})
It("podman image list filter after image", func() {
- if podmanTest.RemoteTest {
- Skip("Does not work on remote client")
- }
+ SkipIfRemote()
podmanTest.RestoreAllArtifacts()
rmi := podmanTest.PodmanNoCache([]string{"image", "rm", "busybox"})
rmi.WaitWithDefaultTimeout()
@@ -230,9 +222,7 @@ RUN apk update && apk add man
})
It("podman images filter dangling", func() {
- if podmanTest.RemoteTest {
- Skip("Does not work on remote client")
- }
+ SkipIfRemote()
dockerfile := `FROM docker.io/library/alpine:latest
`
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
@@ -308,9 +298,7 @@ RUN apk update && apk add man
})
It("podman images --all flag", func() {
- if podmanTest.RemoteTest {
- Skip("Does not work on remote client")
- }
+ SkipIfRemote()
podmanTest.RestoreAllArtifacts()
dockerfile := `FROM docker.io/library/alpine:latest
RUN mkdir hello
@@ -343,10 +331,7 @@ LABEL "com.example.vendor"="Example Vendor"
})
It("podman with images with no layers", func() {
- if podmanTest.RemoteTest {
- Skip("Does not work on remote client")
- }
-
+ SkipIfRemote()
dockerfile := strings.Join([]string{
`FROM scratch`,
`LABEL org.opencontainers.image.authors="<somefolks@example.org>"`,
diff --git a/test/e2e/init_test.go b/test/e2e/init_test.go
index 349487b03..721017d0c 100644
--- a/test/e2e/init_test.go
+++ b/test/e2e/init_test.go
@@ -90,7 +90,6 @@ var _ = Describe("Podman init", func() {
})
It("podman init all three containers, one running", func() {
- Skip(v2remotefail)
session := podmanTest.Podman([]string{"create", "--name", "test1", "-d", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -121,11 +120,10 @@ var _ = Describe("Podman init", func() {
})
It("podman init running container errors", func() {
- Skip(v2remotefail)
- session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top"})
+ session := podmanTest.Podman([]string{"run", "--name", "init_test", "-d", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- init := podmanTest.Podman([]string{"init", "--latest"})
+ init := podmanTest.Podman([]string{"init", "init_test"})
init.WaitWithDefaultTimeout()
Expect(init.ExitCode()).To(Equal(125))
})
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index 24bfa69ce..e56db54a2 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -2,7 +2,9 @@ package integration
import (
"fmt"
+ "io/ioutil"
"os"
+ "path/filepath"
"strings"
. "github.com/containers/libpod/test/utils"
@@ -282,4 +284,26 @@ var _ = Describe("Podman pod create", func() {
podCreate.WaitWithDefaultTimeout()
Expect(podCreate.ExitCode()).To(Equal(125))
})
+
+ It("podman create pod and print id to external file", func() {
+ // Switch to temp dir and restore it afterwards
+ cwd, err := os.Getwd()
+ Expect(err).To(BeNil())
+ Expect(os.Chdir(os.TempDir())).To(BeNil())
+ targetPath := filepath.Join(os.TempDir(), "dir")
+ Expect(os.MkdirAll(targetPath, 0755)).To(BeNil())
+ targetFile := filepath.Join(targetPath, "idFile")
+ defer Expect(os.RemoveAll(targetFile)).To(BeNil())
+ defer Expect(os.Chdir(cwd)).To(BeNil())
+
+ session := podmanTest.Podman([]string{"pod", "create", "--name=abc", "--pod-id-file", targetFile})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ id, _ := ioutil.ReadFile(targetFile)
+ check := podmanTest.Podman([]string{"pod", "inspect", "abc"})
+ check.WaitWithDefaultTimeout()
+ data := check.InspectPodToJSON()
+ Expect(data.ID).To(Equal(string(id)))
+ })
})
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index ccd322dd2..e77e6dd25 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -161,7 +161,6 @@ var _ = Describe("Podman prune", func() {
})
It("podman system prune pods", func() {
- Skip(v2remotefail)
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -169,12 +168,13 @@ var _ = Describe("Podman prune", func() {
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ podid1 := session.OutputToString()
- session = podmanTest.Podman([]string{"pod", "start", "-l"})
+ session = podmanTest.Podman([]string{"pod", "start", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "stop", "-l"})
+ session = podmanTest.Podman([]string{"pod", "stop", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -194,17 +194,17 @@ var _ = Describe("Podman prune", func() {
})
It("podman system prune - pod,container stopped", func() {
- Skip(v2remotefail)
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ podid1 := session.OutputToString()
// Start and stop a pod to get it in exited state.
- session = podmanTest.Podman([]string{"pod", "start", "-l"})
+ session = podmanTest.Podman([]string{"pod", "start", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "stop", "-l"})
+ session = podmanTest.Podman([]string{"pod", "stop", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -226,17 +226,17 @@ var _ = Describe("Podman prune", func() {
})
It("podman system prune with running, exited pod and volume prune set true", func() {
- Skip(v2remotefail)
// Start and stop a pod to get it in exited state.
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ podid1 := session.OutputToString()
- session = podmanTest.Podman([]string{"pod", "start", "-l"})
+ session = podmanTest.Podman([]string{"pod", "start", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "stop", "-l"})
+ session = podmanTest.Podman([]string{"pod", "stop", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -244,7 +244,9 @@ var _ = Describe("Podman prune", func() {
session = podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "start", "-l"})
+ podid2 := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"pod", "start", podid2})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -301,17 +303,17 @@ var _ = Describe("Podman prune", func() {
})
It("podman system prune - with dangling images true", func() {
- Skip(v2remotefail)
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
+ podid1 := session.OutputToString()
// Start and stop a pod to get it in exited state.
- session = podmanTest.Podman([]string{"pod", "start", "-l"})
+ session = podmanTest.Podman([]string{"pod", "start", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"pod", "stop", "-l"})
+ session = podmanTest.Podman([]string{"pod", "stop", podid1})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -320,9 +322,6 @@ var _ = Describe("Podman prune", func() {
create.WaitWithDefaultTimeout()
Expect(create.ExitCode()).To(Equal(0))
- // Adding images should be pruned
- podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true")
-
// Adding unused volume should not be pruned as volumes not set
session = podmanTest.Podman([]string{"volume", "create"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_exit_test.go b/test/e2e/run_exit_test.go
index d4b44ff23..40731142e 100644
--- a/test/e2e/run_exit_test.go
+++ b/test/e2e/run_exit_test.go
@@ -62,7 +62,6 @@ var _ = Describe("Podman run exit", func() {
})
It("podman run exit 50", func() {
- Skip(v2remotefail)
result := podmanTest.Podman([]string{"run", ALPINE, "sh", "-c", "exit 50"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(50))
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 1f892d9f8..58091ff68 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -117,7 +117,7 @@ var _ = Describe("Podman run with volumes", func() {
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=" + dest, ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(ContainSubstring(dest + " rw,nosuid,nodev,noexec,relatime - tmpfs"))
+ Expect(session.OutputToString()).To(ContainSubstring(dest + " rw,nosuid,nodev,relatime - tmpfs"))
session = podmanTest.Podman([]string{"run", "--rm", "--mount", "type=tmpfs,target=/etc/ssl,tmpcopyup", ALPINE, "ls", "/etc/ssl"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/untag_test.go b/test/e2e/untag_test.go
index 43b874d47..dc1a6208e 100644
--- a/test/e2e/untag_test.go
+++ b/test/e2e/untag_test.go
@@ -40,7 +40,6 @@ var _ = Describe("Podman untag", func() {
})
It("podman untag all", func() {
- Skip(v2remotefail)
session := podmanTest.PodmanNoCache([]string{"untag", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/system/160-volumes.bats b/test/system/160-volumes.bats
index 5d65a950f..3233e6f04 100644
--- a/test/system/160-volumes.bats
+++ b/test/system/160-volumes.bats
@@ -115,7 +115,8 @@ echo "got here -$rand-"
EOF
chmod 755 $mountpoint/myscript
- # By default, volumes are mounted noexec. This should fail.
+ # By default, volumes are mounted exec, but we have manually added the
+ # noexec option. This should fail.
# ARGH. Unfortunately, runc (used for cgroups v1) produces a different error
local expect_rc=126
local expect_msg='.* OCI runtime permission denied.*'
@@ -125,12 +126,12 @@ EOF
expect_msg='.* exec user process caused.*permission denied'
fi
- run_podman ${expect_rc} run --rm --volume $myvolume:/vol:z $IMAGE /vol/myscript
+ run_podman ${expect_rc} run --rm --volume $myvolume:/vol:noexec,z $IMAGE /vol/myscript
is "$output" "$expect_msg" "run on volume, noexec"
- # With exec, it should pass
- run_podman run --rm -v $myvolume:/vol:z,exec $IMAGE /vol/myscript
- is "$output" "got here -$rand-" "script in volume is runnable with exec"
+ # With the default, it should pass
+ run_podman run --rm -v $myvolume:/vol:z $IMAGE /vol/myscript
+ is "$output" "got here -$rand-" "script in volume is runnable with default (exec)"
# Clean up
run_podman volume rm $myvolume
diff --git a/troubleshooting.md b/troubleshooting.md
index f04d9e9fa..167ee14c3 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -219,8 +219,15 @@ the system.
#### Solution
-SELinux provides a boolean `container_manage_cgroup`, which allows container
-processes to write to the cgroup file system. Turn on this boolean, on SELinux separated systems, to allow systemd to run properly in the container.
+Newer versions of Podman (2.0 or greater) support running init based containers
+with a different SELinux labels, which allow the container process access to the
+cgroup file system. This feature requires container-selinux-2.132 or newer
+versions.
+
+Prior to Podman 2.0, the SELinux boolean `container_manage_cgroup` allows
+container processes to write to the cgroup file system. Turn on this boolean,
+on SELinux separated systems, to allow systemd to run properly in the container.
+Only do this on systems running older versions of Podman.
`setsebool -P container_manage_cgroup true`
@@ -240,7 +247,7 @@ cannot find newuidmap: exec: "newuidmap": executable file not found in $PATH
#### Solution
-Install a version of shadow-utils that includes these executables. Note RHEL7 and Centos 7 will not have support for this until RHEL7.7 is released.
+Install a version of shadow-utils that includes these executables. Note RHEL 7 and CentOS 7 will not have support for this until RHEL7.7 is released.
### 11) rootless setup user: invalid argument
@@ -424,9 +431,10 @@ Choose one of the following:
* Install the fuse-overlayfs package for your Linux Distribution.
* Add `mount_program = "/usr/bin/fuse-overlayfs"` under `[storage.options]` in your `~/.config/containers/storage.conf` file.
-### 17) rhel7-init based images don't work with cgroups v2
+### 17) RHEL 7 and CentOS 7 based `init` images don't work with cgroup v2
-The systemd version shipped in rhel7-init doesn't have support for cgroups v2. You'll need at least systemd 230.
+The systemd version shipped in RHEL 7 and CentOS 7 doesn't have support for cgroup v2. Support for cgroup V2 requires version 230 of systemd or newer, which
+was never shipped or supported on RHEL 7 or CentOS 7.
#### Symptom
```console
@@ -440,7 +448,15 @@ Error: non zero exit code: 1: OCI runtime error
#### Solution
You'll need to either:
-* configure the host to use cgroups v1
+* configure the host to use cgroup v1
+
+```
+On Fedora you can do:
+# dnf install -y grubby
+# grubby --update-kernel=ALL --args=”systemd.unified_cgroup_hierarchy=0"
+# reboot
+```
+
* update the image to use an updated version of systemd.
### 18) rootless containers exit once the user session exits
@@ -483,7 +499,7 @@ Unable to pull images
```console
$ podman unshare cat /proc/self/uid_map
- 0 1000 1
+ 0 1000 1
```
#### Solution
@@ -496,8 +512,8 @@ Original command now returns
```
$ podman unshare cat /proc/self/uid_map
- 0 1000 1
- 1 100000 65536
+ 0 1000 1
+ 1 100000 65536
```
Reference [subuid](http://man7.org/linux/man-pages/man5/subuid.5.html) and [subgid](http://man7.org/linux/man-pages/man5/subgid.5.html) man pages for more detail.
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index 48e621c99..7b60f8bb3 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -89,6 +89,8 @@ type User struct {
UID uint32 `json:"uid" platform:"linux,solaris"`
// GID is the group id.
GID uint32 `json:"gid" platform:"linux,solaris"`
+ // Umask is the umask for the init process.
+ Umask uint32 `json:"umask,omitempty" platform:"linux,solaris"`
// AdditionalGids are additional group ids set for the container's process.
AdditionalGids []uint32 `json:"additionalGids,omitempty" platform:"linux,solaris"`
// Username is the user name.
@@ -123,13 +125,26 @@ type Hook struct {
Timeout *int `json:"timeout,omitempty"`
}
+// Hooks specifies a command that is run in the container at a particular event in the lifecycle of a container
// Hooks for container setup and teardown
type Hooks struct {
- // Prestart is a list of hooks to be run before the container process is executed.
+ // Prestart is Deprecated. Prestart is a list of hooks to be run before the container process is executed.
+ // It is called in the Runtime Namespace
Prestart []Hook `json:"prestart,omitempty"`
+ // CreateRuntime is a list of hooks to be run after the container has been created but before pivot_root or any equivalent operation has been called
+ // It is called in the Runtime Namespace
+ CreateRuntime []Hook `json:"createRuntime,omitempty"`
+ // CreateContainer is a list of hooks to be run after the container has been created but before pivot_root or any equivalent operation has been called
+ // It is called in the Container Namespace
+ CreateContainer []Hook `json:"createContainer,omitempty"`
+ // StartContainer is a list of hooks to be run after the start operation is called but before the container process is started
+ // It is called in the Container Namespace
+ StartContainer []Hook `json:"startContainer,omitempty"`
// Poststart is a list of hooks to be run after the container process is started.
+ // It is called in the Runtime Namespace
Poststart []Hook `json:"poststart,omitempty"`
// Poststop is a list of hooks to be run after the container process exits.
+ // It is called in the Runtime Namespace
Poststop []Hook `json:"poststop,omitempty"`
}
@@ -165,6 +180,8 @@ type Linux struct {
// IntelRdt contains Intel Resource Director Technology (RDT) information for
// handling resource constraints (e.g., L3 cache, memory bandwidth) for the container
IntelRdt *LinuxIntelRdt `json:"intelRdt,omitempty"`
+ // Personality contains configuration for the Linux personality syscall
+ Personality *LinuxPersonality `json:"personality,omitempty"`
}
// LinuxNamespace is the configuration for a Linux namespace
@@ -291,6 +308,8 @@ type LinuxMemory struct {
Swappiness *uint64 `json:"swappiness,omitempty"`
// DisableOOMKiller disables the OOM killer for out of memory conditions
DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"`
+ // Enables hierarchical memory accounting
+ UseHierarchy *bool `json:"useHierarchy,omitempty"`
}
// LinuxCPU for Linux cgroup 'cpu' resource management
@@ -387,6 +406,28 @@ type LinuxDeviceCgroup struct {
Access string `json:"access,omitempty"`
}
+// LinuxPersonalityDomain refers to a personality domain.
+type LinuxPersonalityDomain string
+
+// LinuxPersonalityFlag refers to an additional personality flag. None are currently defined.
+type LinuxPersonalityFlag string
+
+// Define domain and flags for Personality
+const (
+ // PerLinux is the standard Linux personality
+ PerLinux LinuxPersonalityDomain = "LINUX"
+ // PerLinux32 sets personality to 32 bit
+ PerLinux32 LinuxPersonalityDomain = "LINUX32"
+)
+
+// LinuxPersonality represents the Linux personality syscall input
+type LinuxPersonality struct {
+ // Domain for the personality
+ Domain LinuxPersonalityDomain `json:"domain"`
+ // Additional flags
+ Flags []LinuxPersonalityFlag `json:"flags,omitempty"`
+}
+
// Solaris contains platform-specific configuration for Solaris application containers.
type Solaris struct {
// SMF FMRI which should go "online" before we start the container process.
@@ -556,12 +597,16 @@ type VMImage struct {
type LinuxSeccomp struct {
DefaultAction LinuxSeccompAction `json:"defaultAction"`
Architectures []Arch `json:"architectures,omitempty"`
+ Flags []LinuxSeccompFlag `json:"flags,omitempty"`
Syscalls []LinuxSyscall `json:"syscalls,omitempty"`
}
// Arch used for additional architectures
type Arch string
+// LinuxSeccompFlag is a flag to pass to seccomp(2).
+type LinuxSeccompFlag string
+
// Additional architectures permitted to be used for system calls
// By default only the native architecture of the kernel is permitted
const (
@@ -595,6 +640,7 @@ const (
ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO"
ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE"
ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW"
+ ActLog LinuxSeccompAction = "SCMP_ACT_LOG"
)
// LinuxSeccompOperator used to match syscall arguments in Seccomp
@@ -621,9 +667,10 @@ type LinuxSeccompArg struct {
// LinuxSyscall is used to match a syscall in Seccomp
type LinuxSyscall struct {
- Names []string `json:"names"`
- Action LinuxSeccompAction `json:"action"`
- Args []LinuxSeccompArg `json:"args,omitempty"`
+ Names []string `json:"names"`
+ Action LinuxSeccompAction `json:"action"`
+ ErrnoRet *uint `json:"errnoRet,omitempty"`
+ Args []LinuxSeccompArg `json:"args,omitempty"`
}
// LinuxIntelRdt has container runtime resource constraints for Intel RDT
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
index b920fc1b3..596af0c2f 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
@@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 0
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 1
+ VersionPatch = 2
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-dev"
diff --git a/vendor/github.com/seccomp/containers-golang/.gitignore b/vendor/github.com/seccomp/containers-golang/.gitignore
index 2cad96a16..e433eef88 100644
--- a/vendor/github.com/seccomp/containers-golang/.gitignore
+++ b/vendor/github.com/seccomp/containers-golang/.gitignore
@@ -1,2 +1,2 @@
-default.json
-fixtures
+*.orig
+generate
diff --git a/vendor/github.com/seccomp/containers-golang/LICENSE b/vendor/github.com/seccomp/containers-golang/LICENSE
new file mode 100644
index 000000000..bd465fcf0
--- /dev/null
+++ b/vendor/github.com/seccomp/containers-golang/LICENSE
@@ -0,0 +1,190 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2018-2019 github.com/seccomp authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/seccomp/containers-golang/Makefile b/vendor/github.com/seccomp/containers-golang/Makefile
index 88569e87b..2d91917f9 100644
--- a/vendor/github.com/seccomp/containers-golang/Makefile
+++ b/vendor/github.com/seccomp/containers-golang/Makefile
@@ -1,3 +1,5 @@
+export GO111MODULE=off
+
TAGS ?= seccomp
BUILDFLAGS := -tags "$(AUTOTAGS) $(TAGS)"
GO := go
@@ -5,14 +7,26 @@ PACKAGE := github.com/seccomp/containers-golang
sources := $(wildcard *.go)
-default.json: $(sources)
+.PHONY: seccomp.json
+seccomp.json: $(sources)
$(GO) build -compiler gc $(BUILDFLAGS) ./cmd/generate.go
$(GO) build -compiler gc ./cmd/generate.go
$(GO) run ${BUILDFLAGS} cmd/generate.go
-all: default.json
+all: seccomp.json
.PHONY: test-unit
test-unit:
- $(GO) test $(BUILDFLAGS) $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
- $(GO) test $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
+ $(GO) test -v $(BUILDFLAGS) $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
+ $(GO) test -v $(shell $(GO) list ./... | grep -v ^$(PACKAGE)/vendor)
+
+.PHONY: vendor
+vendor:
+ export GO111MODULE=on \
+ $(GO) mod tidy && \
+ $(GO) mod vendor && \
+ $(GO) mod verify
+
+.PHONY: clean
+clean:
+ rm -f generate
diff --git a/vendor/github.com/seccomp/containers-golang/README.md b/vendor/github.com/seccomp/containers-golang/README.md
index 1012baec3..a44238432 100644
--- a/vendor/github.com/seccomp/containers-golang/README.md
+++ b/vendor/github.com/seccomp/containers-golang/README.md
@@ -1,9 +1,13 @@
+# containers-golang
+
+[![CircleCI](https://circleci.com/gh/seccomp/containers-golang.svg?style=shield)](https://circleci.com/gh/seccomp/containers-golang)
+
`containers-golang` is a set of Go libraries used by container runtimes to generate and load seccomp mappings into the kernel.
seccomp (short for secure computing mode) is a BPF based syscall filter language and present a more conventional function-call based filtering interface that should be familiar to, and easily adopted by, application developers.
## Building
- make - Generates default.json file, which containes the whitelisted syscalls that can be used by container runtime engines like [CRI-O][cri-o], [Buildah][buildah], [Podman][podman] and [Docker][docker], and container runtimes like OCI [Runc][runc] to controll the syscalls available to containers.
+ make - Generates seccomp.json file, which contains the whitelisted syscalls that can be used by container runtime engines like [CRI-O][cri-o], [Buildah][buildah], [Podman][podman] and [Docker][docker], and container runtimes like OCI [Runc][runc] to controll the syscalls available to containers.
### Supported build tags
@@ -13,13 +17,9 @@ seccomp (short for secure computing mode) is a BPF based syscall filter language
When developing this library, please use `make` (or `make … BUILDTAGS=…`) to take advantage of the tests and validation.
-## License
-
-ASL 2.0
-
## Contact
-- IRC: #[CRI-O](irc://irc.freenode.net:6667/#cri-o) on freenode.net
+- IRC: #[containers](irc://irc.freenode.net:6667/#containers) on freenode.net
[cri-o]: https://github.com/kubernetes-incubator/cri-o/pulls
[buildah]: https://github.com/projectatomic/buildah
diff --git a/vendor/github.com/seccomp/containers-golang/go.mod b/vendor/github.com/seccomp/containers-golang/go.mod
new file mode 100644
index 000000000..2b56d46fd
--- /dev/null
+++ b/vendor/github.com/seccomp/containers-golang/go.mod
@@ -0,0 +1,16 @@
+module github.com/seccomp/containers-golang
+
+go 1.13
+
+require (
+ github.com/blang/semver v3.5.1+incompatible // indirect
+ github.com/hashicorp/go-multierror v1.0.0 // indirect
+ github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
+ github.com/opencontainers/runtime-tools v0.9.0
+ github.com/opencontainers/selinux v1.3.0 // indirect
+ github.com/seccomp/libseccomp-golang v0.9.1
+ github.com/sirupsen/logrus v1.4.2 // indirect
+ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // indirect
+ github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+ golang.org/x/sys v0.0.0-20190921190940-14da1ac737cc
+)
diff --git a/vendor/github.com/seccomp/containers-golang/go.sum b/vendor/github.com/seccomp/containers-golang/go.sum
new file mode 100644
index 000000000..ba00acd09
--- /dev/null
+++ b/vendor/github.com/seccomp/containers-golang/go.sum
@@ -0,0 +1,48 @@
+github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7 h1:Dliu5QO+4JYWu/yMshaMU7G3JN2POGpwjJN7gjy10Go=
+github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.1 h1:wY4pOY8fBdSIvs9+IDHC55thBuEulhzfSgKeC1yFvzQ=
+github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2-0.20191007145322-19e92ca81777 h1:7CkKaORyxoXsM8z56r+M0wf3uCpVGVqx4CWq7oJ/4DY=
+github.com/opencontainers/runtime-spec v1.0.2-0.20191007145322-19e92ca81777/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 h1:9mv9SC7GWmRWE0J/+oD8w3GsN2KYGKtg6uwLN7hfP5E=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-tools v0.9.0 h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU=
+github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg=
+github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
+github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqGe5TgR0g=
+github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
+github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
+github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
+github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190921190940-14da1ac737cc h1:EinpED/Eb9JUgDi6pkoFjw+tz69c3lHUZr2+Va84S0w=
+golang.org/x/sys v0.0.0-20190921190940-14da1ac737cc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/seccomp/containers-golang/seccomp.json b/vendor/github.com/seccomp/containers-golang/seccomp.json
index fe9eda56a..4c84d981f 100644
--- a/vendor/github.com/seccomp/containers-golang/seccomp.json
+++ b/vendor/github.com/seccomp/containers-golang/seccomp.json
@@ -52,6 +52,8 @@
"syscalls": [
{
"names": [
+ "_llseek",
+ "_newselect",
"accept",
"accept4",
"access",
@@ -118,6 +120,8 @@
"ftruncate64",
"futex",
"futimesat",
+ "get_robust_list",
+ "get_thread_area",
"getcpu",
"getcwd",
"getdents",
@@ -143,12 +147,10 @@
"getresuid",
"getresuid32",
"getrlimit",
- "get_robust_list",
"getrusage",
"getsid",
"getsockname",
"getsockopt",
- "get_thread_area",
"gettid",
"gettimeofday",
"getuid",
@@ -159,13 +161,13 @@
"inotify_init1",
"inotify_rm_watch",
"io_cancel",
- "ioctl",
"io_destroy",
"io_getevents",
- "ioprio_get",
- "ioprio_set",
"io_setup",
"io_submit",
+ "ioctl",
+ "ioprio_get",
+ "ioprio_set",
"ipc",
"kill",
"lchown",
@@ -176,7 +178,6 @@
"listen",
"listxattr",
"llistxattr",
- "_llseek",
"lremovexattr",
"lseek",
"lsetxattr",
@@ -194,6 +195,7 @@
"mlockall",
"mmap",
"mmap2",
+ "mount",
"mprotect",
"mq_getsetattr",
"mq_notify",
@@ -210,9 +212,9 @@
"munlock",
"munlockall",
"munmap",
+ "name_to_handle_at",
"nanosleep",
"newfstatat",
- "_newselect",
"open",
"openat",
"pause",
@@ -234,6 +236,7 @@
"readlink",
"readlinkat",
"readv",
+ "reboot",
"recv",
"recvfrom",
"recvmmsg",
@@ -253,11 +256,11 @@
"rt_sigsuspend",
"rt_sigtimedwait",
"rt_tgsigqueueinfo",
+ "sched_get_priority_max",
+ "sched_get_priority_min",
"sched_getaffinity",
"sched_getattr",
"sched_getparam",
- "sched_get_priority_max",
- "sched_get_priority_min",
"sched_getscheduler",
"sched_rr_get_interval",
"sched_setaffinity",
@@ -277,6 +280,9 @@
"sendmmsg",
"sendmsg",
"sendto",
+ "set_robust_list",
+ "set_thread_area",
+ "set_tid_address",
"setfsgid",
"setfsgid32",
"setfsuid",
@@ -297,11 +303,8 @@
"setreuid",
"setreuid32",
"setrlimit",
- "set_robust_list",
"setsid",
"setsockopt",
- "set_thread_area",
- "set_tid_address",
"setuid",
"setuid32",
"setxattr",
@@ -335,21 +338,24 @@
"time",
"timer_create",
"timer_delete",
- "timerfd_create",
- "timerfd_gettime",
- "timerfd_settime",
"timer_getoverrun",
"timer_gettime",
"timer_settime",
+ "timerfd_create",
+ "timerfd_gettime",
+ "timerfd_settime",
"times",
"tkill",
"truncate",
"truncate64",
"ugetrlimit",
"umask",
+ "umount",
+ "umount2",
"uname",
"unlink",
"unlinkat",
+ "unshare",
"utime",
"utimensat",
"utimes",
@@ -359,12 +365,7 @@
"waitid",
"waitpid",
"write",
- "writev",
- "mount",
- "umount2",
- "reboot",
- "name_to_handle_at",
- "unshare"
+ "writev"
],
"action": "SCMP_ACT_ALLOW",
"args": [],
@@ -770,4 +771,4 @@
"excludes": {}
}
]
-}
+} \ No newline at end of file
diff --git a/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go b/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go
index fde3cff75..e137a5887 100644
--- a/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go
+++ b/vendor/github.com/seccomp/containers-golang/seccomp_default_linux.go
@@ -1,5 +1,9 @@
// +build seccomp
+// SPDX-License-Identifier: Apache-2.0
+
+// Copyright 2013-2018 Docker, Inc.
+
package seccomp // import "github.com/seccomp/containers-golang"
import (
@@ -44,6 +48,8 @@ func DefaultProfile() *Seccomp {
syscalls := []*Syscall{
{
Names: []string{
+ "_llseek",
+ "_newselect",
"accept",
"accept4",
"access",
@@ -110,6 +116,8 @@ func DefaultProfile() *Seccomp {
"ftruncate64",
"futex",
"futimesat",
+ "get_robust_list",
+ "get_thread_area",
"getcpu",
"getcwd",
"getdents",
@@ -135,12 +143,10 @@ func DefaultProfile() *Seccomp {
"getresuid",
"getresuid32",
"getrlimit",
- "get_robust_list",
"getrusage",
"getsid",
"getsockname",
"getsockopt",
- "get_thread_area",
"gettid",
"gettimeofday",
"getuid",
@@ -151,13 +157,13 @@ func DefaultProfile() *Seccomp {
"inotify_init1",
"inotify_rm_watch",
"io_cancel",
- "ioctl",
"io_destroy",
"io_getevents",
- "ioprio_get",
- "ioprio_set",
"io_setup",
"io_submit",
+ "ioctl",
+ "ioprio_get",
+ "ioprio_set",
"ipc",
"kill",
"lchown",
@@ -168,7 +174,6 @@ func DefaultProfile() *Seccomp {
"listen",
"listxattr",
"llistxattr",
- "_llseek",
"lremovexattr",
"lseek",
"lsetxattr",
@@ -206,7 +211,6 @@ func DefaultProfile() *Seccomp {
"name_to_handle_at",
"nanosleep",
"newfstatat",
- "_newselect",
"open",
"openat",
"pause",
@@ -248,11 +252,11 @@ func DefaultProfile() *Seccomp {
"rt_sigsuspend",
"rt_sigtimedwait",
"rt_tgsigqueueinfo",
+ "sched_get_priority_max",
+ "sched_get_priority_min",
"sched_getaffinity",
"sched_getattr",
"sched_getparam",
- "sched_get_priority_max",
- "sched_get_priority_min",
"sched_getscheduler",
"sched_rr_get_interval",
"sched_setaffinity",
@@ -272,6 +276,9 @@ func DefaultProfile() *Seccomp {
"sendmmsg",
"sendmsg",
"sendto",
+ "set_robust_list",
+ "set_thread_area",
+ "set_tid_address",
"setfsgid",
"setfsgid32",
"setfsuid",
@@ -292,11 +299,8 @@ func DefaultProfile() *Seccomp {
"setreuid",
"setreuid32",
"setrlimit",
- "set_robust_list",
"setsid",
"setsockopt",
- "set_thread_area",
- "set_tid_address",
"setuid",
"setuid32",
"setxattr",
@@ -330,12 +334,12 @@ func DefaultProfile() *Seccomp {
"time",
"timer_create",
"timer_delete",
- "timerfd_create",
- "timerfd_gettime",
- "timerfd_settime",
"timer_getoverrun",
"timer_gettime",
"timer_settime",
+ "timerfd_create",
+ "timerfd_gettime",
+ "timerfd_settime",
"times",
"tkill",
"truncate",
@@ -343,9 +347,11 @@ func DefaultProfile() *Seccomp {
"ugetrlimit",
"umask",
"umount",
+ "umount2",
"uname",
"unlink",
"unlinkat",
+ "unshare",
"utime",
"utimensat",
"utimes",
diff --git a/vendor/github.com/seccomp/containers-golang/seccomp_linux.go b/vendor/github.com/seccomp/containers-golang/seccomp_linux.go
index 9a495e3e2..44dcd90b8 100644
--- a/vendor/github.com/seccomp/containers-golang/seccomp_linux.go
+++ b/vendor/github.com/seccomp/containers-golang/seccomp_linux.go
@@ -1,5 +1,9 @@
// +build seccomp
+// SPDX-License-Identifier: Apache-2.0
+
+// Copyright 2013-2018 Docker, Inc.
+
package seccomp // import "github.com/seccomp/containers-golang"
import (
@@ -9,6 +13,7 @@ import (
"github.com/opencontainers/runtime-spec/specs-go"
libseccomp "github.com/seccomp/libseccomp-golang"
+ "golang.org/x/sys/unix"
)
//go:generate go run -tags 'seccomp' generate.go
@@ -22,11 +27,25 @@ func GetDefaultProfile(rs *specs.Spec) (*specs.LinuxSeccomp, error) {
func LoadProfile(body string, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
var config Seccomp
if err := json.Unmarshal([]byte(body), &config); err != nil {
- return nil, fmt.Errorf("Decoding seccomp profile failed: %v", err)
+ return nil, fmt.Errorf("decoding seccomp profile failed: %v", err)
}
return setupSeccomp(&config, rs)
}
+// LoadProfileFromBytes takes a byte slice and decodes the seccomp profile.
+func LoadProfileFromBytes(body []byte, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
+ config := &Seccomp{}
+ if err := json.Unmarshal(body, config); err != nil {
+ return nil, fmt.Errorf("decoding seccomp profile failed: %v", err)
+ }
+ return setupSeccomp(config, rs)
+}
+
+// LoadProfileFromConfig takes a Seccomp struct and a spec to retrieve a LinuxSeccomp
+func LoadProfileFromConfig(config *Seccomp, specgen *specs.Spec) (*specs.LinuxSeccomp, error) {
+ return setupSeccomp(config, specgen)
+}
+
var nativeToSeccomp = map[string]Arch{
"amd64": ArchX86_64,
"arm64": ArchAARCH64,
@@ -127,21 +146,22 @@ Loop:
}
if call.Name != "" {
- newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall(call.Name, call.Action, call.Args))
+ newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall([]string{call.Name}, call.Action, call.Args, call.ErrnoRet))
}
- for _, n := range call.Names {
- newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall(n, call.Action, call.Args))
+ if len(call.Names) > 0 {
+ newConfig.Syscalls = append(newConfig.Syscalls, createSpecsSyscall(call.Names, call.Action, call.Args, call.ErrnoRet))
}
}
return newConfig, nil
}
-func createSpecsSyscall(name string, action Action, args []*Arg) specs.LinuxSyscall {
+func createSpecsSyscall(names []string, action Action, args []*Arg, errnoRet *uint) specs.LinuxSyscall {
newCall := specs.LinuxSyscall{
- Names: []string{name},
- Action: specs.LinuxSeccompAction(action),
+ Names: names,
+ Action: specs.LinuxSeccompAction(action),
+ ErrnoRet: errnoRet,
}
// Loop through all the arguments of the syscall and convert them
@@ -157,3 +177,15 @@ func createSpecsSyscall(name string, action Action, args []*Arg) specs.LinuxSysc
}
return newCall
}
+
+// IsEnabled returns true if seccomp is enabled for the host.
+func IsEnabled() bool {
+ // Check if Seccomp is supported, via CONFIG_SECCOMP.
+ if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
+ // Make sure the kernel has CONFIG_SECCOMP_FILTER.
+ if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/seccomp/containers-golang/seccomp_unsupported.go b/vendor/github.com/seccomp/containers-golang/seccomp_unsupported.go
index 279340426..936a9a641 100644
--- a/vendor/github.com/seccomp/containers-golang/seccomp_unsupported.go
+++ b/vendor/github.com/seccomp/containers-golang/seccomp_unsupported.go
@@ -1,5 +1,9 @@
// +build !seccomp
+// SPDX-License-Identifier: Apache-2.0
+
+// Copyright 2013-2018 Docker, Inc.
+
package seccomp // import "github.com/seccomp/containers-golang"
import (
@@ -22,3 +26,18 @@ func LoadProfile(body string, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
func GetDefaultProfile(rs *specs.Spec) (*specs.LinuxSeccomp, error) {
return nil, fmt.Errorf("Seccomp not supported on this platform")
}
+
+// LoadProfileFromBytes takes a byte slice and decodes the seccomp profile.
+func LoadProfileFromBytes(body []byte, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
+ return nil, fmt.Errorf("Seccomp not supported on this platform")
+}
+
+// LoadProfileFromConfig takes a Seccomp struct and a spec to retrieve a LinuxSeccomp
+func LoadProfileFromConfig(config *Seccomp, specgen *specs.Spec) (*specs.LinuxSeccomp, error) {
+ return nil, fmt.Errorf("Seccomp not supported on this platform")
+}
+
+// IsEnabled returns true if seccomp is enabled for the host.
+func IsEnabled() bool {
+ return false
+}
diff --git a/vendor/github.com/seccomp/containers-golang/types.go b/vendor/github.com/seccomp/containers-golang/types.go
index b549a55fe..6651c423f 100644
--- a/vendor/github.com/seccomp/containers-golang/types.go
+++ b/vendor/github.com/seccomp/containers-golang/types.go
@@ -1,5 +1,9 @@
package seccomp // import "github.com/seccomp/containers-golang"
+// SPDX-License-Identifier: Apache-2.0
+
+// Copyright 2013-2018 Docker, Inc.
+
// Seccomp represents the config for a seccomp profile for syscall restriction.
type Seccomp struct {
DefaultAction Action `json:"defaultAction"`
@@ -90,4 +94,5 @@ type Syscall struct {
Comment string `json:"comment"`
Includes Filter `json:"includes"`
Excludes Filter `json:"excludes"`
+ ErrnoRet *uint `json:"errnoRet,omitempty"`
}
diff --git a/vendor/github.com/seccomp/containers-golang/vendor.conf b/vendor/github.com/seccomp/containers-golang/vendor.conf
deleted file mode 100644
index 6111c475b..000000000
--- a/vendor/github.com/seccomp/containers-golang/vendor.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-github.com/opencontainers/runtime-tools master
-github.com/blang/semver master
-github.com/hashicorp/go-multierror master
-github.com/hashicorp/errwrap master
-github.com/syndtr/gocapability master
-github.com/xeipuuv/gojsonschema master
-github.com/xeipuuv/gojsonreference master
-github.com/xeipuuv/gojsonpointer master
-
diff --git a/vendor/modules.txt b/vendor/modules.txt
index ed3c9df85..d396297c9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -412,7 +412,7 @@ github.com/opencontainers/runc/libcontainer/devices
github.com/opencontainers/runc/libcontainer/system
github.com/opencontainers/runc/libcontainer/user
github.com/opencontainers/runc/libcontainer/utils
-# github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7
+# github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
github.com/opencontainers/runtime-spec/specs-go
# github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/runtime-tools/error
@@ -477,7 +477,7 @@ github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy
github.com/rootless-containers/rootlesskit/pkg/port/portutil
# github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8
github.com/safchain/ethtool
-# github.com/seccomp/containers-golang v0.0.0-20190312124753-8ca8945ccf5f
+# github.com/seccomp/containers-golang v0.4.1
github.com/seccomp/containers-golang
# github.com/seccomp/libseccomp-golang v0.9.1
github.com/seccomp/libseccomp-golang