Browse code

pkg/stack: move to daemon/internal

This package is used by the daemon to produce a stack-dump, It has no
external consumers, so we can move it to daemon/internal.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2025/07/29 01:38:51
Showing 8 changed files
... ...
@@ -52,8 +52,8 @@ import (
52 52
 	"github.com/containerd/log"
53 53
 	"github.com/docker/docker/daemon/cluster/controllers/plugin"
54 54
 	executorpkg "github.com/docker/docker/daemon/cluster/executor"
55
+	"github.com/docker/docker/daemon/internal/stack"
55 56
 	lncluster "github.com/docker/docker/daemon/libnetwork/cluster"
56
-	"github.com/docker/docker/pkg/stack"
57 57
 	"github.com/moby/moby/api/types/network"
58 58
 	types "github.com/moby/moby/api/types/swarm"
59 59
 	swarmapi "github.com/moby/swarmkit/v2/api"
... ...
@@ -9,10 +9,10 @@ import (
9 9
 
10 10
 	"github.com/containerd/log"
11 11
 	"github.com/docker/docker/daemon/cluster/convert"
12
+	"github.com/docker/docker/daemon/internal/stack"
12 13
 	"github.com/docker/docker/daemon/pkg/opts"
13 14
 	"github.com/docker/docker/daemon/server/backend"
14 15
 	"github.com/docker/docker/errdefs"
15
-	"github.com/docker/docker/pkg/stack"
16 16
 	"github.com/moby/moby/api/types/container"
17 17
 	"github.com/moby/moby/api/types/filters"
18 18
 	types "github.com/moby/moby/api/types/swarm"
... ...
@@ -8,7 +8,7 @@ import (
8 8
 	"os/signal"
9 9
 
10 10
 	"github.com/containerd/log"
11
-	"github.com/docker/docker/pkg/stack"
11
+	"github.com/docker/docker/daemon/internal/stack"
12 12
 	"golang.org/x/sys/unix"
13 13
 )
14 14
 
... ...
@@ -7,7 +7,7 @@ import (
7 7
 	"unsafe"
8 8
 
9 9
 	"github.com/containerd/log"
10
-	"github.com/docker/docker/pkg/stack"
10
+	"github.com/docker/docker/daemon/internal/stack"
11 11
 	"golang.org/x/sys/windows"
12 12
 )
13 13
 
14 14
new file mode 100644
... ...
@@ -0,0 +1,59 @@
0
+package stack
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+	"path/filepath"
6
+	"runtime"
7
+	"strings"
8
+	"time"
9
+
10
+	"github.com/pkg/errors"
11
+)
12
+
13
+const stacksLogNameTemplate = "goroutine-stacks-%s.log"
14
+
15
+// Dump outputs the runtime stack to os.StdErr.
16
+func Dump() {
17
+	_ = dump(os.Stderr)
18
+}
19
+
20
+// DumpToFile appends the runtime stack into a file named "goroutine-stacks-<timestamp>.log"
21
+// in dir and returns the full path to that file. If no directory name is
22
+// provided, it outputs to os.Stderr.
23
+func DumpToFile(dir string) (string, error) {
24
+	var f *os.File
25
+	if dir != "" {
26
+		path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.ReplaceAll(time.Now().Format(time.RFC3339), ":", "")))
27
+		var err error
28
+		f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o666)
29
+		if err != nil {
30
+			return "", errors.Wrap(err, "failed to open file to write the goroutine stacks")
31
+		}
32
+		defer func() {
33
+			_ = f.Sync()
34
+			_ = f.Close()
35
+		}()
36
+	} else {
37
+		f = os.Stderr
38
+	}
39
+	return f.Name(), dump(f)
40
+}
41
+
42
+func dump(f *os.File) error {
43
+	var (
44
+		buf       []byte
45
+		stackSize int
46
+	)
47
+	bufferLen := 16384
48
+	for stackSize == len(buf) {
49
+		buf = make([]byte, bufferLen)
50
+		stackSize = runtime.Stack(buf, true)
51
+		bufferLen *= 2
52
+	}
53
+	buf = buf[:stackSize]
54
+	if _, err := f.Write(buf); err != nil {
55
+		return errors.Wrap(err, "failed to write goroutine stacks")
56
+	}
57
+	return nil
58
+}
0 59
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+package stack
1
+
2
+import (
3
+	"os"
4
+	"testing"
5
+
6
+	"gotest.tools/v3/assert"
7
+	is "gotest.tools/v3/assert/cmp"
8
+)
9
+
10
+func TestDump(t *testing.T) {
11
+	Dump()
12
+}
13
+
14
+func TestDumpToFile(t *testing.T) {
15
+	tmpDir := t.TempDir()
16
+	dumpPath, err := DumpToFile(tmpDir)
17
+	assert.Check(t, err)
18
+	readFile, _ := os.ReadFile(dumpPath)
19
+	fileData := string(readFile)
20
+	assert.Check(t, is.Contains(fileData, "goroutine"))
21
+}
22
+
23
+func TestDumpToFileWithEmptyInput(t *testing.T) {
24
+	path, err := DumpToFile("")
25
+	assert.Check(t, err)
26
+	assert.Check(t, is.Equal(os.Stderr.Name(), path))
27
+}
0 28
deleted file mode 100644
... ...
@@ -1,59 +0,0 @@
1
-package stack
2
-
3
-import (
4
-	"fmt"
5
-	"os"
6
-	"path/filepath"
7
-	"runtime"
8
-	"strings"
9
-	"time"
10
-
11
-	"github.com/pkg/errors"
12
-)
13
-
14
-const stacksLogNameTemplate = "goroutine-stacks-%s.log"
15
-
16
-// Dump outputs the runtime stack to os.StdErr.
17
-func Dump() {
18
-	_ = dump(os.Stderr)
19
-}
20
-
21
-// DumpToFile appends the runtime stack into a file named "goroutine-stacks-<timestamp>.log"
22
-// in dir and returns the full path to that file. If no directory name is
23
-// provided, it outputs to os.Stderr.
24
-func DumpToFile(dir string) (string, error) {
25
-	var f *os.File
26
-	if dir != "" {
27
-		path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.ReplaceAll(time.Now().Format(time.RFC3339), ":", "")))
28
-		var err error
29
-		f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o666)
30
-		if err != nil {
31
-			return "", errors.Wrap(err, "failed to open file to write the goroutine stacks")
32
-		}
33
-		defer func() {
34
-			_ = f.Sync()
35
-			_ = f.Close()
36
-		}()
37
-	} else {
38
-		f = os.Stderr
39
-	}
40
-	return f.Name(), dump(f)
41
-}
42
-
43
-func dump(f *os.File) error {
44
-	var (
45
-		buf       []byte
46
-		stackSize int
47
-	)
48
-	bufferLen := 16384
49
-	for stackSize == len(buf) {
50
-		buf = make([]byte, bufferLen)
51
-		stackSize = runtime.Stack(buf, true)
52
-		bufferLen *= 2
53
-	}
54
-	buf = buf[:stackSize]
55
-	if _, err := f.Write(buf); err != nil {
56
-		return errors.Wrap(err, "failed to write goroutine stacks")
57
-	}
58
-	return nil
59
-}
60 1
deleted file mode 100644
... ...
@@ -1,28 +0,0 @@
1
-package stack
2
-
3
-import (
4
-	"os"
5
-	"testing"
6
-
7
-	"gotest.tools/v3/assert"
8
-	is "gotest.tools/v3/assert/cmp"
9
-)
10
-
11
-func TestDump(t *testing.T) {
12
-	Dump()
13
-}
14
-
15
-func TestDumpToFile(t *testing.T) {
16
-	tmpDir := t.TempDir()
17
-	dumpPath, err := DumpToFile(tmpDir)
18
-	assert.Check(t, err)
19
-	readFile, _ := os.ReadFile(dumpPath)
20
-	fileData := string(readFile)
21
-	assert.Check(t, is.Contains(fileData, "goroutine"))
22
-}
23
-
24
-func TestDumpToFileWithEmptyInput(t *testing.T) {
25
-	path, err := DumpToFile("")
26
-	assert.Check(t, err)
27
-	assert.Check(t, is.Equal(os.Stderr.Name(), path))
28
-}