Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --preservefds to podman run #6625

Merged
merged 1 commit into from
Jun 23, 2020
Merged
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: 1 addition & 0 deletions cmd/podman/common/create_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type ContainerCLIOpts struct {
PIDsLimit int64
Pod string
PodIDFile string
PreserveFDs uint
Privileged bool
PublishAll bool
Pull string
Expand Down
1 change: 1 addition & 0 deletions cmd/podman/common/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
s.LogConfiguration.Options = logOpts
s.Name = c.Name
s.PreserveFDs = c.PreserveFDs

s.OOMScoreAdj = &c.OOMScoreAdj
if c.Restart != "" {
Expand Down
3 changes: 3 additions & 0 deletions cmd/podman/containers/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ func runFlags(flags *pflag.FlagSet) {
flags.SetNormalizeFunc(common.AliasFlags)
flags.BoolVar(&runOpts.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
flags.BoolVar(&runRmi, "rmi", false, "Remove container image unless used by other containers")
flags.UintVar(&runOpts.PreserveFDs, "preserve-fds", 0, "Pass a number of additional file descriptors into the container")
if registry.IsRemote() {
_ = flags.MarkHidden("authfile")
_ = flags.MarkHidden("env-host")
_ = flags.MarkHidden("http-proxy")
_ = flags.MarkHidden("preserve-fds")
}
// Not sure we want these exposed yet. If we do, they need to be documented in man pages
_ = flags.MarkHidden("override-arch")
Expand Down Expand Up @@ -163,6 +165,7 @@ func run(cmd *cobra.Command, args []string) error {
}
runOpts.Detach = cliVals.Detach
runOpts.DetachKeys = cliVals.DetachKeys
cliVals.PreserveFDs = runOpts.PreserveFDs
s := specgen.NewSpecGenerator(args[0], cliVals.RootFS)
if err := common.FillOutSpecGen(s, &cliVals, args); err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions completions/bash/podman
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,7 @@ _podman_container_run() {
--pids-limit
--pod
--pod-id-file
--preserve-fds
--publish -p
--pull
--runtime
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-run.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,10 @@ If a container is run with a pod, and the pod has an infra-container, the infra-

Run container in an existing pod and read the pod's ID from the specified file. If a container is run within a pod, and the pod has an infra-container, the infra-container will be started before the container is.

**--preserve-fds**=*N*

Pass down to the process N additional file descriptors (in addition to 0, 1, 2). The total FDs will be 3+N.
mheon marked this conversation as resolved.
Show resolved Hide resolved

**--privileged**=**true**|**false**

Give extended privileges to this container. The default is **false**.
Expand Down
5 changes: 5 additions & 0 deletions libpod/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,11 @@ type ContainerConfig struct {

// HealthCheckConfig has the health check command and related timings
HealthCheckConfig *manifest.Schema2HealthConfig `json:"healthcheck"`

// PreserveFDs is a number of additional file descriptors (in addition
// to 0, 1, 2) that will be passed to the executed process. The total FDs
// passed will be 3 + PreserveFDs.
PreserveFDs uint `json:"preserveFds,omitempty"`
mheon marked this conversation as resolved.
Show resolved Hide resolved
}

// ContainerNamedVolume is a named volume that will be mounted into the
Expand Down
24 changes: 23 additions & 1 deletion libpod/oci_conmon_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,10 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
}
}

if ctr.config.PreserveFDs > 0 {
args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", ctr.config.PreserveFDs))...)
}

if restoreOptions != nil {
args = append(args, "--restore", ctr.CheckpointPath())
if restoreOptions.TCPEstablished {
Expand Down Expand Up @@ -935,8 +939,16 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
return err
}

if ctr.config.PreserveFDs > 0 {
for fd := 3; fd < int(3+ctr.config.PreserveFDs); fd++ {
cmd.ExtraFiles = append(cmd.ExtraFiles, os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)))
}
}

cmd.Env = r.conmonEnv
cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3), fmt.Sprintf("_OCI_STARTPIPE=%d", 4))
// we don't want to step on users fds they asked to preserve
// Since 0-2 are used for stdio, start the fds we pass in at preserveFDs+3
cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", ctr.config.PreserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", ctr.config.PreserveFDs+4))
cmd.Env = append(cmd.Env, conmonEnv...)
cmd.ExtraFiles = append(cmd.ExtraFiles, childSyncPipe, childStartPipe)
cmd.ExtraFiles = append(cmd.ExtraFiles, envFiles...)
Expand Down Expand Up @@ -1018,6 +1030,16 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
ctr.state.ConmonPID = conmonPID
}

