libct/int: show stderr if command failed

When running a process inside a container, make sure its stderr is not
nil (except for some trivial cases like cat). Modify waitProcess to show
failed command's stderr, if possible.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2026-04-08 15:21:06 -07:00
parent dd9fda7d60
commit bf4fcc3002
3 changed files with 24 additions and 8 deletions

View File

@@ -171,6 +171,7 @@ func TestEnter(t *testing.T) {
Env: standardEnvironment,
Stdin: stdinR,
Stdout: &stdout,
Stderr: new(strings.Builder),
Init: true,
}
err = container.Run(&pconfig)
@@ -184,13 +185,13 @@ func TestEnter(t *testing.T) {
stdinR2, stdinW2, err := os.Pipe()
ok(t, err)
pconfig2 := libcontainer.Process{
Cwd: "/",
Env: standardEnvironment,
Cwd: "/",
Args: []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"},
Env: standardEnvironment,
Stdin: stdinR2,
Stdout: &stdout2,
Stderr: new(strings.Builder),
}
pconfig2.Args = []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"}
pconfig2.Stdin = stdinR2
pconfig2.Stdout = &stdout2
err = container.Run(&pconfig2)
_ = stdinR2.Close()
defer stdinW2.Close()
@@ -253,6 +254,7 @@ func TestProcessEnv(t *testing.T) {
},
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
Init: true,
}
err = container.Run(&pconfig)
@@ -293,6 +295,7 @@ func TestProcessEmptyCaps(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
Init: true,
}
err = container.Run(&pconfig)
@@ -336,6 +339,7 @@ func TestProcessCaps(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
Capabilities: &configs.Capabilities{},
Init: true,
}
@@ -396,6 +400,7 @@ func TestAdditionalGroups(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
AdditionalGroups: []int{3333, 99999},
Init: true,
}
@@ -833,6 +838,7 @@ func TestSysctl(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
Init: true,
}
err = container.Run(&pconfig)
@@ -942,6 +948,7 @@ func TestOomScoreAdj(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
Init: true,
}
err = container.Run(&pconfig)
@@ -1081,6 +1088,7 @@ func TestHook(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
Init: true,
}
err = container.Run(&pconfig)
@@ -1196,6 +1204,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) {
Env: standardEnvironment,
Stdin: stdinR2,
Stdout: &stdout2,
Stderr: new(strings.Builder),
}
err = container.Run(pconfig2)
@@ -1307,6 +1316,7 @@ func TestRootfsPropagationSharedMount(t *testing.T) {
Env: standardEnvironment,
Stdin: stdinR2,
Stdout: &stdout2,
Stderr: new(strings.Builder),
Capabilities: &configs.Capabilities{},
}
@@ -1490,6 +1500,7 @@ func TestInitJoinPID(t *testing.T) {
Args: []string{"ps"},
Env: standardEnvironment,
Stdout: buffers.Stdout,
Stderr: new(strings.Builder),
}
err = container1.Run(ps)
ok(t, err)
@@ -1622,6 +1633,7 @@ func TestTmpfsCopyUp(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
Init: true,
}
err = container.Run(&pconfig)

View File

@@ -160,6 +160,7 @@ func TestExecInAdditionalGroups(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
Stderr: new(strings.Builder),
AdditionalGroups: []int{4444, 87654},
}
err = container.Run(&pconfig)
@@ -538,7 +539,7 @@ func TestExecInUserns(t *testing.T) {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
},
Stdout: buffers.Stdout,
Stderr: os.Stderr,
Stderr: new(strings.Builder),
}
err = container.Run(process2)
ok(t, err)

View File

@@ -90,7 +90,10 @@ func waitProcess(p *libcontainer.Process, t testing.TB) {
t.Helper()
_, err := p.Wait()
if err != nil {
t.Fatalf("unexpected error: %v", err)
if stderr, ok := p.Stderr.(fmt.Stringer); ok {
err = fmt.Errorf("%w; stderr:\n%s", err, stderr)
}
t.Fatalf("command failed: %v", err)
}
}