Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e8fb6c4

Browse files
committedFeb 20, 2025·
fix: logs updated on starting of a stopped container
Signed-off-by: Shubharanshu Mahapatra <[email protected]>
1 parent 87cc074 commit e8fb6c4

File tree

4 files changed

+115
-3
lines changed

4 files changed

+115
-3
lines changed
 

‎cmd/nerdctl/container/container_logs_test.go

+97
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"os/exec"
2222
"runtime"
23+
"strconv"
2324
"strings"
2425
"testing"
2526
"time"
@@ -28,6 +29,8 @@ import (
2829
"gotest.tools/v3/icmd"
2930

3031
"github.com/containerd/nerdctl/v2/pkg/testutil"
32+
"github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
33+
"github.com/containerd/nerdctl/v2/pkg/testutil/test"
3134
)
3235

3336
func TestLogs(t *testing.T) {
@@ -255,3 +258,97 @@ func TestTailFollowRotateLogs(t *testing.T) {
255258
}
256259
assert.Equal(t, true, len(tailLogs) > linesPerFile, logRun.Stderr())
257260
}
261+
262+
func TestLogsWithStartContainer(t *testing.T) {
263+
if runtime.GOOS == "windows" {
264+
t.Skip("dual logging test is not supported on Windows")
265+
}
266+
267+
testCase := nerdtest.Setup()
268+
testCase.SubTests = []*test.Case{
269+
{
270+
Description: "Test logs are directed correctly for container start of a interactive container",
271+
Require: test.Require(
272+
test.Not(nerdtest.Docker),
273+
test.Not(test.Windows),
274+
),
275+
Setup: func(data test.Data, helpers test.Helpers) {
276+
cmd := helpers.Command("run", "-it", "--name", data.Identifier(), testutil.CommonImage)
277+
cmd.WithWrapper("unbuffer", "-p")
278+
cmd.WithStdin(testutil.NewDelayOnceReader(strings.NewReader("echo foo\nexit\n")))
279+
cmd.Run(&test.Expected{
280+
ExitCode: 0,
281+
})
282+
283+
},
284+
Cleanup: func(data test.Data, helpers test.Helpers) {
285+
helpers.Anyhow("rm", "-f", data.Identifier())
286+
},
287+
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
288+
cmd := helpers.Command("start", "-a", data.Identifier())
289+
cmd.WithWrapper("unbuffer", "-p")
290+
cmd.WithStdin(testutil.NewDelayOnceReader(strings.NewReader("echo bar\nexit\n")))
291+
cmd.Run(&test.Expected{
292+
ExitCode: 0,
293+
})
294+
295+
cmd = helpers.Command("logs", data.Identifier())
296+
297+
return cmd
298+
},
299+
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
300+
return &test.Expected{
301+
ExitCode: 0,
302+
Errors: []error{},
303+
Output: test.All(
304+
func(stdout string, info string, t *testing.T) {
305+
assert.Assert(t, strings.Contains(stdout, "foo"))
306+
assert.Assert(t, strings.Contains(stdout, "bar"))
307+
},
308+
),
309+
}
310+
},
311+
},
312+
{
313+
Description: "Test logs are captured after stopping and starting a non-interactive container and continue capturing new logs",
314+
Require: test.Require(
315+
test.Not(nerdtest.Docker),
316+
test.Not(test.Windows),
317+
),
318+
Setup: func(data test.Data, helpers test.Helpers) {
319+
cmd := helpers.Command("run", "-d", "--name", data.Identifier(), testutil.CommonImage, "sh", "-c", "while true; do echo foo; sleep 1; done")
320+
cmd.Run(&test.Expected{
321+
ExitCode: 0,
322+
})
323+
},
324+
Cleanup: func(data test.Data, helpers test.Helpers) {
325+
helpers.Anyhow("rm", "-f", data.Identifier())
326+
},
327+
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
328+
329+
helpers.Anyhow("stop", data.Identifier())
330+
initialLogs := helpers.Capture("logs", data.Identifier())
331+
initialFooCount := strings.Count(initialLogs, "foo")
332+
data.Set("initialFooCount", strconv.Itoa(initialFooCount))
333+
helpers.Anyhow("start", data.Identifier())
334+
time.Sleep(5 * time.Second)
335+
cmd := helpers.Command("logs", data.Identifier())
336+
return cmd
337+
},
338+
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
339+
return &test.Expected{
340+
ExitCode: 0,
341+
Errors: []error{},
342+
Output: test.All(
343+
func(stdout string, info string, t *testing.T) {
344+
finalLogsCount := strings.Count(stdout, "foo")
345+
initialFooCount, _ := strconv.Atoi(data.Get("initialFooCount"))
346+
assert.Assert(t, finalLogsCount > initialFooCount, "Expected 'foo' count to increase after restart")
347+
},
348+
),
349+
}
350+
},
351+
},
352+
}
353+
testCase.Run(t)
354+
}

‎pkg/taskutil/taskutil.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,16 @@ func NewTask(ctx context.Context, client *containerd.Client, container container
6666
var ioCreator cio.Creator
6767
if len(attachStreamOpt) != 0 {
6868
log.G(ctx).Debug("attaching output instead of using the log-uri")
69+
// when attaching a TTY we use writee for stdio and binary for log persistence
6970
if flagT {
7071
in, err := consoleutil.NewDetachableStdin(con, detachKeys, closer)
7172
if err != nil {
7273
return nil, err
7374
}
74-
ioCreator = cio.NewCreator(cio.WithStreams(in, con, nil), cio.WithTerminal)
75+
ioCreator = cioutil.NewContainerIO(namespace, logURI, true, in, con, nil)
7576
} else {
7677
streams := processAttachStreamsOpt(attachStreamOpt)
77-
ioCreator = cio.NewCreator(cio.WithStreams(streams.stdIn, streams.stdOut, streams.stdErr))
78+
ioCreator = cioutil.NewContainerIO(namespace, logURI, false, streams.stdIn, streams.stdOut, streams.stdErr)
7879
}
7980

8081
} else if flagT && flagD {

‎pkg/testutil/testutil_freebsd.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
package testutil
1818

19-
import "fmt"
19+
import (
20+
"fmt"
21+
"io"
22+
)
2023

2124
const (
2225
CommonImage = "docker.io/knast/freebsd:13-STABLE"
@@ -40,3 +43,8 @@ func mirrorOf(s string) string {
4043
// plain mirror, NOT stargz-converted images
4144
return fmt.Sprintf("ghcr.io/stargz-containers/%s-org", s)
4245
}
46+
47+
func NewDelayOnceReader(wrapped io.Reader) io.Reader {
48+
// not implemented
49+
return nil
50+
}

‎pkg/testutil/testutil_windows.go

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package testutil
1818

1919
import (
20+
"io"
2021
"os"
2122
"strconv"
2223
"strings"
@@ -110,3 +111,8 @@ func HyperVContainer(inspect dockercompat.Container) (bool, error) {
110111

111112
return hypervContainer, nil
112113
}
114+
115+
func NewDelayOnceReader(wrapped io.Reader) io.Reader {
116+
// not implemented
117+
return nil
118+
}

0 commit comments

Comments
 (0)
Please sign in to comment.