aboutsummaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_api.go24
-rw-r--r--libpod/container_exec.go4
-rw-r--r--libpod/container_top_linux.go2
-rw-r--r--libpod/define/config.go31
-rw-r--r--libpod/healthcheck.go2
-rw-r--r--libpod/image/image.go6
-rw-r--r--libpod/image/image_test.go2
-rw-r--r--libpod/oci.go4
-rw-r--r--libpod/oci_attach_linux.go14
-rw-r--r--libpod/oci_attach_unsupported.go4
-rw-r--r--libpod/oci_conmon_linux.go49
-rw-r--r--libpod/options.go2
12 files changed, 95 insertions, 49 deletions
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 967180437..55c79fa74 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -3,7 +3,6 @@ package libpod
import (
"bufio"
"context"
- "io"
"io/ioutil"
"net"
"os"
@@ -96,7 +95,7 @@ func (c *Container) Start(ctx context.Context, recursive bool) (err error) {
// The channel will be closed automatically after the result of attach has been
// sent.
// If recursive is set, StartAndAttach will also start all containers this container depends on.
-func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, recursive bool) (attachResChan <-chan error, err error) {
+func (c *Container) StartAndAttach(ctx context.Context, streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, recursive bool) (attachResChan <-chan error, err error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -213,29 +212,10 @@ func (c *Container) Kill(signal uint) error {
return c.save()
}
-// AttachStreams contains streams that will be attached to the container
-type AttachStreams struct {
- // OutputStream will be attached to container's STDOUT
- OutputStream io.WriteCloser
- // ErrorStream will be attached to container's STDERR
- ErrorStream io.WriteCloser
- // InputStream will be attached to container's STDIN
- InputStream *bufio.Reader
- // AttachOutput is whether to attach to STDOUT
- // If false, stdout will not be attached
- AttachOutput bool
- // AttachError is whether to attach to STDERR
- // If false, stdout will not be attached
- AttachError bool
- // AttachInput is whether to attach to STDIN
- // If false, stdout will not be attached
- AttachInput bool
-}
-
// Attach attaches to a container.
// This function returns when the attach finishes. It does not hold the lock for
// the duration of its runtime, only using it at the beginning to verify state.
-func (c *Container) Attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) error {
+func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize) error {
if !c.batched {
c.lock.Lock()
if err := c.syncContainer(); err != nil {
diff --git a/libpod/container_exec.go b/libpod/container_exec.go
index 5469462f8..c1ce8b724 100644
--- a/libpod/container_exec.go
+++ b/libpod/container_exec.go
@@ -221,7 +221,7 @@ func (c *Container) ExecStart(sessionID string) error {
// ExecStartAndAttach starts and attaches to an exec session in a container.
// TODO: Should we include detach keys in the signature to allow override?
// TODO: How do we handle AttachStdin/AttachStdout/AttachStderr?
-func (c *Container) ExecStartAndAttach(sessionID string, streams *AttachStreams) error {
+func (c *Container) ExecStartAndAttach(sessionID string, streams *define.AttachStreams) error {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -544,7 +544,7 @@ func (c *Container) ExecResize(sessionID string, newSize remotecommand.TerminalS
// Exec emulates the old Libpod exec API, providing a single call to create,
// run, and remove an exec session. Returns exit code and error. Exit code is
// not guaranteed to be set sanely if error is not nil.
-func (c *Container) Exec(config *ExecConfig, streams *AttachStreams, resize <-chan remotecommand.TerminalSize) (int, error) {
+func (c *Container) Exec(config *ExecConfig, streams *define.AttachStreams, resize <-chan remotecommand.TerminalSize) (int, error) {
sessionID, err := c.ExecCreate(config)
if err != nil {
return -1, err
diff --git a/libpod/container_top_linux.go b/libpod/container_top_linux.go
index 2a35a2ae9..98a69966a 100644
--- a/libpod/container_top_linux.go
+++ b/libpod/container_top_linux.go
@@ -112,7 +112,7 @@ func (c *Container) execPS(args []string) ([]string, error) {
defer wErrPipe.Close()
defer rErrPipe.Close()
- streams := new(AttachStreams)
+ streams := new(define.AttachStreams)
streams.OutputStream = wPipe
streams.ErrorStream = wErrPipe
streams.AttachOutput = true
diff --git a/libpod/define/config.go b/libpod/define/config.go
index 5598f97a3..10e00062a 100644
--- a/libpod/define/config.go
+++ b/libpod/define/config.go
@@ -1,5 +1,10 @@
package define
+import (
+ "bufio"
+ "io"
+)
+
var (
// DefaultInfraImage to use for infra container
DefaultInfraImage = "k8s.gcr.io/pause:3.2"
@@ -26,3 +31,29 @@ type InfoData struct {
// VolumeDriverLocal is the "local" volume driver. It is managed by libpod
// itself.
const VolumeDriverLocal = "local"
+
+const (
+ OCIManifestDir = "oci-dir"
+ OCIArchive = "oci-archive"
+ V2s2ManifestDir = "docker-dir"
+ V2s2Archive = "docker-archive"
+)
+
+// AttachStreams contains streams that will be attached to the container
+type AttachStreams struct {
+ // OutputStream will be attached to container's STDOUT
+ OutputStream io.WriteCloser
+ // ErrorStream will be attached to container's STDERR
+ ErrorStream io.WriteCloser
+ // InputStream will be attached to container's STDIN
+ InputStream *bufio.Reader
+ // AttachOutput is whether to attach to STDOUT
+ // If false, stdout will not be attached
+ AttachOutput bool
+ // AttachError is whether to attach to STDERR
+ // If false, stdout will not be attached
+ AttachError bool
+ // AttachInput is whether to attach to STDIN
+ // If false, stdout will not be attached
+ AttachInput bool
+}
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
index 08a613dfe..daddb6561 100644
--- a/libpod/healthcheck.go
+++ b/libpod/healthcheck.go
@@ -108,7 +108,7 @@ func (c *Container) runHealthCheck() (HealthCheckStatus, error) {
hcw := hcWriteCloser{
captureBuffer,
}
- streams := new(AttachStreams)
+ streams := new(define.AttachStreams)
streams.OutputStream = hcw
streams.ErrorStream = hcw
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 5f914ed79..80cc6f15a 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -512,8 +512,8 @@ func getImageDigest(ctx context.Context, src types.ImageReference, sc *types.Sys
return "@" + imageDigest.Hex(), nil
}
-// normalizedTag returns the canonical version of tag for use in Image.Names()
-func normalizedTag(tag string) (reference.Named, error) {
+// NormalizedTag returns the canonical version of tag for use in Image.Names()
+func NormalizedTag(tag string) (reference.Named, error) {
decomposedTag, err := decompose(tag)
if err != nil {
return nil, err
@@ -541,7 +541,7 @@ func (i *Image) TagImage(tag string) error {
if err := i.reloadImage(); err != nil {
return err
}
- ref, err := normalizedTag(tag)
+ ref, err := NormalizedTag(tag)
if err != nil {
return err
}
diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go
index 19f7eee1e..3cd368cdc 100644
--- a/libpod/image/image_test.go
+++ b/libpod/image/image_test.go
@@ -292,7 +292,7 @@ func TestNormalizedTag(t *testing.T) {
{"ns/busybox:latest", "localhost/ns/busybox:latest"}, // Unqualified with a dot-less namespace
{"docker.io/busybox:latest", "docker.io/library/busybox:latest"}, // docker.io without /library/
} {
- res, err := normalizedTag(c.input)
+ res, err := NormalizedTag(c.input)
if c.expected == "" {
assert.Error(t, err, c.input)
} else {
diff --git a/libpod/oci.go b/libpod/oci.go
index ef46cf5c3..e4fbcb62e 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -4,6 +4,8 @@ import (
"bufio"
"net"
+ "github.com/containers/libpod/libpod/define"
+
"k8s.io/client-go/tools/remotecommand"
)
@@ -141,7 +143,7 @@ type ExecOptions struct {
// the container was run as will be used.
User string
// Streams are the streams that will be attached to the container.
- Streams *AttachStreams
+ Streams *define.AttachStreams
// PreserveFDs is a number of additional file descriptors (in addition
// to 0, 1, 2) that will be passed to the executed process. The total FDs
// passed will be 3 + PreserveFDs.
diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go
index 433993edb..ff158c2d1 100644
--- a/libpod/oci_attach_linux.go
+++ b/libpod/oci_attach_linux.go
@@ -31,7 +31,7 @@ const (
// Attach to the given container
// Does not check if state is appropriate
// started is only required if startContainer is true
-func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
+func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
}
@@ -94,7 +94,7 @@ func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan re
// 4. attachToExec sends on startFd, signalling it has attached to the socket and child is ready to go
// 5. child receives on startFd, runs the runtime exec command
// attachToExec is responsible for closing startFd and attachFd
-func (c *Container) attachToExec(streams *AttachStreams, keys *string, sessionID string, startFd, attachFd *os.File) error {
+func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, sessionID string, startFd, attachFd *os.File) error {
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
}
@@ -189,7 +189,7 @@ func buildSocketPath(socketPath string) string {
return socketPath
}
-func setupStdioChannels(streams *AttachStreams, conn *net.UnixConn, detachKeys []byte) (chan error, chan error) {
+func setupStdioChannels(streams *define.AttachStreams, conn *net.UnixConn, detachKeys []byte) (chan error, chan error) {
receiveStdoutError := make(chan error)
go func() {
receiveStdoutError <- redirectResponseToOutputStreams(streams.OutputStream, streams.ErrorStream, streams.AttachOutput, streams.AttachError, conn)
@@ -200,8 +200,10 @@ func setupStdioChannels(streams *AttachStreams, conn *net.UnixConn, detachKeys [
var err error
if streams.AttachInput {
_, err = utils.CopyDetachable(conn, streams.InputStream, detachKeys)
- if connErr := conn.CloseWrite(); connErr != nil {
- logrus.Errorf("unable to close conn: %q", connErr)
+ if err == nil {
+ if connErr := conn.CloseWrite(); connErr != nil {
+ logrus.Errorf("unable to close conn: %q", connErr)
+ }
}
}
stdinDone <- err
@@ -255,7 +257,7 @@ func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeO
return err
}
-func readStdio(streams *AttachStreams, receiveStdoutError, stdinDone chan error) error {
+func readStdio(streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error {
var err error
select {
case err = <-receiveStdoutError:
diff --git a/libpod/oci_attach_unsupported.go b/libpod/oci_attach_unsupported.go
index 987d2c973..3b0216e5d 100644
--- a/libpod/oci_attach_unsupported.go
+++ b/libpod/oci_attach_unsupported.go
@@ -9,10 +9,10 @@ import (
"k8s.io/client-go/tools/remotecommand"
)
-func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
+func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, started chan bool) error {
return define.ErrNotImplemented
}
-func (c *Container) attachToExec(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, sessionID string, startFd *os.File, attachFd *os.File) error {
+func (c *Container) attachToExec(streams *define.AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, sessionID string, startFd *os.File, attachFd *os.File) error {
return define.ErrNotImplemented
}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index ce888c690..2e96dbe57 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -353,6 +353,9 @@ func (r *ConmonOCIRuntime) StartContainer(ctr *Container) error {
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify))
}
+ if path, ok := os.LookupEnv("PATH"); ok {
+ env = append(env, fmt.Sprintf("PATH=%s", path))
+ }
if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, "start", ctr.ID()); err != nil {
return err
}
@@ -575,13 +578,36 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, httpConn net.Conn, httpBuf
}
}
+// isRetryable returns whether the error was caused by a blocked syscall or the
+// specified operation on a non blocking file descriptor wasn't ready for completion.
+func isRetryable(err error) bool {
+ if errno, isErrno := errors.Cause(err).(syscall.Errno); isErrno {
+ return errno == syscall.EINTR || errno == syscall.EAGAIN
+ }
+ return false
+}
+
+// openControlFile opens the terminal control file.
+func openControlFile(ctr *Container, parentDir string) (*os.File, error) {
+ controlPath := filepath.Join(parentDir, "ctl")
+ for i := 0; i < 600; i++ {
+ controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY|unix.O_NONBLOCK, 0)
+ if err == nil {
+ return controlFile, err
+ }
+ if !isRetryable(err) {
+ return nil, errors.Wrapf(err, "could not open ctl file for terminal resize for container %s", ctr.ID())
+ }
+ time.Sleep(time.Second / 10)
+ }
+ return nil, errors.Errorf("timeout waiting for %q", controlPath)
+}
+
// AttachResize resizes the terminal used by the given container.
func (r *ConmonOCIRuntime) AttachResize(ctr *Container, newSize remotecommand.TerminalSize) error {
- // TODO: probably want a dedicated function to get ctl file path?
- controlPath := filepath.Join(ctr.bundlePath(), "ctl")
- controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
+ controlFile, err := openControlFile(ctr, ctr.bundlePath())
if err != nil {
- return errors.Wrapf(err, "could not open ctl file for terminal resize")
+ return err
}
defer controlFile.Close()
@@ -785,11 +811,9 @@ func (r *ConmonOCIRuntime) ExecContainer(c *Container, sessionID string, options
// ExecAttachResize resizes the TTY of the given exec session.
func (r *ConmonOCIRuntime) ExecAttachResize(ctr *Container, sessionID string, newSize remotecommand.TerminalSize) error {
- // TODO: probably want a dedicated function to get ctl file path?
- controlPath := filepath.Join(ctr.execBundlePath(sessionID), "ctl")
- controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0)
+ controlFile, err := openControlFile(ctr, ctr.execBundlePath(sessionID))
if err != nil {
- return errors.Wrapf(err, "could not open ctl file for terminal resize for container %s exec session %s", ctr.ID(), sessionID)
+ return err
}
defer controlFile.Close()
@@ -909,6 +933,13 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container
if options.TCPEstablished {
args = append(args, "--tcp-established")
}
+ runtimeDir, err := util.GetRuntimeDir()
+ if err != nil {
+ return err
+ }
+ if err = os.Setenv("XDG_RUNTIME_DIR", runtimeDir); err != nil {
+ return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
+ }
args = append(args, ctr.ID())
return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...)
}
@@ -918,7 +949,7 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container
func (r *ConmonOCIRuntime) SupportsCheckpoint() bool {
// Check if the runtime implements checkpointing. Currently only
// runc's checkpoint/restore implementation is supported.
- cmd := exec.Command(r.path, "checkpoint", "-h")
+ cmd := exec.Command(r.path, "checkpoint", "--help")
if err := cmd.Start(); err != nil {
return false
}
diff --git a/libpod/options.go b/libpod/options.go
index dfbec364a..65a089131 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1334,7 +1334,7 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption {
}
destinations[vol.Dest] = true
- mountOpts, err := util.ProcessOptions(vol.Options, false, nil)
+ mountOpts, err := util.ProcessOptions(vol.Options, false, "")
if err != nil {
return errors.Wrapf(err, "error processing options for named volume %q mounted at %q", vol.Name, vol.Dest)
}