Make exec support --cidfile.

Fixes: #21256

Signed-off-by: Martin Glatzle <findessp@yandex.ru>
This commit is contained in:
Martin Glatzle
2024-07-06 00:33:04 +02:00
parent b762c15e1c
commit f1527283d6
3 changed files with 73 additions and 9 deletions

View File

@ -50,6 +50,7 @@ var (
envInput, envFile []string envInput, envFile []string
execOpts entities.ExecOptions execOpts entities.ExecOptions
execDetach bool execDetach bool
execCidFile string
) )
func execFlags(cmd *cobra.Command) { func execFlags(cmd *cobra.Command) {
@ -63,6 +64,10 @@ func execFlags(cmd *cobra.Command) {
flags.StringVar(&execOpts.DetachKeys, detachKeysFlagName, containerConfig.DetachKeys(), "Select the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _") flags.StringVar(&execOpts.DetachKeys, detachKeysFlagName, containerConfig.DetachKeys(), "Select the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
_ = cmd.RegisterFlagCompletionFunc(detachKeysFlagName, common.AutocompleteDetachKeys) _ = cmd.RegisterFlagCompletionFunc(detachKeysFlagName, common.AutocompleteDetachKeys)
cidfileFlagName := "cidfile"
flags.StringVar(&execCidFile, cidfileFlagName, "", "File to read the container ID from")
_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
envFlagName := "env" envFlagName := "env"
flags.StringArrayVarP(&envInput, envFlagName, "e", []string{}, "Set environment variables") flags.StringArrayVarP(&envInput, envFlagName, "e", []string{}, "Set environment variables")
_ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone) _ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone)
@ -116,16 +121,12 @@ func init() {
} }
func exec(cmd *cobra.Command, args []string) error { func exec(cmd *cobra.Command, args []string) error {
var nameOrID string nameOrID, command, err := determineTargetCtrAndCmd(args, execOpts.Latest, execCidFile != "")
if err != nil {
return err
}
execOpts.Cmd = command
if len(args) == 0 && !execOpts.Latest {
return errors.New("exec requires the name or ID of a container or the --latest flag")
}
execOpts.Cmd = args
if !execOpts.Latest {
execOpts.Cmd = args[1:]
nameOrID = strings.TrimPrefix(args[0], "/")
}
// Validate given environment variables // Validate given environment variables
execOpts.Envs = make(map[string]string) execOpts.Envs = make(map[string]string)
for _, f := range envFile { for _, f := range envFile {
@ -191,6 +192,33 @@ func exec(cmd *cobra.Command, args []string) error {
return nil return nil
} }
// determineTargetCtrAndCmd determines which command exec should run in which container
func determineTargetCtrAndCmd(args []string, latestSpecified bool, execCidFileProvided bool) (string, []string, error) {
var nameOrID string
var command []string
if len(args) == 0 && !latestSpecified && !execCidFileProvided {
return "", nil, errors.New("exec requires the name or ID of a container or the --latest or --cidfile flag")
} else if latestSpecified && execCidFileProvided {
return "", nil, errors.New("--latest and --cidfile can not be used together")
}
command = args
if !latestSpecified {
if !execCidFileProvided {
// assume first arg to be name or ID
command = args[1:]
nameOrID = strings.TrimPrefix(args[0], "/")
} else {
content, err := os.ReadFile(execCidFile)
if err != nil {
return "", nil, fmt.Errorf("reading CIDFile: %w", err)
}
nameOrID = strings.Split(string(content), "\n")[0]
}
}
return nameOrID, command, nil
}
func execWait(ctr string, seconds int32) error { func execWait(ctr string, seconds int32) error {
maxDuration := time.Duration(seconds) * time.Second maxDuration := time.Duration(seconds) * time.Second
interval := 100 * time.Millisecond interval := 100 * time.Millisecond

View File

@ -13,6 +13,10 @@ podman\-exec - Execute a command in a running container
## OPTIONS ## OPTIONS
#### **--cidfile**=*file*
Read the ID of the target container from the specified *file*.
#### **--detach**, **-d** #### **--detach**, **-d**
Start the exec session, but do not attach to it. The command runs in the background, and the exec session is automatically removed when it completes. The **podman exec** command prints the ID of the exec session and exits immediately after it starts. Start the exec session, but do not attach to it. The command runs in the background, and the exec session is automatically removed when it completes. The **podman exec** command prints the ID of the exec session and exits immediately after it starts.

View File

@ -60,6 +60,38 @@ var _ = Describe("Podman exec", func() {
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
}) })
It("podman exec simple command using cidfile", func() {
cidFile := filepath.Join(tempdir, "cid")
session := podmanTest.RunTopContainerWithArgs("test1", []string{"--cidfile", cidFile})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
result := podmanTest.Podman([]string{"exec", "--cidfile", cidFile, "ls"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
})
It("podman exec latest and cidfile", func() {
SkipIfRemote("--latest flag n/a")
cidFile := filepath.Join(tempdir, "cid")
session := podmanTest.RunTopContainerWithArgs("test1", []string{"--cidfile", cidFile})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
result := podmanTest.Podman([]string{"exec", "--cidfile", cidFile, "--latest", "ls"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitWithError(125, `--latest and --cidfile can not be used together`))
})
It("podman exec nonextant cidfile", func() {
session := podmanTest.Podman([]string{"exec", "--cidfile", "foobar", "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitWithError(125, `reading CIDFile: open foobar: no such file or directory`))
})
It("podman exec environment test", func() { It("podman exec environment test", func() {
setup := podmanTest.RunTopContainer("test1") setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout() setup.WaitWithDefaultTimeout()