mirror of
https://github.com/containers/podman.git
synced 2025-06-22 01:48:54 +08:00
podman: new option --preserve-fd
add a new option --preserve-fd that allows to specify a list of FDs to pass down to the container. It is similar to --preserve-fds but it allows to specify a list of FDs instead of the maximum FD number to preserve. --preserve-fd and --preserve-fds are mutually exclusive. It requires crun since runc would complain if any fd below --preserve-fds is not preserved. Closes: https://github.com/containers/podman/issues/20844 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
@ -416,6 +416,9 @@ type ContainerMiscConfig struct {
|
||||
// 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"`
|
||||
// PreserveFD is a list of additional file descriptors (in addition
|
||||
// to 0, 1, 2) that will be passed to the executed process.
|
||||
PreserveFD []uint `json:"preserveFd,omitempty"`
|
||||
// Timezone is the timezone inside the container.
|
||||
// Local means it has the same timezone as the host machine
|
||||
Timezone string `json:"timezone,omitempty"`
|
||||
|
@ -66,6 +66,9 @@ type ExecConfig struct {
|
||||
// given is the number that will be passed into the exec session,
|
||||
// starting at 3.
|
||||
PreserveFDs uint `json:"preserveFds,omitempty"`
|
||||
// PreserveFD is a list of additional file descriptors (in addition
|
||||
// to 0, 1, 2) that will be passed to the executed process.
|
||||
PreserveFD []uint `json:"preserveFd,omitempty"`
|
||||
// ExitCommand is the exec session's exit command.
|
||||
// This command will be executed when the exec session exits.
|
||||
// If unset, no command will be executed.
|
||||
@ -1092,6 +1095,7 @@ func prepareForExec(c *Container, session *ExecSession) (*ExecOptions, error) {
|
||||
opts.Cwd = session.Config.WorkDir
|
||||
opts.User = session.Config.User
|
||||
opts.PreserveFDs = session.Config.PreserveFDs
|
||||
opts.PreserveFD = session.Config.PreserveFD
|
||||
opts.DetachKeys = session.Config.DetachKeys
|
||||
opts.ExitCommand = session.Config.ExitCommand
|
||||
opts.ExitCommandDelay = session.Config.ExitCommandDelay
|
||||
|
@ -202,6 +202,9 @@ type ExecOptions struct {
|
||||
// to 0, 1, 2) that will be passed to the executed process. The total FDs
|
||||
// passed will be 3 + PreserveFDs.
|
||||
PreserveFDs uint
|
||||
// PreserveFD is a list of additional file descriptors (in addition
|
||||
// to 0, 1, 2) that will be passed to the executed process.
|
||||
PreserveFD []uint
|
||||
// DetachKeys is a set of keys that, when pressed in sequence, will
|
||||
// detach from the container.
|
||||
// If not provided, the default keys will be used.
|
||||
|
@ -1038,6 +1038,39 @@ func (r *ConmonOCIRuntime) getLogTag(ctr *Container) (string, error) {
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
func getPreserveFdExtraFiles(preserveFD []uint, preserveFDs uint) (uint, []*os.File, []*os.File, error) {
|
||||
var filesToClose []*os.File
|
||||
var extraFiles []*os.File
|
||||
|
||||
preserveFDsMap := make(map[uint]struct{})
|
||||
for _, i := range preserveFD {
|
||||
if i < 3 {
|
||||
return 0, nil, nil, fmt.Errorf("cannot preserve FD %d, consider using the passthrough log-driver to pass STDIO streams into the container: %w", i, define.ErrInvalidArg)
|
||||
}
|
||||
if i-2 > preserveFDs {
|
||||
// preserveFDs is the number of FDs above 2 to keep around.
|
||||
// e.g. if the user specified FD=3, then preserveFDs must be 1.
|
||||
preserveFDs = i - 2
|
||||
}
|
||||
preserveFDsMap[i] = struct{}{}
|
||||
}
|
||||
|
||||
if preserveFDs > 0 {
|
||||
for fd := 3; fd < int(3+preserveFDs); fd++ {
|
||||
if len(preserveFDsMap) > 0 {
|
||||
if _, ok := preserveFDsMap[uint(fd)]; !ok {
|
||||
extraFiles = append(extraFiles, nil)
|
||||
continue
|
||||
}
|
||||
}
|
||||
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd))
|
||||
filesToClose = append(filesToClose, f)
|
||||
extraFiles = append(extraFiles, f)
|
||||
}
|
||||
}
|
||||
return preserveFDs, filesToClose, extraFiles, nil
|
||||
}
|
||||
|
||||
// createOCIContainer generates this container's main conmon instance and prepares it for starting
|
||||
func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) (int64, error) {
|
||||
var stderrBuf bytes.Buffer
|
||||
@ -1114,10 +1147,11 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
|
||||
args = append(args, []string{"--exit-command-arg", arg}...)
|
||||
}
|
||||
|
||||
// Pass down the LISTEN_* environment (see #10443).
|
||||
preserveFDs := ctr.config.PreserveFDs
|
||||
|
||||
// Pass down the LISTEN_* environment (see #10443).
|
||||
if val := os.Getenv("LISTEN_FDS"); val != "" {
|
||||
if ctr.config.PreserveFDs > 0 {
|
||||
if preserveFDs > 0 || len(ctr.config.PreserveFD) > 0 {
|
||||
logrus.Warnf("Ignoring LISTEN_FDS to preserve custom user-specified FDs")
|
||||
} else {
|
||||
fds, err := strconv.Atoi(val)
|
||||
@ -1128,6 +1162,10 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
|
||||
}
|
||||
}
|
||||
|
||||
preserveFDs, filesToClose, extraFiles, err := getPreserveFdExtraFiles(ctr.config.PreserveFD, preserveFDs)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if preserveFDs > 0 {
|
||||
args = append(args, formatRuntimeOpts("--preserve-fds", strconv.FormatUint(uint64(preserveFDs), 10))...)
|
||||
}
|
||||
@ -1189,14 +1227,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
|
||||
return 0, fmt.Errorf("configuring conmon env: %w", err)
|
||||
}
|
||||
|
||||
var filesToClose []*os.File
|
||||
if preserveFDs > 0 {
|
||||
for fd := 3; fd < int(3+preserveFDs); fd++ {
|
||||
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd))
|
||||
filesToClose = append(filesToClose, f)
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, f)
|
||||
}
|
||||
}
|
||||
cmd.ExtraFiles = extraFiles
|
||||
|
||||
cmd.Env = r.conmonEnv
|
||||
// we don't want to step on users fds they asked to preserve
|
||||
|
@ -391,8 +391,13 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
|
||||
|
||||
args := r.sharedConmonArgs(c, sessionID, c.execBundlePath(sessionID), c.execPidPath(sessionID), c.execLogPath(sessionID), c.execExitFileDir(sessionID), ociLog, define.NoLogging, c.config.LogTag)
|
||||
|
||||
if options.PreserveFDs > 0 {
|
||||
args = append(args, formatRuntimeOpts("--preserve-fds", strconv.FormatUint(uint64(options.PreserveFDs), 10))...)
|
||||
preserveFDs, filesToClose, extraFiles, err := getPreserveFdExtraFiles(options.PreserveFD, options.PreserveFDs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if preserveFDs > 0 {
|
||||
args = append(args, formatRuntimeOpts("--preserve-fds", strconv.FormatUint(uint64(preserveFDs), 10))...)
|
||||
}
|
||||
|
||||
if options.Terminal {
|
||||
@ -442,19 +447,12 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
|
||||
return nil, nil, fmt.Errorf("configuring conmon env: %w", err)
|
||||
}
|
||||
|
||||
var filesToClose []*os.File
|
||||
if options.PreserveFDs > 0 {
|
||||
for fd := 3; fd < int(3+options.PreserveFDs); fd++ {
|
||||
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd))
|
||||
filesToClose = append(filesToClose, f)
|
||||
execCmd.ExtraFiles = append(execCmd.ExtraFiles, f)
|
||||
}
|
||||
}
|
||||
execCmd.ExtraFiles = extraFiles
|
||||
|
||||
// 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
|
||||
execCmd.Env = r.conmonEnv
|
||||
execCmd.Env = append(execCmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", options.PreserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", options.PreserveFDs+4), fmt.Sprintf("_OCI_ATTACHPIPE=%d", options.PreserveFDs+5))
|
||||
execCmd.Env = append(execCmd.Env, fmt.Sprintf("_OCI_SYNCPIPE=%d", preserveFDs+3), fmt.Sprintf("_OCI_STARTPIPE=%d", preserveFDs+4), fmt.Sprintf("_OCI_ATTACHPIPE=%d", preserveFDs+5))
|
||||
execCmd.Env = append(execCmd.Env, conmonEnv...)
|
||||
|
||||
execCmd.ExtraFiles = append(execCmd.ExtraFiles, childSyncPipe, childStartPipe, childAttachPipe)
|
||||
|
@ -1555,6 +1555,18 @@ func WithPreserveFDs(fd uint) CtrCreateOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPreserveFD forwards from the process running Libpod into the container
|
||||
// the given list of extra FDs to the created container
|
||||
func WithPreserveFD(fds []uint) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return define.ErrCtrFinalized
|
||||
}
|
||||
ctr.config.PreserveFD = fds
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithCreateCommand adds the full command plus arguments of the current
|
||||
// process to the container config.
|
||||
func WithCreateCommand(cmd []string) CtrCreateOption {
|
||||
|
Reference in New Issue
Block a user