diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/image/image.go | 6 | ||||
-rw-r--r-- | libpod/image/image_test.go | 2 | ||||
-rw-r--r-- | libpod/oci_attach_linux.go | 6 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 37 | ||||
-rw-r--r-- | libpod/podfilters/pods.go | 115 |
5 files changed, 152 insertions, 14 deletions
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_attach_linux.go b/libpod/oci_attach_linux.go index 433993edb..fb0a54bff 100644 --- a/libpod/oci_attach_linux.go +++ b/libpod/oci_attach_linux.go @@ -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 diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index ce888c690..6a0097b8e 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -575,13 +575,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 +808,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() diff --git a/libpod/podfilters/pods.go b/libpod/podfilters/pods.go new file mode 100644 index 000000000..54fa85edc --- /dev/null +++ b/libpod/podfilters/pods.go @@ -0,0 +1,115 @@ +package podfilters + +import ( + "strconv" + "strings" + + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/pkg/util" + "github.com/pkg/errors" +) + +// GeneratePodFilterFunc takes a filter and filtervalue (key, value) +// and generates a libpod function that can be used to filter +// pods +func GeneratePodFilterFunc(filter, filterValue string) ( + func(pod *libpod.Pod) bool, error) { + switch filter { + case "ctr-ids": + return func(p *libpod.Pod) bool { + ctrIds, err := p.AllContainersByID() + if err != nil { + return false + } + return util.StringInSlice(filterValue, ctrIds) + }, nil + case "ctr-names": + return func(p *libpod.Pod) bool { + ctrs, err := p.AllContainers() + if err != nil { + return false + } + for _, ctr := range ctrs { + if filterValue == ctr.Name() { + return true + } + } + return false + }, nil + case "ctr-number": + return func(p *libpod.Pod) bool { + ctrIds, err := p.AllContainersByID() + if err != nil { + return false + } + + fVint, err2 := strconv.Atoi(filterValue) + if err2 != nil { + return false + } + return len(ctrIds) == fVint + }, nil + case "ctr-status": + if !util.StringInSlice(filterValue, + []string{"created", "restarting", "running", "paused", + "exited", "unknown"}) { + return nil, errors.Errorf("%s is not a valid status", filterValue) + } + return func(p *libpod.Pod) bool { + ctr_statuses, err := p.Status() + if err != nil { + return false + } + for _, ctr_status := range ctr_statuses { + state := ctr_status.String() + if ctr_status == define.ContainerStateConfigured { + state = "created" + } + if state == filterValue { + return true + } + } + return false + }, nil + case "id": + return func(p *libpod.Pod) bool { + return strings.Contains(p.ID(), filterValue) + }, nil + case "name": + return func(p *libpod.Pod) bool { + return strings.Contains(p.Name(), filterValue) + }, nil + case "status": + if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created"}) { + return nil, errors.Errorf("%s is not a valid pod status", filterValue) + } + return func(p *libpod.Pod) bool { + status, err := p.GetPodStatus() + if err != nil { + return false + } + if strings.ToLower(status) == filterValue { + return true + } + return false + }, nil + case "label": + var filterArray = strings.SplitN(filterValue, "=", 2) + var filterKey = filterArray[0] + if len(filterArray) > 1 { + filterValue = filterArray[1] + } else { + filterValue = "" + } + return func(p *libpod.Pod) bool { + for labelKey, labelValue := range p.Labels() { + if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) { + return true + } + } + return false + }, nil + } + return nil, errors.Errorf("%s is an invalid filter", filter) +} |