summaryrefslogtreecommitdiff
path: root/pkg/adapter/containers_remote.go
diff options
context:
space:
mode:
authorBrent Baude <bbaude@redhat.com>2020-04-16 12:25:26 -0500
committerBrent Baude <bbaude@redhat.com>2020-04-16 15:53:58 -0500
commit241326a9a8c20ad7f2bcf651416b836e7778e090 (patch)
tree4001e8e47a022bb1b9bfbf2332c42e1aeb802f9e /pkg/adapter/containers_remote.go
parent88c6fd06cd54fb9a8826306dfdf1a77e400de5de (diff)
downloadpodman-241326a9a8c20ad7f2bcf651416b836e7778e090.tar.gz
podman-241326a9a8c20ad7f2bcf651416b836e7778e090.tar.bz2
podman-241326a9a8c20ad7f2bcf651416b836e7778e090.zip
Podman V2 birth
remote podman v1 and replace with podman v2. Signed-off-by: Brent Baude <bbaude@redhat.com>
Diffstat (limited to 'pkg/adapter/containers_remote.go')
-rw-r--r--pkg/adapter/containers_remote.go1139
1 files changed, 0 insertions, 1139 deletions
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
deleted file mode 100644
index 777605896..000000000
--- a/pkg/adapter/containers_remote.go
+++ /dev/null
@@ -1,1139 +0,0 @@
-// +build remoteclient
-
-package adapter
-
-import (
- "bufio"
- "context"
- "encoding/json"
- "fmt"
- "io"
- "os"
- "strconv"
- "syscall"
- "time"
-
- "github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/define"
- "github.com/containers/libpod/libpod/logs"
- envLib "github.com/containers/libpod/pkg/env"
- iopodman "github.com/containers/libpod/pkg/varlink"
- "github.com/containers/libpod/pkg/varlinkapi/virtwriter"
- "github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/docker/pkg/term"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "github.com/varlink/go/varlink"
- "golang.org/x/crypto/ssh/terminal"
- "k8s.io/client-go/tools/remotecommand"
-)
-
-// Inspect returns an inspect struct from varlink
-func (c *Container) Inspect(size bool) (*define.InspectContainerData, error) {
- reply, err := iopodman.ContainerInspectData().Call(c.Runtime.Conn, c.ID(), size)
- if err != nil {
- return nil, err
- }
- data := define.InspectContainerData{}
- if err := json.Unmarshal([]byte(reply), &data); err != nil {
- return nil, err
- }
- return &data, err
-}
-
-// ID returns the ID of the container
-func (c *Container) ID() string {
- return c.config.ID
-}
-
-// Restart a single container
-func (c *Container) Restart(timeout int64) error {
- _, err := iopodman.RestartContainer().Call(c.Runtime.Conn, c.ID(), timeout)
- return err
-}
-
-// Pause a container
-func (c *Container) Pause() error {
- _, err := iopodman.PauseContainer().Call(c.Runtime.Conn, c.ID())
- return err
-}
-
-// Unpause a container
-func (c *Container) Unpause() error {
- _, err := iopodman.UnpauseContainer().Call(c.Runtime.Conn, c.ID())
- return err
-}
-
-func (c *Container) PortMappings() ([]ocicni.PortMapping, error) {
- // First check if the container belongs to a network namespace (like a pod)
- // Taken from libpod portmappings()
- if len(c.config.NetNsCtr) > 0 {
- netNsCtr, err := c.Runtime.LookupContainer(c.config.NetNsCtr)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to lookup network namespace for container %s", c.ID())
- }
- return netNsCtr.PortMappings()
- }
- return c.config.PortMappings, nil
-}
-
-// 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
-
-}
-
-// Spec obtains the container spec.
-func (r *LocalRuntime) Spec(name string) (*specs.Spec, error) {
- reply, err := iopodman.Spec().Call(r.Conn, name)
- if err != nil {
- return nil, err
- }
- data := specs.Spec{}
- if err := json.Unmarshal([]byte(reply), &data); err != nil {
- return nil, err
- }
- return &data, nil
-}
-
-// LookupContainers is a wrapper for LookupContainer
-func (r *LocalRuntime) LookupContainers(idsOrNames []string) ([]*Container, error) {
- var containers []*Container
- for _, name := range idsOrNames {
- ctr, err := r.LookupContainer(name)
- if err != nil {
- return nil, err
- }
- containers = append(containers, ctr)
- }
- return containers, 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)
- return &Container{
- remoteContainer{
- r,
- config,
- state,
- },
- }, nil
-}
-
-// GetAllContainers returns all containers in a slice
-func (r *LocalRuntime) GetAllContainers() ([]*Container, error) {
- var containers []*Container
- ctrs, err := iopodman.GetContainersByContext().Call(r.Conn, true, false, []string{})
- if err != nil {
- return nil, err
- }
- for _, ctr := range ctrs {
- container, err := r.LookupContainer(ctr)
- if err != nil {
- return nil, err
- }
- containers = append(containers, container)
- }
- return containers, nil
-}
-
-func (r *LocalRuntime) LookupContainersWithStatus(filters []string) ([]*Container, error) {
- var containers []*Container
- ctrs, err := iopodman.GetContainersByStatus().Call(r.Conn, filters)
- if err != nil {
- return nil, err
- }
- // This is not performance savvy; if this turns out to be a problematic series of lookups, we need to
- // create a new endpoint to speed things up
- for _, ctr := range ctrs {
- container, err := r.LookupContainer(ctr.Id)
- if err != nil {
- return nil, err
- }
- containers = append(containers, container)
- }
- return containers, 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
- reply, err := iopodman.ContainerArtifacts().Call(c.Runtime.Conn, c.ID(), name)
- if err != nil {
- return nil, err
- }
- if err := json.Unmarshal([]byte(reply), &data); err != nil {
- return nil, err
- }
- return data, err
-}
-
-// Config returns a container's Config ... same as ctr.Config()
-func (c *Container) Config() *libpod.ContainerConfig {
- if c.config != nil {
- return c.config
- }
- return c.Runtime.Config(c.ID())
-}
-
-// Name returns the name of the container
-func (c *Container) Name() string {
- return c.config.Name
-}
-
-// StopContainers stops requested containers using varlink.
-// 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, TranslateError(err)
- }
-
- for _, id := range ids {
- if _, err := iopodman.StopContainer().Call(r.Conn, id, int64(cli.Timeout)); err != nil {
- transError := TranslateError(err)
- if errors.Cause(transError) == define.ErrCtrStopped {
- ok = append(ok, id)
- continue
- }
- if errors.Cause(transError) == define.ErrCtrStateInvalid && cli.All {
- ok = append(ok, id)
- continue
- }
- failures[id] = err
- } else {
- // We should be using ID here because in varlink, only successful returns
- // include the string id
- ok = append(ok, id)
- }
- }
- return ok, failures, nil
-}
-
-// InitContainers initializes container(s) based on Varlink.
-// It returns a list of successful ID(s), a map of failed container ID to error,
-// or an error if a more general error occurred.
-func (r *LocalRuntime) InitContainers(ctx context.Context, cli *cliconfig.InitValues) ([]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 nil, nil, err
- }
-
- for _, id := range ids {
- initialized, err := iopodman.InitContainer().Call(r.Conn, id)
- if err != nil {
- if cli.All {
- switch err.(type) {
- case *iopodman.InvalidState:
- ok = append(ok, initialized)
- default:
- failures[id] = err
- }
- } else {
- failures[id] = err
- }
- } else {
- ok = append(ok, initialized)
- }
- }
- return ok, failures, nil
-}
-
-// KillContainers sends signal to container(s) based on varlink.
-// 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
-}
-
-// RemoveContainer removes container(s) based on varlink inputs.
-func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmValues) ([]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 {
- // Failed to get containers. If force is specified, get the containers ID
- // and evict them
- if !cli.Force {
- return nil, nil, TranslateError(err)
- }
-
- for _, ctr := range cli.InputArgs {
- logrus.Debugf("Evicting container %q", ctr)
- id, err := iopodman.EvictContainer().Call(r.Conn, ctr, cli.Volumes)
- if err != nil {
- failures[ctr] = errors.Wrapf(err, "Failed to evict container: %q", id)
- continue
- }
- ok = append(ok, id)
- }
- return ok, failures, nil
- }
-
- for _, id := range ids {
- _, err := iopodman.RemoveContainer().Call(r.Conn, id, cli.Force, cli.Volumes)
- if err != nil {
- failures[id] = err
- } else {
- ok = append(ok, id)
- }
- }
- return ok, failures, nil
-}
-
-// UmountRootFilesystems umounts container(s) root filesystems based on varlink inputs
-func (r *LocalRuntime) UmountRootFilesystems(ctx context.Context, cli *cliconfig.UmountValues) ([]string, map[string]error, error) {
- ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
- if err != nil {
- return nil, nil, err
- }
-
- var (
- ok = []string{}
- failures = map[string]error{}
- )
-
- for _, id := range ids {
- err := iopodman.UnmountContainer().Call(r.Conn, id, cli.Force)
- if err != nil {
- failures[id] = err
- } else {
- ok = append(ok, id)
- }
- }
- 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
- // }
- //
- // size := new(shared.ContainerSize)
- // size.RootFsSize = data.SizeRootFs
- // size.RwSize = data.SizeRw
-
- bcs := shared.BatchContainerStruct{
- ConConfig: ctr.config,
- ConState: ctr.state.State,
- ExitCode: ctr.state.ExitCode,
- Pid: ctr.state.PID,
- StartedTime: ctr.state.StartedTime,
- ExitedTime: ctr.state.FinishedTime,
- // Size: size,
- }
- return bcs, nil
-}
-
-// Log one or more containers over a varlink connection
-func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *logs.LogOptions) error {
- // GetContainersLogs
- reply, err := iopodman.GetContainersLogs().Send(r.Conn, uint64(varlink.More), c.InputArgs, c.Follow, c.Latest, options.Since.Format(time.RFC3339Nano), 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 := logs.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
-}
-
-// CreateContainer creates a container from the cli over varlink
-func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) {
- results := shared.NewIntermediateLayer(&c.PodmanCommand, true)
- return iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink())
-}
-
-// Run creates a container overvarlink and then starts it
-func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) {
- // TODO the exit codes for run need to be figured out for remote connections
- results := shared.NewIntermediateLayer(&c.PodmanCommand, true)
- cid, err := iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink())
- if err != nil {
- return exitCode, err
- }
- if c.Bool("detach") {
- if _, err := iopodman.StartContainer().Call(r.Conn, cid); err != nil {
- return exitCode, err
- }
- fmt.Println(cid)
- return 0, nil
- }
- inputStream := os.Stdin
- // If -i is not set, clear stdin
- if !c.Bool("interactive") {
- inputStream = nil
- }
- exitChan, errChan, err := r.attach(ctx, inputStream, os.Stdout, cid, true, c.String("detach-keys"))
- if err != nil {
- return exitCode, err
- }
- exitCode = <-exitChan
- finalError := <-errChan
- return exitCode, finalError
-}
-
-func ReadExitFile(runtimeTmp, ctrID string) (int, error) {
- return 0, define.ErrNotImplemented
-}
-
-// Ps lists containers based on criteria from user
-func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]shared.PsContainerOutput, error) {
- var psContainers []shared.PsContainerOutput
- last := int64(c.Last)
- PsOpts := iopodman.PsOpts{
- All: c.All,
- Filters: &c.Filter,
- Last: &last,
- Latest: &c.Latest,
- NoTrunc: &c.NoTrunct,
- Pod: &c.Pod,
- Quiet: &c.Quiet,
- Size: &c.Size,
- Sort: &c.Sort,
- Sync: &c.Sync,
- }
- containers, err := iopodman.Ps().Call(r.Conn, PsOpts)
- if err != nil {
- return nil, err
- }
- for _, ctr := range containers {
- createdAt, err := time.Parse(time.RFC3339Nano, ctr.CreatedAt)
- if err != nil {
- return nil, err
- }
- exitedAt, err := time.Parse(time.RFC3339Nano, ctr.ExitedAt)
- if err != nil {
- return nil, err
- }
- startedAt, err := time.Parse(time.RFC3339Nano, ctr.StartedAt)
- if err != nil {
- return nil, err
- }
- containerSize := shared.ContainerSize{
- RootFsSize: ctr.RootFsSize,
- RwSize: ctr.RwSize,
- }
- state, err := define.StringToContainerStatus(ctr.State)
- if err != nil {
- return nil, err
- }
- psc := shared.PsContainerOutput{
- ID: ctr.Id,
- Image: ctr.Image,
- Command: ctr.Command,
- Created: ctr.Created,
- Ports: ctr.Ports,
- Names: ctr.Names,
- IsInfra: ctr.IsInfra,
- Status: ctr.Status,
- State: state,
- Pid: int(ctr.PidNum),
- Size: &containerSize,
- Pod: ctr.Pod,
- CreatedAt: createdAt,
- ExitedAt: exitedAt,
- StartedAt: startedAt,
- Labels: ctr.Labels,
- PID: ctr.NsPid,
- Cgroup: ctr.Cgroup,
- IPC: ctr.Ipc,
- MNT: ctr.Mnt,
- NET: ctr.Net,
- PIDNS: ctr.PidNs,
- User: ctr.User,
- UTS: ctr.Uts,
- Mounts: ctr.Mounts,
- }
- psContainers = append(psContainers, psc)
- }
- return psContainers, nil
-}
-
-// Attach to a remote terminal
-func (r *LocalRuntime) Attach(ctx context.Context, c *cliconfig.AttachValues) error {
- ctr, err := r.LookupContainer(c.InputArgs[0])
- if err != nil {
- return nil
- }
- if ctr.state.State != define.ContainerStateRunning {
- return errors.New("you can only attach to running containers")
- }
- inputStream := os.Stdin
- if c.NoStdin {
- inputStream, err = os.Open(os.DevNull)
- if err != nil {
- return err
- }
- }
- _, errChan, err := r.attach(ctx, inputStream, os.Stdout, c.InputArgs[0], false, c.DetachKeys)
- if err != nil {
- return err
- }
- return <-errChan
-}
-
-// Checkpoint one or more containers
-func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues) error {
- if c.Export != "" {
- return errors.New("the remote client does not support exporting checkpoints")
- }
- if c.IgnoreRootfs {
- return errors.New("the remote client does not support --ignore-rootfs")
- }
-
- var lastError error
- ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
- if err != nil {
- return err
- }
- if c.All {
- // We don't have a great way to get all the running containers, so need to get all and then
- // check status on them bc checkpoint considers checkpointing a stopped container an error
- var runningIds []string
- for _, id := range ids {
- ctr, err := r.LookupContainer(id)
- if err != nil {
- return err
- }
- if ctr.state.State == define.ContainerStateRunning {
- runningIds = append(runningIds, id)
- }
- }
- ids = runningIds
- }
-
- for _, id := range ids {
- if _, err := iopodman.ContainerCheckpoint().Call(r.Conn, id, c.Keep, c.Keep, c.TcpEstablished); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to checkpoint container %v", id)
- } else {
- fmt.Println(id)
- }
- }
- return lastError
-}
-
-// Restore one or more containers
-func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues) error {
- if c.Import != "" {
- return errors.New("the remote client does not support importing checkpoints")
- }
- if c.IgnoreRootfs {
- return errors.New("the remote client does not support --ignore-rootfs")
- }
-
- var lastError error
- ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
- if err != nil {
- return err
- }
- if c.All {
- // We don't have a great way to get all the exited containers, so need to get all and then
- // check status on them bc checkpoint considers restoring a running container an error
- var exitedIDs []string
- for _, id := range ids {
- ctr, err := r.LookupContainer(id)
- if err != nil {
- return err
- }
- if ctr.state.State != define.ContainerStateRunning {
- exitedIDs = append(exitedIDs, id)
- }
- }
- ids = exitedIDs
- }
-
- for _, id := range ids {
- if _, err := iopodman.ContainerRestore().Call(r.Conn, id, c.Keep, c.TcpEstablished); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to restore container %v", id)
- } else {
- fmt.Println(id)
- }
- }
- return lastError
-}
-
-// Start starts an already created container
-func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigProxy bool) (int, error) {
- var (
- finalErr error
- exitCode = define.ExecErrorCodeGeneric
- )
- // TODO Figure out how to deal with exit codes
- inputStream := os.Stdin
- if !c.Interactive {
- inputStream = nil
- }
-
- containerIDs, err := iopodman.GetContainersByContext().Call(r.Conn, false, c.Latest, c.InputArgs)
- if err != nil {
- return exitCode, err
- }
- if len(containerIDs) < 1 {
- return exitCode, errors.New("failed to find containers to start")
- }
- // start.go makes sure that if attach, there can be only one ctr
- if c.Attach {
- exitChan, errChan, err := r.attach(ctx, inputStream, os.Stdout, containerIDs[0], true, c.DetachKeys)
- if err != nil {
- return exitCode, nil
- }
- exitCode := <-exitChan
- err = <-errChan
- return exitCode, err
- }
-
- // TODO the notion of starting a pod container and its deps still needs to be worked through
- // Everything else is detached
- for _, cid := range containerIDs {
- reply, err := iopodman.StartContainer().Call(r.Conn, cid)
- if err != nil {
- if finalErr != nil {
- fmt.Println(err)
- }
- finalErr = err
- } else {
- fmt.Println(reply)
- }
- }
- return exitCode, finalErr
-}
-
-func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid string, start bool, detachKeys string) (chan int, chan error, error) {
- var (
- oldTermState *term.State
- )
- spec, err := r.Spec(cid)
- if err != nil {
- return nil, nil, err
- }
- resize := make(chan remotecommand.TerminalSize, 5)
- 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 && spec.Process.Terminal {
- cancel, oldTermState, err := handleTerminalAttach(ctx, resize)
- if err != nil {
- return nil, nil, err
- }
- defer cancel()
- defer restoreTerminal(oldTermState) // nolint: errcheck
-
- logrus.SetFormatter(&RawTtyFormatter{})
- term.SetRawTerminal(os.Stdin.Fd()) // nolint: errcheck
- }
-
- reply, err := iopodman.Attach().Send(r.Conn, varlink.Upgrade, cid, detachKeys, start)
- if err != nil {
- restoreTerminal(oldTermState) // nolint: errcheck
- return nil, nil, err
- }
-
- // See if the server accepts the upgraded connection or returns an error
- _, err = reply()
-
- if err != nil {
- restoreTerminal(oldTermState) // nolint: errcheck
- return nil, nil, err
- }
-
- ecChan := make(chan int, 1)
- errChan := configureVarlinkAttachStdio(r.Conn.Reader, r.Conn.Writer, stdin, stdout, oldTermState, resize, ecChan)
- return ecChan, errChan, nil
-}
-
-// PauseContainers pauses container(s) based on CLI inputs.
-func (r *LocalRuntime) PauseContainers(ctx context.Context, cli *cliconfig.PauseValues) ([]string, map[string]error, error) {
- var (
- ok []string
- failures = map[string]error{}
- ctrs []*Container
- err error
- )
-
- if cli.All {
- filters := []string{define.ContainerStateRunning.String()}
- ctrs, err = r.LookupContainersWithStatus(filters)
- } else {
- ctrs, err = r.LookupContainers(cli.InputArgs)
- }
- if err != nil {
- return ok, failures, err
- }
-
- for _, c := range ctrs {
- c := c
- err := c.Pause()
- if err != nil {
- failures[c.ID()] = err
- } else {
- ok = append(ok, c.ID())
- }
- }
- return ok, failures, nil
-}
-
-// UnpauseContainers unpauses containers based on input
-func (r *LocalRuntime) UnpauseContainers(ctx context.Context, cli *cliconfig.UnpauseValues) ([]string, map[string]error, error) {
- var (
- ok = []string{}
- failures = map[string]error{}
- ctrs []*Container
- err error
- )
-
- maxWorkers := shared.DefaultPoolSize("unpause")
- if cli.GlobalIsSet("max-workers") {
- maxWorkers = cli.GlobalFlags.MaxWorks
- }
- logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
-
- if cli.All {
- filters := []string{define.ContainerStatePaused.String()}
- ctrs, err = r.LookupContainersWithStatus(filters)
- } else {
- ctrs, err = r.LookupContainers(cli.InputArgs)
- }
- if err != nil {
- return ok, failures, err
- }
- for _, c := range ctrs {
- c := c
- err := c.Unpause()
- if err != nil {
- failures[c.ID()] = err
- } else {
- ok = append(ok, c.ID())
- }
- }
- return ok, failures, nil
-}
-
-// Restart restarts a container over varlink
-func (r *LocalRuntime) Restart(ctx context.Context, c *cliconfig.RestartValues) ([]string, map[string]error, error) {
- var (
- containers []*Container
- restartContainers []*Container
- err error
- ok = []string{}
- failures = map[string]error{}
- )
- useTimeout := c.Flag("timeout").Changed || c.Flag("time").Changed
- inputTimeout := c.Timeout
-
- if c.Latest { // nolint: gocritic
- lastCtr, err := r.GetLatestContainer()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "unable to get latest container")
- }
- restartContainers = append(restartContainers, lastCtr)
- } else if c.Running {
- containers, err = r.LookupContainersWithStatus([]string{define.ContainerStateRunning.String()})
- if err != nil {
- return nil, nil, err
- }
- restartContainers = append(restartContainers, containers...)
- } else if c.All {
- containers, err = r.GetAllContainers()
- if err != nil {
- return nil, nil, err
- }
- restartContainers = append(restartContainers, containers...)
- } else {
- for _, id := range c.InputArgs {
- ctr, err := r.LookupContainer(id)
- if err != nil {
- return nil, nil, err
- }
- restartContainers = append(restartContainers, ctr)
- }
- }
-
- for _, c := range restartContainers {
- c := c
- timeout := c.config.StopTimeout
- if useTimeout {
- timeout = inputTimeout
- }
- err := c.Restart(int64(timeout))
- if err != nil {
- failures[c.ID()] = err
- } else {
- ok = append(ok, c.ID())
- }
- }
- return ok, failures, nil
-}
-
-// Top display the running processes of a container
-func (r *LocalRuntime) Top(cli *cliconfig.TopValues) ([]string, error) {
- var (
- ctr *Container
- err error
- descriptors []string
- )
- if cli.Latest {
- ctr, err = r.GetLatestContainer()
- descriptors = cli.InputArgs
- } else {
- ctr, err = r.LookupContainer(cli.InputArgs[0])
- descriptors = cli.InputArgs[1:]
- }
- if err != nil {
- return nil, err
- }
- return iopodman.Top().Call(r.Conn, ctr.ID(), descriptors)
-}
-
-// Prune removes stopped containers
-func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, filter []string) ([]string, map[string]error, error) {
-
- var (
- ok = []string{}
- failures = map[string]error{}
- ctrs []*Container
- err error
- )
- logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
-
- filters := []string{define.ContainerStateExited.String()}
- ctrs, err = r.LookupContainersWithStatus(filters)
- if err != nil {
- return ok, failures, err
- }
- for _, c := range ctrs {
- c := c
- _, err := iopodman.RemoveContainer().Call(r.Conn, c.ID(), false, false)
- if err != nil {
- failures[c.ID()] = err
- } else {
- ok = append(ok, c.ID())
- }
- }
- return ok, failures, nil
-}
-
-// Cleanup any leftovers bits of stopped containers
-func (r *LocalRuntime) CleanupContainers(ctx context.Context, cli *cliconfig.CleanupValues) ([]string, map[string]error, error) {
- return nil, nil, errors.New("container cleanup not supported for remote clients")
-}
-
-// Port displays port information about existing containers
-func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) {
- var (
- containers []*Container
- err error
- )
- // This one is a bit odd because when all is used, we only use running containers.
- if !c.All {
- containers, err = r.GetContainersByContext(false, c.Latest, c.InputArgs)
- } else {
- // we need to only use running containers if all
- filters := []string{define.ContainerStateRunning.String()}
- containers, err = r.LookupContainersWithStatus(filters)
- }
- if err != nil {
- return nil, err
- }
- return containers, nil
-}
-
-// GenerateSystemd creates a systemd until for a container
-func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
- return "", errors.New("systemd generation not supported for remote clients")
-}
-
-// GetNamespaces returns namespace information about a container for PS
-func (r *LocalRuntime) GetNamespaces(container shared.PsContainerOutput) *shared.Namespace {
- ns := shared.Namespace{
- PID: container.PID,
- Cgroup: container.Cgroup,
- IPC: container.IPC,
- MNT: container.MNT,
- NET: container.NET,
- PIDNS: container.PIDNS,
- User: container.User,
- UTS: container.UTS,
- }
- return &ns
-}
-
-// Commit creates a local image from a container
-func (r *LocalRuntime) Commit(ctx context.Context, c *cliconfig.CommitValues, container, imageName string) (string, error) {
- var iid string
- reply, err := iopodman.Commit().Send(r.Conn, varlink.More, container, imageName, c.Change, c.Author, c.Message, c.Pause, c.Format)
- if err != nil {
- return "", err
- }
- for {
- responses, flags, err := reply()
- if err != nil {
- return "", err
- }
- for _, line := range responses.Logs {
- fmt.Fprintln(os.Stderr, line)
- }
- iid = responses.Id
- if flags&varlink.Continues == 0 {
- break
- }
- }
- return iid, nil
-}
-
-// ExecContainer executes a command in the container
-func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecValues) (int, error) {
- var (
- oldTermState *term.State
- ec = define.ExecErrorCodeGeneric
- )
- // default invalid command exit code
- // Validate given environment variables
- cliEnv, err := envLib.ParseSlice(cli.Env)
- if err != nil {
- return 0, errors.Wrap(err, "error parsing environment variables")
- }
- envs := envLib.Slice(cliEnv)
-
- resize := make(chan remotecommand.TerminalSize, 5)
- 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 && cli.Tty {
- cancel, oldTermState, err := handleTerminalAttach(ctx, resize)
- if err != nil {
- return ec, err
- }
- defer cancel()
- defer restoreTerminal(oldTermState) // nolint: errcheck
-
- logrus.SetFormatter(&RawTtyFormatter{})
- term.SetRawTerminal(os.Stdin.Fd()) // nolint: errcheck
- }
-
- opts := iopodman.ExecOpts{
- Name: cli.InputArgs[0],
- Tty: cli.Tty,
- Privileged: cli.Privileged,
- Cmd: cli.InputArgs[1:],
- User: &cli.User,
- Workdir: &cli.Workdir,
- Env: &envs,
- DetachKeys: &cli.DetachKeys,
- }
-
- inputStream := os.Stdin
- if !cli.Interactive {
- inputStream = nil
- }
-
- reply, err := iopodman.ExecContainer().Send(r.Conn, varlink.Upgrade, opts)
- if err != nil {
- return ec, errors.Wrapf(err, "Exec failed to contact service for %s", cli.InputArgs)
- }
-
- _, err = reply()
- if err != nil {
- return ec, errors.Wrapf(err, "Exec operation failed for %s", cli.InputArgs)
- }
- ecChan := make(chan int, 1)
- errChan := configureVarlinkAttachStdio(r.Conn.Reader, r.Conn.Writer, inputStream, os.Stdout, oldTermState, resize, ecChan)
-
- ec = <-ecChan
- err = <-errChan
-
- return ec, err
-}
-
-func configureVarlinkAttachStdio(reader *bufio.Reader, writer *bufio.Writer, stdin *os.File, stdout *os.File, oldTermState *term.State, resize chan remotecommand.TerminalSize, ecChan chan int) chan error { // nolint: interfacer
- errChan := make(chan error, 1)
- // These are the special writers that encode input from the client.
- varlinkStdinWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.ToStdin)
- varlinkResizeWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.TerminalResize)
- varlinkHangupWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.HangUpFromClient)
-
- go func() {
- // Read from the wire and direct to stdout or stderr
- err := virtwriter.Reader(reader, stdout, os.Stderr, nil, nil, ecChan)
- defer restoreTerminal(oldTermState) // nolint: errcheck
- sendGenericError(ecChan)
- errChan <- err
- }()
-
- go func() {
- for termResize := range resize {
- b, err := json.Marshal(termResize)
- if err != nil {
- defer restoreTerminal(oldTermState) // nolint: errcheck,staticcheck
- sendGenericError(ecChan)
- errChan <- err
- }
- _, err = varlinkResizeWriter.Write(b)
- if err != nil {
- defer restoreTerminal(oldTermState) // nolint: errcheck,staticcheck
- sendGenericError(ecChan)
- errChan <- err
- }
- }
- }()
- if stdin != nil {
- // Takes stdinput and sends it over the wire after being encoded
- go func() {
- if _, err := io.Copy(varlinkStdinWriter, stdin); err != nil {
- defer restoreTerminal(oldTermState) // nolint: errcheck
- sendGenericError(ecChan)
- errChan <- err
- }
- _, err := varlinkHangupWriter.Write([]byte("EOF"))
- if err != nil {
- logrus.Errorf("unable to notify server to hangup: %q", err)
- }
- err = varlinkStdinWriter.Close()
- errChan <- err
- }()
- }
- return errChan
-}
-
-func sendGenericError(ecChan chan int) {
- if ecChan != nil {
- ecChan <- define.ExecErrorCodeGeneric
- }
-}