if ctr.config.PreserveFDs > 0 {
for fd := 3; fd < int(3+ctr.config.PreserveFDs); fd++ {
// These fds were passed down to the runtime. Close them
// and not interfere
if err := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close(); err != nil {
logrus.Debugf("unable to close file fd-%d", fd)
}
}
}

return nil
}

Expand Down
12 changes: 12 additions & 0 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,18 @@ func WithHealthCheck(healthCheck *manifest.Schema2HealthConfig) CtrCreateOption
}
}

// WithPreserveFDs forwards from the process running Libpod into the container
// the given number of extra FDs (starting after the standard streams) to the created container
func WithPreserveFDs(fd uint) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.PreserveFDs = fd
return nil
}
}

// WithCreateCommand adds the full command plus arguments of the current
// process to the container config.
func WithCreateCommand() CtrCreateOption {
Expand Down
1 change: 1 addition & 0 deletions pkg/domain/entities/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ type ContainerRunOptions struct {
ErrorStream *os.File
InputStream *os.File
OutputStream *os.File
PreserveFDs uint
Rm bool
SigProxy bool
Spec *specgen.SpecGenerator
Expand Down
4 changes: 4 additions & 0 deletions pkg/specgen/generate/container_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, err
}

if s.PreserveFDs > 0 {
options = append(options, libpod.WithPreserveFDs(s.PreserveFDs))
}

opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, newImage)
if err != nil {
return nil, err
Expand Down
5 changes: 5 additions & 0 deletions pkg/specgen/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ type ContainerBasicConfig struct {
// Remove indicates if the container should be removed once it has been started
// and exits
Remove bool `json:"remove"`
// PreserveFDs is a number of additional file descriptors (in addition
// to 0, 1, 2) that will be passed to the executed process. The total FDs
// passed will be 3 + PreserveFDs.
// set tags as `json:"-"` for not supported remote
PreserveFDs uint `json:"-"`
mheon marked this conversation as resolved.
Show resolved Hide resolved
}

// ContainerStorageConfig contains information on the storage configuration of a
Expand Down
12 changes: 12 additions & 0 deletions test/e2e/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1015,4 +1015,16 @@ USER mail`
Expect(session.ExitCode()).To(Equal(0))
}
})

It("podman run --preserve-fds", func() {
devNull, err := os.Open("/dev/null")
Expect(err).To(BeNil())
defer devNull.Close()
files := []*os.File{
devNull,
}
session := podmanTest.PodmanExtraFiles([]string{"run", "--preserve-fds", "1", ALPINE, "ls"}, files)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
})
12 changes: 12 additions & 0 deletions test/system/030-run.bats
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ echo $rand | 0 | $rand
is "$tests_run" "$(grep . <<<$tests | wc -l)" "Ran the full set of tests"
}

# 'run --preserve-fds' passes a number of additional file descriptors into the container
@test "podman run --preserve-fds" {
skip "enable this once #6653 is fixed"
skip_if_remote

content=$(random_string 20)
echo "$content" > $PODMAN_TMPDIR/tempfile

run_podman run --rm -i --preserve-fds=2 $IMAGE sh -c "cat <&4" 4<$PODMAN_TMPDIR/tempfile
is "$output" "$content" "container read input from fd 4"
}

@test "podman run - uidmapping has no /sys/kernel mounts" {
skip_if_rootless "cannot umount as rootless"
skip_if_remote "TODO Fix this for remote case"
Expand Down