summaryrefslogtreecommitdiff
path: root/pkg/domain/infra
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/domain/infra')
-rw-r--r--pkg/domain/infra/abi/containers.go116
-rw-r--r--pkg/domain/infra/tunnel/containers.go69
-rw-r--r--pkg/domain/infra/tunnel/events.go32
-rw-r--r--pkg/domain/infra/tunnel/images.go7
4 files changed, 160 insertions, 64 deletions
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 21618f555..8b0d53940 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1142,12 +1142,12 @@ func (ic *ContainerEngine) Shutdown(_ context.Context) {
})
}
-func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) error {
- defer close(options.StatChan)
+func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) (statsChan chan entities.ContainerStatsReport, err error) {
+ statsChan = make(chan entities.ContainerStatsReport, 1)
+
containerFunc := ic.Libpod.GetRunningContainers
+ queryAll := false
switch {
- case len(namesOrIds) > 0:
- containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
case options.Latest:
containerFunc = func() ([]*libpod.Container, error) {
lastCtr, err := ic.Libpod.GetLatestContainer()
@@ -1156,62 +1156,76 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
}
return []*libpod.Container{lastCtr}, nil
}
- case options.All:
+ case len(namesOrIds) > 0:
+ containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
+ default:
+ // No containers, no latest -> query all!
+ queryAll = true
containerFunc = ic.Libpod.GetAllContainers
}
- ctrs, err := containerFunc()
- if err != nil {
- return errors.Wrapf(err, "unable to get list of containers")
- }
- containerStats := map[string]*define.ContainerStats{}
- for _, ctr := range ctrs {
- initialStats, err := ctr.GetContainerStats(&define.ContainerStats{})
- if err != nil {
- // when doing "all", don't worry about containers that are not running
- cause := errors.Cause(err)
- if options.All && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
- continue
- }
- if cause == cgroups.ErrCgroupV1Rootless {
- err = cause
- }
- return err
+ go func() {
+ defer close(statsChan)
+ var (
+ err error
+ containers []*libpod.Container
+ containerStats map[string]*define.ContainerStats
+ )
+ containerStats = make(map[string]*define.ContainerStats)
+
+ stream: // label to flatten the scope
+ select {
+ case <-ctx.Done():
+ // client cancelled
+ logrus.Debugf("Container stats stopped: context cancelled")
+ return
+ default:
+ // just fall through and do work
}
- containerStats[ctr.ID()] = initialStats
- }
- for {
- reportStats := []*define.ContainerStats{}
- for _, ctr := range ctrs {
- id := ctr.ID()
- if _, ok := containerStats[ctr.ID()]; !ok {
- initialStats, err := ctr.GetContainerStats(&define.ContainerStats{})
- if errors.Cause(err) == define.ErrCtrRemoved || errors.Cause(err) == define.ErrNoSuchCtr || errors.Cause(err) == define.ErrCtrStateInvalid {
- // skip dealing with a container that is gone
- continue
+
+ // Anonymous func to easily use the return values for streaming.
+ computeStats := func() ([]define.ContainerStats, error) {
+ containers, err = containerFunc()
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to get list of containers")
+ }
+
+ reportStats := []define.ContainerStats{}
+ for _, ctr := range containers {
+ prev, ok := containerStats[ctr.ID()]
+ if !ok {
+ prev = &define.ContainerStats{}
}
+
+ stats, err := ctr.GetContainerStats(prev)
if err != nil {
- return err
+ cause := errors.Cause(err)
+ if queryAll && (cause == define.ErrCtrRemoved || cause == define.ErrNoSuchCtr || cause == define.ErrCtrStateInvalid) {
+ continue
+ }
+ if cause == cgroups.ErrCgroupV1Rootless {
+ err = cause
+ }
+ return nil, err
}
- containerStats[id] = initialStats
- }
- stats, err := ctr.GetContainerStats(containerStats[id])
- if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
- return err
+
+ containerStats[ctr.ID()] = stats
+ reportStats = append(reportStats, *stats)
}
- // replace the previous measurement with the current one
- containerStats[id] = stats
- reportStats = append(reportStats, stats)
+ return reportStats, nil
}
- ctrs, err = containerFunc()
- if err != nil {
- return err
- }
- options.StatChan <- reportStats
- if options.NoStream {
- break
+
+ report := entities.ContainerStatsReport{}
+ report.Stats, report.Error = computeStats()
+ statsChan <- report
+
+ if report.Error != nil || !options.Stream {
+ return
}
+
time.Sleep(time.Second)
- }
- return nil
+ goto stream
+ }()
+
+ return statsChan, nil
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index d0f90d900..9b03503c6 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -481,27 +481,67 @@ func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input,
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
reports := []*entities.ContainerStartReport{}
- for _, name := range namesOrIds {
+ var exitCode = define.ExecErrorCodeGeneric
+ ctrs, err := getContainersByContext(ic.ClientCxt, false, false, namesOrIds)
+ if err != nil {
+ return nil, err
+ }
+ // There can only be one container if attach was used
+ for i, ctr := range ctrs {
+ name := ctr.ID
report := entities.ContainerStartReport{
Id: name,
- RawInput: name,
- ExitCode: 125,
+ RawInput: namesOrIds[i],
+ ExitCode: exitCode,
}
+ ctrRunning := ctr.State == define.ContainerStateRunning.String()
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)
+ err = startAndAttach(ic, name, &options.DetachKeys, options.Stdin, options.Stdout, options.Stderr)
+ if err == define.ErrDetach {
+ // User manually detached
+ // Exit cleanly immediately
+ report.Err = err
+ reports = append(reports, &report)
+ return reports, nil
+ }
+ if ctrRunning {
+ reports = append(reports, &report)
+ return reports, nil
+ }
+
+ if err != nil {
+ report.ExitCode = define.ExitCode(report.Err)
+ report.Err = err
+ reports = append(reports, &report)
+ return reports, errors.Wrapf(report.Err, "unable to start container %s", name)
+ }
+ exitCode, err := containers.Wait(ic.ClientCxt, name, nil)
+ if err == define.ErrNoSuchCtr {
+ // Check events
+ event, err := ic.GetLastContainerEvent(ctx, name, events.Exited)
+ if err != nil {
+ logrus.Errorf("Cannot get exit code: %v", err)
+ report.ExitCode = define.ExecErrorCodeNotFound
+ } else {
+ report.ExitCode = event.ContainerExitCode
}
} else {
- report.ExitCode = define.ExitCode(report.Err)
+ report.ExitCode = int(exitCode)
}
reports = append(reports, &report)
return reports, nil
}
- report.Err = containers.Start(ic.ClientCxt, name, &options.DetachKeys)
- report.ExitCode = define.ExitCode(report.Err)
+ // Start the container if it's not running already.
+ if !ctrRunning {
+ err = containers.Start(ic.ClientCxt, name, &options.DetachKeys)
+ if err != nil {
+ report.Err = errors.Wrapf(err, "unable to start container %q", name)
+ report.ExitCode = define.ExitCode(err)
+ reports = append(reports, &report)
+ continue
+ }
+ }
+ report.ExitCode = 0
reports = append(reports, &report)
}
return reports, nil
@@ -682,6 +722,9 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string,
func (ic *ContainerEngine) Shutdown(_ context.Context) {
}
-func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) error {
- return errors.New("not implemented")
+func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []string, options entities.ContainerStatsOptions) (statsChan chan entities.ContainerStatsReport, err error) {
+ if options.Latest {
+ return nil, errors.New("latest is not supported for the remote client")
+ }
+ return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
}
diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go
index e6f4834b9..53bae6cef 100644
--- a/pkg/domain/infra/tunnel/events.go
+++ b/pkg/domain/infra/tunnel/events.go
@@ -2,8 +2,10 @@ package tunnel
import (
"context"
+ // "fmt"
"strings"
+ "github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/pkg/bindings/system"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
@@ -29,3 +31,33 @@ func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptio
}()
return system.Events(ic.ClientCxt, binChan, nil, &opts.Since, &opts.Until, filters, &opts.Stream)
}
+
+// GetLastContainerEvent takes a container name or ID and an event status and returns
+// the last occurrence of the container event
+func (ic *ContainerEngine) GetLastContainerEvent(ctx context.Context, nameOrID string, containerEvent events.Status) (*events.Event, error) {
+ // check to make sure the event.Status is valid
+ if _, err := events.StringToStatus(containerEvent.String()); err != nil {
+ return nil, err
+ }
+ var event events.Event
+ return &event, nil
+
+ /*
+ FIXME: We need new bindings for this section
+ filters := []string{
+ fmt.Sprintf("container=%s", nameOrID),
+ fmt.Sprintf("event=%s", containerEvent),
+ "type=container",
+ }
+
+ containerEvents, err := system.GetEvents(ctx, entities.EventsOptions{Filter: filters})
+ if err != nil {
+ return nil, err
+ }
+ if len(containerEvents) < 1 {
+ return nil, errors.Wrapf(events.ErrEventNotFound, "%s not found", containerEvent.String())
+ }
+ // return the last element in the slice
+ return containerEvents[len(containerEvents)-1], nil
+ */
+}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 332a7c2eb..981884109 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -199,6 +199,13 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions)
return nil, err
}
defer f.Close()
+ fInfo, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ if fInfo.IsDir() {
+ return nil, errors.Errorf("remote client supports archives only but %q is a directory", opts.Input)
+ }
ref := opts.Name
if len(opts.Tag) > 0 {
ref += ":" + opts.Tag