summaryrefslogtreecommitdiff
path: root/pkg/adapter
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/adapter')
-rw-r--r--pkg/adapter/containers.go156
-rw-r--r--pkg/adapter/containers_remote.go205
-rw-r--r--pkg/adapter/pods.go60
-rw-r--r--pkg/adapter/pods_remote.go108
-rw-r--r--pkg/adapter/runtime.go109
-rw-r--r--pkg/adapter/runtime_remote.go160
-rw-r--r--pkg/adapter/shortcuts/shortcuts.go27
7 files changed, 735 insertions, 90 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
new file mode 100644
index 000000000..932d209cd
--- /dev/null
+++ b/pkg/adapter/containers.go
@@ -0,0 +1,156 @@
+// +build !remoteclient
+
+package adapter
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter/shortcuts"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// GetLatestContainer gets the latest Container and wraps it in an adapter Container
+func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
+ Container := Container{}
+ c, err := r.Runtime.GetLatestContainer()
+ Container.Container = c
+ return &Container, err
+}
+
+// GetAllContainers gets all Containers and wraps each one in an adapter Container
+func (r *LocalRuntime) GetAllContainers() ([]*Container, error) {
+ var containers []*Container
+ allContainers, err := r.Runtime.GetAllContainers()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, c := range allContainers {
+ containers = append(containers, &Container{c})
+ }
+ return containers, nil
+}
+
+// LookupContainer gets a Container by name or id and wraps it in an adapter Container
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ ctr, err := r.Runtime.LookupContainer(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ return &Container{ctr}, nil
+}
+
+// StopContainers stops container(s) based on CLI inputs.
+// Returns list of successful id(s), map of failed id(s) + error, or error not from container
+func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
+ var timeout *uint
+ if cli.Flags().Changed("timeout") || cli.Flags().Changed("time") {
+ t := uint(cli.Timeout)
+ timeout = &t
+ }
+
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, c := range ctrs {
+ if timeout == nil {
+ t := c.StopTimeout()
+ timeout = &t
+ logrus.Debugf("Set timeout to container %s default (%d)", c.ID(), *timeout)
+ }
+ if err := c.StopWithTimeout(*timeout); err == nil {
+ ok = append(ok, c.ID())
+ } else if errors.Cause(err) == libpod.ErrCtrStopped {
+ ok = append(ok, c.ID())
+ logrus.Debugf("Container %s is already stopped", c.ID())
+ } else {
+ failures[c.ID()] = err
+ }
+ }
+ return ok, failures, nil
+}
+
+// KillContainers sends signal to container(s) based on CLI inputs.
+// Returns list of successful id(s), map of failed id(s) + error, or error not from container
+func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, c := range ctrs {
+ if err := c.Kill(uint(signal)); err == nil {
+ ok = append(ok, c.ID())
+ } else {
+ failures[c.ID()] = err
+ }
+ }
+ return ok, failures, nil
+}
+
+// WaitOnContainers waits for all given container(s) to stop
+func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.WaitValues, interval time.Duration) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ctrs, err := shortcuts.GetContainersByContext(false, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, c := range ctrs {
+ if returnCode, err := c.WaitWithInterval(interval); err == nil {
+ ok = append(ok, strconv.Itoa(int(returnCode)))
+ } else {
+ failures[c.ID()] = err
+ }
+ }
+ return ok, failures, err
+}
+
+// Log logs one or more containers
+func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) error {
+ var wg sync.WaitGroup
+ options.WaitGroup = &wg
+ if len(c.InputArgs) > 1 {
+ options.Multi = true
+ }
+ logChannel := make(chan *libpod.LogLine, int(c.Tail)*len(c.InputArgs)+1)
+ containers, err := shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime)
+ if err != nil {
+ return err
+ }
+ if err := r.Runtime.Log(containers, options, logChannel); err != nil {
+ return err
+ }
+ go func() {
+ wg.Wait()
+ close(logChannel)
+ }()
+ for line := range logChannel {
+ fmt.Println(line.String(options))
+ }
+ return nil
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 3f43a6905..2982d6cbb 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -3,17 +3,26 @@
package adapter
import (
+ "context"
"encoding/json"
- "github.com/containers/libpod/cmd/podman/shared"
+ "fmt"
+ "strconv"
+ "syscall"
+ "time"
- iopodman "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/shared"
+ "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/inspect"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/varlink/go/varlink"
)
// Inspect returns an inspect struct from varlink
func (c *Container) Inspect(size bool) (*inspect.ContainerInspectData, error) {
- reply, err := iopodman.ContainerInspectData().Call(c.Runtime.Conn, c.ID())
+ reply, err := iopodman.ContainerInspectData().Call(c.Runtime.Conn, c.ID(), size)
if err != nil {
return nil, err
}
@@ -29,6 +38,70 @@ func (c *Container) ID() string {
return c.config.ID
}
+// Config returns a container config
+func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
+ // TODO the Spec being returned is not populated. Matt and I could not figure out why. Will defer
+ // further looking into it for after devconf.
+ // The libpod function for this has no errors so we are kind of in a tough
+ // spot here. Logging the errors for now.
+ reply, err := iopodman.ContainerConfig().Call(r.Conn, name)
+ if err != nil {
+ logrus.Error("call to container.config failed")
+ }
+ data := libpod.ContainerConfig{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ logrus.Error("failed to unmarshal container inspect data")
+ }
+ return &data
+
+}
+
+// ContainerState returns the "state" of the container.
+func (r *LocalRuntime) ContainerState(name string) (*libpod.ContainerState, error) { // no-lint
+ reply, err := iopodman.ContainerStateData().Call(r.Conn, name)
+ if err != nil {
+ return nil, err
+ }
+ data := libpod.ContainerState{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, err
+
+}
+
+// LookupContainer gets basic information about container over a varlink
+// connection and then translates it to a *Container
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ state, err := r.ContainerState(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ config := r.Config(idOrName)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Container{
+ remoteContainer{
+ r,
+ config,
+ state,
+ },
+ }, nil
+}
+
+func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
+ reply, err := iopodman.GetContainersByContext().Call(r.Conn, false, true, nil)
+ if err != nil {
+ return nil, err
+ }
+ if len(reply) > 0 {
+ return r.LookupContainer(reply[0])
+ }
+ return nil, errors.New("no containers exist")
+}
+
// GetArtifact returns a container's artifacts
func (c *Container) GetArtifact(name string) ([]byte, error) {
var data []byte
@@ -55,18 +128,90 @@ func (c *Container) Name() string {
return c.config.Name
}
+// StopContainers stops requested containers using CLI inputs.
+// Returns the list of stopped container ids, map of failed to stop container ids + errors, or any non-container error
+func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, id := range ids {
+ stopped, err := iopodman.StopContainer().Call(r.Conn, id, int64(cli.Timeout))
+ if err != nil {
+ failures[id] = err
+ } else {
+ ok = append(ok, stopped)
+ }
+ }
+ return ok, failures, nil
+}
+
+// KillContainers sends signal to container(s) based on CLI inputs.
+// Returns list of successful id(s), map of failed id(s) + error, or error not from container
+func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, id := range ids {
+ killed, err := iopodman.KillContainer().Call(r.Conn, id, int64(signal))
+ if err != nil {
+ failures[id] = err
+ } else {
+ ok = append(ok, killed)
+ }
+ }
+ return ok, failures, nil
+}
+
+// WaitOnContainers waits for all given container(s) to stop.
+// interval is currently ignored.
+func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.WaitValues, interval time.Duration) ([]string, map[string]error, error) {
+ var (
+ ok = []string{}
+ failures = map[string]error{}
+ )
+
+ ids, err := iopodman.GetContainersByContext().Call(r.Conn, false, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return ok, failures, err
+ }
+
+ for _, id := range ids {
+ stopped, err := iopodman.WaitContainer().Call(r.Conn, id, int64(interval))
+ if err != nil {
+ failures[id] = err
+ } else {
+ ok = append(ok, strconv.FormatInt(stopped, 10))
+ }
+ }
+ return ok, failures, nil
+}
+
// BatchContainerOp is wrapper func to mimic shared's function with a similar name meant for libpod
func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContainerStruct, error) {
// TODO If pod ps ever shows container's sizes, re-enable this code; otherwise it isn't needed
// and would be a perf hit
- //data, err := ctr.Inspect(true)
- //if err != nil {
- // return shared.BatchContainerStruct{}, err
- //}
+ // data, err := ctr.Inspect(true)
+ // if err != nil {
+ // return shared.BatchContainerStruct{}, err
+ // }
//
- //size := new(shared.ContainerSize)
- //size.RootFsSize = data.SizeRootFs
- //size.RwSize = data.SizeRw
+ // size := new(shared.ContainerSize)
+ // size.RootFsSize = data.SizeRootFs
+ // size.RwSize = data.SizeRw
bcs := shared.BatchContainerStruct{
ConConfig: ctr.config,
@@ -75,7 +220,45 @@ func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContai
Pid: ctr.state.PID,
StartedTime: ctr.state.StartedTime,
ExitedTime: ctr.state.FinishedTime,
- //Size: size,
+ // Size: size,
}
return bcs, nil
}
+
+// Logs one or more containers over a varlink connection
+func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) error {
+ //GetContainersLogs
+ reply, err := iopodman.GetContainersLogs().Send(r.Conn, uint64(varlink.More), c.InputArgs, c.Follow, c.Latest, options.Since.Format(time.RFC3339Nano), int64(c.Tail), c.Timestamps)
+ if err != nil {
+ return errors.Wrapf(err, "failed to get container logs")
+ }
+ if len(c.InputArgs) > 1 {
+ options.Multi = true
+ }
+ for {
+ log, flags, err := reply()
+ if err != nil {
+ return err
+ }
+ if log.Time == "" && log.Msg == "" {
+ // We got a blank log line which can signal end of stream
+ break
+ }
+ lTime, err := time.Parse(time.RFC3339Nano, log.Time)
+ if err != nil {
+ return errors.Wrapf(err, "unable to parse time of log %s", log.Time)
+ }
+ logLine := libpod.LogLine{
+ Device: log.Device,
+ ParseLogType: log.ParseLogType,
+ Time: lTime,
+ Msg: log.Msg,
+ CID: log.Cid,
+ }
+ fmt.Println(logLine.String(options))
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+ return nil
+}
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index 706a8fe96..669971789 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -4,6 +4,7 @@ package adapter
import (
"context"
+ "github.com/pkg/errors"
"strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
@@ -17,6 +18,13 @@ type Pod struct {
*libpod.Pod
}
+// PodContainerStats is struct containing an adapter Pod and a libpod
+// ContainerStats and is used primarily for outputing pod stats.
+type PodContainerStats struct {
+ Pod *Pod
+ ContainerStats map[string]*libpod.ContainerStats
+}
+
// RemovePods ...
func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValues) ([]string, []error) {
var (
@@ -321,3 +329,55 @@ func (r *LocalRuntime) RestartPods(ctx context.Context, c *cliconfig.PodRestartV
return restartIDs, containerErrors, restartErrors
}
+
+// PodTop is a wrapper function to call GetPodPidInformation in libpod and return its results
+// for output
+func (r *LocalRuntime) PodTop(c *cliconfig.PodTopValues, descriptors []string) ([]string, error) {
+ var (
+ pod *Pod
+ err error
+ )
+
+ if c.Latest {
+ pod, err = r.GetLatestPod()
+ } else {
+ pod, err = r.LookupPod(c.InputArgs[0])
+ }
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to lookup requested container")
+ }
+ podStatus, err := pod.GetPodStatus()
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to get status for pod %s", pod.ID())
+ }
+ if podStatus != "Running" {
+ return nil, errors.Errorf("pod top can only be used on pods with at least one running container")
+ }
+ return pod.GetPodPidInformation(descriptors)
+}
+
+// GetStatPods returns pods for use in pod stats
+func (r *LocalRuntime) GetStatPods(c *cliconfig.PodStatsValues) ([]*Pod, error) {
+ var (
+ adapterPods []*Pod
+ pods []*libpod.Pod
+ err error
+ )
+
+ if len(c.InputArgs) > 0 || c.Latest || c.All {
+ pods, err = shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime)
+ } else {
+ pods, err = r.Runtime.GetRunningPods()
+ }
+ if err != nil {
+ return nil, err
+ }
+ // convert libpod pods to adapter pods
+ for _, p := range pods {
+ adapterPod := Pod{
+ p,
+ }
+ adapterPods = append(adapterPods, &adapterPod)
+ }
+ return adapterPods, nil
+}
diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go
index 220f7163f..ef8de90a6 100644
--- a/pkg/adapter/pods_remote.go
+++ b/pkg/adapter/pods_remote.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/varlinkapi"
"github.com/pkg/errors"
"github.com/ulule/deepcopier"
)
@@ -21,6 +22,13 @@ type Pod struct {
remotepod
}
+// PodContainerStats is struct containing an adapter Pod and a libpod
+// ContainerStats and is used primarily for outputing pod stats.
+type PodContainerStats struct {
+ Pod *Pod
+ ContainerStats map[string]*libpod.ContainerStats
+}
+
type remotepod struct {
config *libpod.PodConfig
state *libpod.PodInspectState
@@ -399,3 +407,103 @@ func (r *LocalRuntime) RestartPods(ctx context.Context, c *cliconfig.PodRestartV
}
return restartIDs, nil, restartErrors
}
+
+// PodTop gets top statistics for a pod
+func (r *LocalRuntime) PodTop(c *cliconfig.PodTopValues, descriptors []string) ([]string, error) {
+ var (
+ latest bool
+ podName string
+ )
+ if c.Latest {
+ latest = true
+ } else {
+ podName = c.InputArgs[0]
+ }
+ return iopodman.TopPod().Call(r.Conn, podName, latest, descriptors)
+}
+
+// GetStatPods returns pods for use in pod stats
+func (r *LocalRuntime) GetStatPods(c *cliconfig.PodStatsValues) ([]*Pod, error) {
+ var (
+ pods []*Pod
+ err error
+ podIDs []string
+ running bool
+ )
+
+ if len(c.InputArgs) > 0 || c.Latest || c.All {
+ podIDs, err = iopodman.GetPodsByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
+ } else {
+ podIDs, err = iopodman.GetPodsByContext().Call(r.Conn, true, false, []string{})
+ running = true
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range podIDs {
+ pod, err := r.Inspect(p)
+ if err != nil {
+ return nil, err
+ }
+ if running {
+ status, err := pod.GetPodStatus()
+ if err != nil {
+ // if we cannot get the status of the pod, skip and move on
+ continue
+ }
+ if strings.ToUpper(status) != "RUNNING" {
+ // if the pod is not running, skip and move on as well
+ continue
+ }
+ }
+ pods = append(pods, pod)
+ }
+ return pods, nil
+}
+
+// GetPodStats returns the stats for each of its containers
+func (p *Pod) GetPodStats(previousContainerStats map[string]*libpod.ContainerStats) (map[string]*libpod.ContainerStats, error) {
+ var (
+ ok bool
+ prevStat *libpod.ContainerStats
+ )
+ newContainerStats := make(map[string]*libpod.ContainerStats)
+ containers, err := p.AllContainers()
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range containers {
+ if prevStat, ok = previousContainerStats[c.ID()]; !ok {
+ prevStat = &libpod.ContainerStats{ContainerID: c.ID()}
+ }
+ cStats := iopodman.ContainerStats{
+ Id: prevStat.ContainerID,
+ Name: prevStat.Name,
+ Cpu: prevStat.CPU,
+ Cpu_nano: int64(prevStat.CPUNano),
+ System_nano: int64(prevStat.SystemNano),
+ Mem_usage: int64(prevStat.MemUsage),
+ Mem_limit: int64(prevStat.MemLimit),
+ Mem_perc: prevStat.MemPerc,
+ Net_input: int64(prevStat.NetInput),
+ Net_output: int64(prevStat.NetOutput),
+ Block_input: int64(prevStat.BlockInput),
+ Block_output: int64(prevStat.BlockOutput),
+ Pids: int64(prevStat.PIDs),
+ }
+ stats, err := iopodman.GetContainerStatsWithHistory().Call(p.Runtime.Conn, cStats)
+ if err != nil {
+ return nil, err
+ }
+ newStats := varlinkapi.ContainerStatsToLibpodContainerStats(stats)
+ // If the container wasn't running, don't include it
+ // but also suppress the error
+ if err != nil && errors.Cause(err) != libpod.ErrCtrStateInvalid {
+ return nil, err
+ }
+ if err == nil {
+ newContainerStats[c.ID()] = &newStats
+ }
+ }
+ return newContainerStats, nil
+}
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 8624981b1..6a68a3aea 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -3,11 +3,13 @@
package adapter
import (
+ "bufio"
"context"
"io"
"io/ioutil"
"os"
"strconv"
+ "text/template"
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
@@ -16,7 +18,9 @@ import (
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
@@ -108,15 +112,6 @@ func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, for
return r.Runtime.RemoveImage(ctx, img.Image, force)
}
-// LookupContainer ...
-func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
- ctr, err := r.Runtime.LookupContainer(idOrName)
- if err != nil {
- return nil, err
- }
- return &Container{ctr}, nil
-}
-
// PruneImages is wrapper into PruneImages within the image pkg
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
return r.ImageRuntime().PruneImages(all)
@@ -264,7 +259,7 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti
if err != nil {
return errors.Wrapf(err, "error parsing namespace-related options")
}
- usernsOption, idmappingOptions, err := parse.IDMappingOptions(c.PodmanCommand.Command)
+ usernsOption, idmappingOptions, err := parse.IDMappingOptions(c.PodmanCommand.Command, options.Isolation)
if err != nil {
return errors.Wrapf(err, "error parsing ID mapping options")
}
@@ -341,3 +336,97 @@ func IsImageNotFound(err error) bool {
}
return false
}
+
+// HealthCheck is a wrapper to same named function in libpod
+func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.HealthCheckStatus, error) {
+ return r.Runtime.HealthCheck(c.InputArgs[0])
+}
+
+// JoinOrCreateRootlessPod joins the specified pod if it is running or it creates a new user namespace
+// if the pod is stopped
+func (r *LocalRuntime) JoinOrCreateRootlessPod(pod *Pod) (bool, int, error) {
+ if os.Geteuid() == 0 {
+ return false, 0, nil
+ }
+ opts := rootless.Opts{
+ Argument: pod.ID(),
+ }
+
+ inspect, err := pod.Inspect()
+ if err != nil {
+ return false, 0, err
+ }
+ for _, ctr := range inspect.Containers {
+ prevCtr, err := r.LookupContainer(ctr.ID)
+ if err != nil {
+ return false, -1, err
+ }
+ s, err := prevCtr.State()
+ if err != nil {
+ return false, -1, err
+ }
+ if s != libpod.ContainerStateRunning && s != libpod.ContainerStatePaused {
+ continue
+ }
+ data, err := ioutil.ReadFile(prevCtr.Config().ConmonPidFile)
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", prevCtr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts)
+ }
+
+ return rootless.BecomeRootInUserNSWithOpts(&opts)
+}
+
+// Events is a wrapper to libpod to obtain libpod/podman events
+func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
+ var (
+ fromStart bool
+ eventsError error
+ )
+ options, err := shared.GenerateEventOptions(c.Filter, c.Since, c.Until)
+ if err != nil {
+ return errors.Wrapf(err, "unable to generate event options")
+ }
+ tmpl, err := template.New("events").Parse(c.Format)
+ if err != nil {
+ return err
+ }
+ if len(c.Since) > 0 || len(c.Until) > 0 {
+ fromStart = true
+ }
+ eventChannel := make(chan *events.Event)
+ go func() {
+ eventsError = r.Runtime.Events(fromStart, c.Stream, options, eventChannel)
+ }()
+
+ if eventsError != nil {
+ return eventsError
+ }
+ if err != nil {
+ return errors.Wrapf(err, "unable to tail the events log")
+ }
+ w := bufio.NewWriter(os.Stdout)
+ for event := range eventChannel {
+ if len(c.Format) > 0 {
+ if err := tmpl.Execute(w, event); err != nil {
+ return err
+ }
+ } else {
+ if _, err := w.Write([]byte(event.ToHumanReadable())); err != nil {
+ return err
+ }
+ }
+ if _, err := w.Write([]byte("\n")); err != nil {
+ return err
+ }
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 29b43e9b0..6c53d0c62 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -5,12 +5,12 @@ package adapter
import (
"bufio"
"context"
- "encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
+ "text/template"
"time"
"github.com/containers/buildah/imagebuildah"
@@ -19,6 +19,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/utils"
"github.com/containers/storage/pkg/archive"
@@ -49,14 +50,13 @@ func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
if err != nil {
return nil, err
}
- rr := RemoteRuntime{
- Conn: conn,
- Remote: true,
- }
- foo := LocalRuntime{
- &rr,
- }
- return &foo, nil
+
+ return &LocalRuntime{
+ &RemoteRuntime{
+ Conn: conn,
+ Remote: true,
+ },
+ }, nil
}
// Shutdown is a bogus wrapper for compat with the libpod runtime
@@ -315,66 +315,6 @@ func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error)
return imageHistories, nil
}
-// LookupContainer gets basic information about container over a varlink
-// connection and then translates it to a *Container
-func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
- state, err := r.ContainerState(idOrName)
- if err != nil {
- return nil, err
- }
- config := r.Config(idOrName)
- if err != nil {
- return nil, err
- }
-
- rc := remoteContainer{
- r,
- config,
- state,
- }
-
- c := Container{
- rc,
- }
- return &c, nil
-}
-
-func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
- return nil, libpod.ErrNotImplemented
-}
-
-// ContainerState returns the "state" of the container.
-func (r *LocalRuntime) ContainerState(name string) (*libpod.ContainerState, error) { //no-lint
- reply, err := iopodman.ContainerStateData().Call(r.Conn, name)
- if err != nil {
- return nil, err
- }
- data := libpod.ContainerState{}
- if err := json.Unmarshal([]byte(reply), &data); err != nil {
- return nil, err
- }
- return &data, err
-
-}
-
-// Config returns a container config
-func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
- // TODO the Spec being returned is not populated. Matt and I could not figure out why. Will defer
- // further looking into it for after devconf.
- // The libpod function for this has no errors so we are kind of in a tough
- // spot here. Logging the errors for now.
- reply, err := iopodman.ContainerConfig().Call(r.Conn, name)
- if err != nil {
- logrus.Error("call to container.config failed")
- }
- data := libpod.ContainerConfig{}
- if err := json.Unmarshal([]byte(reply), &data); err != nil {
- logrus.Error("failed to unmarshal container inspect data")
- }
- return &data
-
-}
-
// PruneImages is the wrapper call for a remote-client to prune images
func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
return iopodman.ImagesPrune().Call(r.Conn, all)
@@ -808,3 +748,85 @@ func IsImageNotFound(err error) bool {
}
return false
}
+
+// HealthCheck executes a container's healthcheck over a varlink connection
+func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.HealthCheckStatus, error) {
+ return -1, libpod.ErrNotImplemented
+}
+
+// JoinOrCreateRootlessPod joins the specified pod if it is running or it creates a new user namespace
+// if the pod is stopped
+func (r *LocalRuntime) JoinOrCreateRootlessPod(pod *Pod) (bool, int, error) {
+ // Nothing to do in the remote case
+ return true, 0, nil
+}
+
+// Events monitors libpod/podman events over a varlink connection
+func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
+ var more uint64
+ if c.Stream {
+ more = uint64(varlink.More)
+ }
+ reply, err := iopodman.GetEvents().Send(r.Conn, more, c.Filter, c.Since, c.Until)
+ if err != nil {
+ return errors.Wrapf(err, "unable to obtain events")
+ }
+
+ w := bufio.NewWriter(os.Stdout)
+ tmpl, err := template.New("events").Parse(c.Format)
+ if err != nil {
+ return err
+ }
+
+ for {
+ returnedEvent, flags, err := reply()
+ if err != nil {
+ // When the error handling is back into podman, we can flip this to a better way to check
+ // for problems. For now, this works.
+ return err
+ }
+ if returnedEvent.Time == "" && returnedEvent.Status == "" && returnedEvent.Type == "" {
+ // We got a blank event return, signals end of stream in certain cases
+ break
+ }
+ eTime, err := time.Parse(time.RFC3339Nano, returnedEvent.Time)
+ if err != nil {
+ return errors.Wrapf(err, "unable to parse time of event %s", returnedEvent.Time)
+ }
+ eType, err := events.StringToType(returnedEvent.Type)
+ if err != nil {
+ return err
+ }
+ eStatus, err := events.StringToStatus(returnedEvent.Status)
+ if err != nil {
+ return err
+ }
+ event := events.Event{
+ ID: returnedEvent.Id,
+ Image: returnedEvent.Image,
+ Name: returnedEvent.Name,
+ Status: eStatus,
+ Time: eTime,
+ Type: eType,
+ }
+ if len(c.Format) > 0 {
+ if err := tmpl.Execute(w, event); err != nil {
+ return err
+ }
+ } else {
+ if _, err := w.Write([]byte(event.ToHumanReadable())); err != nil {
+ return err
+ }
+ }
+ if _, err := w.Write([]byte("\n")); err != nil {
+ return err
+ }
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+ return nil
+}
diff --git a/pkg/adapter/shortcuts/shortcuts.go b/pkg/adapter/shortcuts/shortcuts.go
index 0633399ae..677d88457 100644
--- a/pkg/adapter/shortcuts/shortcuts.go
+++ b/pkg/adapter/shortcuts/shortcuts.go
@@ -25,3 +25,30 @@ func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime)
}
return outpods, nil
}
+
+// GetContainersByContext gets pods whether all, latest, or a slice of names/ids
+func GetContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) ([]*libpod.Container, error) {
+ var ctrs = []*libpod.Container{}
+
+ if all {
+ return runtime.GetAllContainers()
+ }
+
+ if latest {
+ c, err := runtime.GetLatestContainer()
+ if err != nil {
+ return nil, err
+ }
+ ctrs = append(ctrs, c)
+ return ctrs, nil
+ }
+
+ for _, c := range names {
+ ctr, err := runtime.LookupContainer(c)
+ if err != nil {
+ return nil, err
+ }
+ ctrs = append(ctrs, ctr)
+ }
+ return ctrs, nil
+}