Skip to content

Commit 027fecb

Browse files
committed
Make exec support --cidfile.
Fixes: containers#21256 Signed-off-by: Martin Glatzle <[email protected]>
1 parent b762c15 commit 027fecb

File tree

3 files changed

+78
-9
lines changed

3 files changed

+78
-9
lines changed

cmd/podman/containers/exec.go

+38-9
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var (
5050
envInput, envFile []string
5151
execOpts entities.ExecOptions
5252
execDetach bool
53+
execCidFile string
5354
)
5455

5556
func execFlags(cmd *cobra.Command) {
@@ -63,6 +64,10 @@ func execFlags(cmd *cobra.Command) {
6364
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 _")
6465
_ = cmd.RegisterFlagCompletionFunc(detachKeysFlagName, common.AutocompleteDetachKeys)
6566

67+
cidfileFlagName := "cidfile"
68+
flags.StringVar(&execCidFile, cidfileFlagName, "", "File to read the container ID from")
69+
_ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault)
70+
6671
envFlagName := "env"
6772
flags.StringArrayVarP(&envInput, envFlagName, "e", []string{}, "Set environment variables")
6873
_ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone)
@@ -97,6 +102,7 @@ func execFlags(cmd *cobra.Command) {
97102

98103
if registry.IsRemote() {
99104
_ = flags.MarkHidden("preserve-fds")
105+
_ = flags.MarkHidden("cidfile")
100106
}
101107
}
102108

@@ -116,16 +122,12 @@ func init() {
116122
}
117123

118124
func exec(cmd *cobra.Command, args []string) error {
119-
var nameOrID string
120-
121-
if len(args) == 0 && !execOpts.Latest {
122-
return errors.New("exec requires the name or ID of a container or the --latest flag")
123-
}
124-
execOpts.Cmd = args
125-
if !execOpts.Latest {
126-
execOpts.Cmd = args[1:]
127-
nameOrID = strings.TrimPrefix(args[0], "/")
125+
nameOrID, command, err := determineTargetCtrAndCmd(args, execOpts.Latest, execCidFile != "")
126+
if err != nil {
127+
return err
128128
}
129+
execOpts.Cmd = command
130+
129131
// Validate given environment variables
130132
execOpts.Envs = make(map[string]string)
131133
for _, f := range envFile {
@@ -191,6 +193,33 @@ func exec(cmd *cobra.Command, args []string) error {
191193
return nil
192194
}
193195

196+
// determineTargetCtrAndCmd determines which command exec should run in which container
197+
func determineTargetCtrAndCmd(args []string, latestSpecified bool, execCidFileProvided bool) (string, []string, error) {
198+
var nameOrID string
199+
var command []string
200+
201+
if len(args) == 0 && !latestSpecified && !execCidFileProvided {
202+
return "", nil, errors.New("exec requires the name or ID of a container or the --latest or --cidfile flag")
203+
} else if latestSpecified && execCidFileProvided {
204+
return "", nil, errors.New("--latest and --cidfile can not be used together")
205+
}
206+
command = args
207+
if !latestSpecified {
208+
if !execCidFileProvided {
209+
// assume first arg to be name or ID
210+
command = args[1:]
211+
nameOrID = strings.TrimPrefix(args[0], "/")
212+
} else {
213+
content, err := os.ReadFile(execCidFile)
214+
if err != nil {
215+
return "", nil, fmt.Errorf("reading CIDFile: %w", err)
216+
}
217+
nameOrID = strings.Split(string(content), "\n")[0]
218+
}
219+
}
220+
return nameOrID, command, nil
221+
}
222+
194223
func execWait(ctr string, seconds int32) error {
195224
maxDuration := time.Duration(seconds) * time.Second
196225
interval := 100 * time.Millisecond

docs/source/markdown/podman-exec.1.md.in

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ podman\-exec - Execute a command in a running container
1313

1414
## OPTIONS
1515

16+
#### **--cidfile**=*file*
17+
18+
Read the ID of the target container from the specified *file*.
19+
1620
#### **--detach**, **-d**
1721

1822
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.

test/e2e/exec_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,42 @@ var _ = Describe("Podman exec", func() {
6060
Expect(session).Should(ExitCleanly())
6161
})
6262

63+
It("podman exec simple command using cidfile", func() {
64+
SkipIfRemote("not supported for --cidfile")
65+
66+
cidFile := filepath.Join(tempdir, "cid")
67+
session := podmanTest.RunTopContainerWithArgs("test1", []string{"--cidfile", cidFile})
68+
session.WaitWithDefaultTimeout()
69+
Expect(session).Should(ExitCleanly())
70+
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
71+
72+
result := podmanTest.Podman([]string{"exec", "--cidfile", cidFile, "ls"})
73+
result.WaitWithDefaultTimeout()
74+
Expect(result).Should(ExitCleanly())
75+
})
76+
77+
It("podman exec latest and cidfile", func() {
78+
SkipIfRemote("not supported for --cidfile")
79+
80+
cidFile := filepath.Join(tempdir, "cid")
81+
session := podmanTest.RunTopContainerWithArgs("test1", []string{"--cidfile", cidFile})
82+
session.WaitWithDefaultTimeout()
83+
Expect(session).Should(ExitCleanly())
84+
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
85+
86+
result := podmanTest.Podman([]string{"exec", "--cidfile", cidFile, "--latest", "ls"})
87+
result.WaitWithDefaultTimeout()
88+
Expect(result).Should(ExitWithError(125, `--latest and --cidfile can not be used together`))
89+
})
90+
91+
It("podman exec nonextant cidfile", func() {
92+
SkipIfRemote("not supported for --cidfile")
93+
94+
session := podmanTest.Podman([]string{"exec", "--cidfile", "foobar", "ls"})
95+
session.WaitWithDefaultTimeout()
96+
Expect(session).Should(ExitWithError(125, `reading CIDFile: open foobar: no such file or directory`))
97+
})
98+
6399
It("podman exec environment test", func() {
64100
setup := podmanTest.RunTopContainer("test1")
65101
setup.WaitWithDefaultTimeout()

0 commit comments

Comments
 (0)