Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion cmd/podman/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const remoteclient = false
func getMainCommands() []*cobra.Command {
rootCommands := []*cobra.Command{
_commitCommand,
_execCommand,
_playCommand,
_loginCommand,
_logoutCommand,
Expand Down
92 changes: 20 additions & 72 deletions cmd/podman/exec.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
package main

import (
"fmt"
"io/ioutil"
"os"
"strconv"

"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -51,79 +45,33 @@ func init() {
flags.IntVar(&execCommand.PreserveFDs, "preserve-fds", 0, "Pass N additional file descriptors to the container")
flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container")
markFlagHiddenForRemoteClient("latest", flags)
markFlagHiddenForRemoteClient("preserve-fds", flags)
}

func execCmd(c *cliconfig.ExecValues) error {
args := c.InputArgs
var ctr *libpod.Container
var err error
argStart := 1
if len(args) < 1 && !c.Latest {
return errors.Errorf("you must provide one container name or id")
}
if len(args) < 2 && !c.Latest {
return errors.Errorf("you must provide a command to exec")
}
if c.Latest {
argStart = 0
if len(c.InputArgs) < 1 {
return errors.Errorf("you must provide a command to exec")
}
} else {
switch {
case len(c.InputArgs) < 1:
return errors.Errorf("you must provide one container name or id")
case len(c.InputArgs) < 2:
return errors.Errorf("you must provide a command to exec")
}
}
cmd := args[argStart:]
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)

runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)

if c.Latest {
ctr, err = runtime.GetLatestContainer()
} else {
ctr, err = runtime.LookupContainer(args[0])
}
_, _, err = runtime.ContainerExecute(getContext(), c)
if err != nil {
return errors.Wrapf(err, "unable to exec into %s", args[0])
}

if c.PreserveFDs > 0 {
entries, err := ioutil.ReadDir("/proc/self/fd")
if err != nil {
return errors.Wrapf(err, "unable to read /proc/self/fd")
}
m := make(map[int]bool)
for _, e := range entries {
i, err := strconv.Atoi(e.Name())
if err != nil {
if err != nil {
return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
}
}
m[i] = true
}
for i := 3; i < 3+c.PreserveFDs; i++ {
if _, found := m[i]; !found {
return errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
}
}

logrus.Error(err)
return errors.Cause(err)
}

// ENVIRONMENT VARIABLES
env := map[string]string{}

if err := parse.ReadKVStrings(env, []string{}, c.Env); err != nil {
return errors.Wrapf(err, "unable to process environment variables")
}
envs := []string{}
for k, v := range env {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}

streams := new(libpod.AttachStreams)
streams.OutputStream = os.Stdout
streams.ErrorStream = os.Stderr
streams.InputStream = os.Stdin
streams.AttachOutput = true
streams.AttachError = true
streams.AttachInput = true

return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs)
return nil
}
1 change: 1 addition & 0 deletions cmd/podman/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var mainCommands = []*cobra.Command{
_diffCommand,
_createCommand,
_eventsCommand,
_execCommand,
_exportCommand,
_generateCommand,
_historyCommand,
Expand Down
20 changes: 20 additions & 0 deletions cmd/podman/varlink/io.podman.varlink
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,23 @@ type DiffInfo(
changeType: string
)

type ExecOpts(
# container name or id
name: string,
# Create pseudo tty
tty: bool,
# privileged access in container
privileged: bool,
# command to execute in container
cmd: []string,
# user to use in container
user: ?string,
# workdir to run command in container
workdir: ?string,
# slice of keyword=value environment variables
env: ?[]string
)

# GetVersion returns version and build information of the podman service
method GetVersion() -> (
version: string,
Expand Down Expand Up @@ -1088,6 +1105,9 @@ method ContainerRestore(name: string, keep: bool, tcpEstablished: bool) -> (id:
# ContainerRunlabel runs executes a command as described by a given container image label.
method ContainerRunlabel(runlabel: Runlabel) -> ()

# ContainerExecute runs executes a command in the given container.
method ContainerExecute(opts: ExecOpts) -> ()

# ListContainerMounts gathers all the mounted container mount points and returns them as an array
# of strings
# #### Example
Expand Down
74 changes: 74 additions & 0 deletions pkg/adapter/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/containers/storage"
Expand Down Expand Up @@ -510,3 +511,76 @@ func (r *LocalRuntime) Restore(c *cliconfig.RestoreValues, options libpod.Contai
}
return lastError
}

// ContainerExecute executes a command in the container
func (r *LocalRuntime) ContainerExecute(ctx context.Context, cli *cliconfig.ExecValues) ([]string, map[string]error, error) {
var (
cmd []string
ctr *Container
err error
failures = map[string]error{}
ok = []string{}
)

if cli.Latest {
if ctr, err = r.GetLatestContainer(); err != nil {
return ok, failures, err
}
cmd = cli.InputArgs[0:]
} else {
if ctr, err = r.LookupContainer(cli.InputArgs[0]); err != nil {
return ok, failures, err
}
cmd = cli.InputArgs[1:]
}

if cli.PreserveFDs > 0 {
entries, err := ioutil.ReadDir("/proc/self/fd")
if err != nil {
return ok, failures, errors.Wrapf(err, "Exec unable to read /proc/self/fd")
}

m := make(map[int]bool)
for _, e := range entries {
i, err := strconv.Atoi(e.Name())
if err != nil {
return ok, failures, errors.Wrapf(err, "Exec cannot parse %s in /proc/self/fd", e.Name())
}
m[i] = true
}

for i := 3; i < 3+cli.PreserveFDs; i++ {
if _, found := m[i]; !found {
return ok, failures, errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
}
}
}

// Validate given environment variables
env := map[string]string{}
if err := parse.ReadKVStrings(env, []string{}, cli.Env); err != nil {
return ok, failures, errors.Wrapf(err, "Exec unable to process environment variables")
}

// Build env slice of key=value strings for Exec
envs := []string{}
for k, v := range env {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}

streams := new(libpod.AttachStreams)
streams.OutputStream = os.Stdout
streams.ErrorStream = os.Stderr
streams.InputStream = os.Stdin
streams.AttachOutput = true
streams.AttachError = true
streams.AttachInput = true

err = ctr.Exec(cli.Tty, cli.Privileged, envs, cmd, cli.User, cli.Workdir, streams, cli.PreserveFDs)
if err != nil {
failures[ctr.ID()] = err
} else {
ok = append(ok, ctr.ID())
}
return ok, failures, err
}
38 changes: 38 additions & 0 deletions pkg/adapter/containers_remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/shared/parse"
iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/inspect"
Expand Down Expand Up @@ -609,3 +610,40 @@ func (r *LocalRuntime) Restore(c *cliconfig.RestoreValues, options libpod.Contai
}
return lastError
}

// ContainerExecute executes a command in the container
func (r *LocalRuntime) ContainerExecute(ctx context.Context, cli *cliconfig.ExecValues) ([]string, map[string]error, error) {
// Validate given environment variables
env := map[string]string{}
if err := parse.ReadKVStrings(env, []string{}, cli.Env); err != nil {
return nil, nil, errors.Wrapf(err, "Exec unable to process environment variables")
}

// Build env slice of key=value strings for Exec
envs := []string{}
for k, v := range env {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}

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,
}

receive, err := iopodman.ContainerExecute().Send(r.Conn, varlink.Upgrade, opts)
if err != nil {
return nil, nil, errors.Wrapf(err, "Exec failed to contact service for %s", cli.InputArgs)
}

_, err = receive()
if err != nil {
return nil, nil, errors.Wrapf(err, "Exec operation failed for %s", cli.InputArgs)
}

return nil, nil, nil
}
2 changes: 1 addition & 1 deletion pkg/adapter/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"
"io"
"io/ioutil"
"k8s.io/api/core/v1"
"os"
"text/template"

Expand All @@ -25,6 +24,7 @@ import (
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
)

// LocalRuntime describes a typical libpod runtime
Expand Down
7 changes: 4 additions & 3 deletions pkg/varlinkapi/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st
if finalErr != libpod.ErrDetach && finalErr != nil {
logrus.Error(finalErr)
}
quitWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.Quit)
_, err = quitWriter.Write([]byte("HANG-UP"))
// TODO error handling is not quite right here yet

if err = virtwriter.HangUp(writer); err != nil {
logrus.Errorf("Failed to HANG-UP attach to %s: %s", ctr.ID(), err.Error())
}
return call.Writer.Flush()
}

Expand Down
Loading