Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1dd3133

Browse files
committed
move to agentcontainers package
1 parent 7d5f6c7 commit 1dd3133

8 files changed

+118
-87
lines changed

agent/agent.go

+7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"tailscale.com/util/clientmetric"
3434

3535
"cdr.dev/slog"
36+
"github.com/coder/coder/v2/agent/agentcontainers"
3637
"github.com/coder/coder/v2/agent/agentexec"
3738
"github.com/coder/coder/v2/agent/agentscripts"
3839
"github.com/coder/coder/v2/agent/agentssh"
@@ -82,6 +83,7 @@ type Options struct {
8283
ServiceBannerRefreshInterval time.Duration
8384
BlockFileTransfer bool
8485
Execer agentexec.Execer
86+
ContainerLister agentcontainers.Lister
8587
}
8688

8789
type Client interface {
@@ -144,6 +146,9 @@ func New(options Options) Agent {
144146
if options.Execer == nil {
145147
options.Execer = agentexec.DefaultExecer
146148
}
149+
if options.ContainerLister == nil {
150+
options.ContainerLister = &agentcontainers.DockerCLILister{}
151+
}
147152

148153
hardCtx, hardCancel := context.WithCancel(context.Background())
149154
gracefulCtx, gracefulCancel := context.WithCancel(hardCtx)
@@ -178,6 +183,7 @@ func New(options Options) Agent {
178183
prometheusRegistry: prometheusRegistry,
179184
metrics: newAgentMetrics(prometheusRegistry),
180185
execer: options.Execer,
186+
lister: options.ContainerLister,
181187
}
182188
// Initially, we have a closed channel, reflecting the fact that we are not initially connected.
183189
// Each time we connect we replace the channel (while holding the closeMutex) with a new one
@@ -247,6 +253,7 @@ type agent struct {
247253
// labeled in Coder with the agent + workspace.
248254
metrics *agentMetrics
249255
execer agentexec.Execer
256+
lister agentcontainers.Lister
250257
}
251258

252259
func (a *agent) TailnetConn() *tailnet.Conn {

agent/containers.go renamed to agent/agentcontainers/containers.go

+29-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
package agent
1+
package agentcontainers
22

3-
//go:generate mockgen -destination ./containers_mock.go -package agent . ContainerLister
3+
//go:generate mockgen -destination ./containers_mock.go -package agentcontainers . Lister
44

55
import (
66
"context"
@@ -25,7 +25,7 @@ const (
2525

2626
type devcontainersHandler struct {
2727
cacheDuration time.Duration
28-
cl ContainerLister
28+
cl Lister
2929
clock quartz.Clock
3030

3131
initLockOnce sync.Once // ensures we don't get a race when initializing lockCh
@@ -36,7 +36,27 @@ type devcontainersHandler struct {
3636
mtime time.Time
3737
}
3838

39-
func (ch *devcontainersHandler) handler(rw http.ResponseWriter, r *http.Request) {
39+
// WithLister sets the agentcontainers.Lister implementation to use.
40+
// The default implementation uses the Docker CLI to list containers.
41+
func WithLister(cl Lister) Option {
42+
return func(ch *devcontainersHandler) {
43+
ch.cl = cl
44+
}
45+
}
46+
47+
// Option is a functional option for devcontainersHandler.
48+
type Option func(*devcontainersHandler)
49+
50+
// New returns a new devcontainersHandler with the given options applied.
51+
func New(options ...Option) http.Handler {
52+
ch := &devcontainersHandler{}
53+
for _, opt := range options {
54+
opt(ch)
55+
}
56+
return ch
57+
}
58+
59+
func (ch *devcontainersHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
4060
ct, err := ch.getContainers(r.Context())
4161
if err != nil {
4262
if errors.Is(err, context.Canceled) {
@@ -77,9 +97,7 @@ func (ch *devcontainersHandler) getContainers(ctx context.Context) (codersdk.Wor
7797
ch.cacheDuration = defaultGetContainersCacheDuration
7898
}
7999
if ch.cl == nil {
80-
// TODO(cian): we may need some way to select the desired
81-
// implementation, but for now there is only one.
82-
ch.cl = &dockerCLIContainerLister{}
100+
ch.cl = &DockerCLILister{}
83101
}
84102
if ch.containers == nil {
85103
ch.containers = &codersdk.WorkspaceAgentListContainersResponse{}
@@ -93,6 +111,7 @@ func (ch *devcontainersHandler) getContainers(ctx context.Context) (codersdk.Wor
93111
// Return a copy of the cached data to avoid accidental modification by the caller.
94112
cpy := codersdk.WorkspaceAgentListContainersResponse{
95113
Containers: slices.Clone(ch.containers.Containers),
114+
Warnings: slices.Clone(ch.containers.Warnings),
96115
}
97116
return cpy, nil
98117
}
@@ -110,13 +129,14 @@ func (ch *devcontainersHandler) getContainers(ctx context.Context) (codersdk.Wor
110129
// caller.
111130
cpy := codersdk.WorkspaceAgentListContainersResponse{
112131
Containers: slices.Clone(ch.containers.Containers),
132+
Warnings: slices.Clone(ch.containers.Warnings),
113133
}
114134
return cpy, nil
115135
}
116136

117-
// ContainerLister is an interface for listing containers visible to the
137+
// Lister is an interface for listing containers visible to the
118138
// workspace agent.
119-
type ContainerLister interface {
139+
type Lister interface {
120140
// List returns a list of containers visible to the workspace agent.
121141
// This should include running and stopped containers.
122142
List(ctx context.Context) (codersdk.WorkspaceAgentListContainersResponse, error)

agent/containers_dockercli.go renamed to agent/agentcontainers/containers_dockercli.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package agent
1+
package agentcontainers
22

33
import (
44
"bufio"
@@ -18,12 +18,12 @@ import (
1818
"golang.org/x/xerrors"
1919
)
2020

21-
// dockerCLIContainerLister is a ContainerLister that lists containers using the docker CLI
22-
type dockerCLIContainerLister struct{}
21+
// DockerCLILister is a ContainerLister that lists containers using the docker CLI
22+
type DockerCLILister struct{}
2323

24-
var _ ContainerLister = &dockerCLIContainerLister{}
24+
var _ Lister = &DockerCLILister{}
2525

26-
func (*dockerCLIContainerLister) List(ctx context.Context) (codersdk.WorkspaceAgentListContainersResponse, error) {
26+
func (*DockerCLILister) List(ctx context.Context) (codersdk.WorkspaceAgentListContainersResponse, error) {
2727
var stdoutBuf, stderrBuf bytes.Buffer
2828
// List all container IDs, one per line, with no truncation
2929
cmd := exec.CommandContext(ctx, "docker", "ps", "--all", "--quiet", "--no-trunc")

agent/containers_internal_test.go renamed to agent/agentcontainers/containers_internal_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package agent
1+
package agentcontainers
22

33
import (
44
"os/exec"
@@ -51,7 +51,7 @@ func TestDockerCLIContainerLister(t *testing.T) {
5151
assert.NoError(t, pool.Purge(ct), "Could not purge resource %q", ct.Container.Name)
5252
})
5353

54-
dcl := dockerCLIContainerLister{}
54+
dcl := DockerCLILister{}
5555
ctx := testutil.Context(t, testutil.WaitShort)
5656
actual, err := dcl.List(ctx)
5757
require.NoError(t, err, "Could not list containers")
@@ -100,15 +100,15 @@ func TestContainersHandler(t *testing.T) {
100100
// relative age of the cached data
101101
cacheAge time.Duration
102102
// function to set up expectations for the mock
103-
setupMock func(*MockContainerLister)
103+
setupMock func(*MockLister)
104104
// expected result
105105
expected codersdk.WorkspaceAgentListContainersResponse
106106
// expected error
107107
expectedErr string
108108
}{
109109
{
110110
name: "no cache",
111-
setupMock: func(mcl *MockContainerLister) {
111+
setupMock: func(mcl *MockLister) {
112112
mcl.EXPECT().List(gomock.Any()).Return(makeResponse(fakeCt), nil).AnyTimes()
113113
},
114114
expected: makeResponse(fakeCt),
@@ -118,7 +118,7 @@ func TestContainersHandler(t *testing.T) {
118118
cacheData: makeResponse(),
119119
cacheAge: 2 * time.Second,
120120
cacheDur: time.Second,
121-
setupMock: func(mcl *MockContainerLister) {
121+
setupMock: func(mcl *MockLister) {
122122
mcl.EXPECT().List(gomock.Any()).Return(makeResponse(fakeCt), nil).AnyTimes()
123123
},
124124
expected: makeResponse(fakeCt),
@@ -132,7 +132,7 @@ func TestContainersHandler(t *testing.T) {
132132
},
133133
{
134134
name: "lister error",
135-
setupMock: func(mcl *MockContainerLister) {
135+
setupMock: func(mcl *MockLister) {
136136
mcl.EXPECT().List(gomock.Any()).Return(makeResponse(), assert.AnError).AnyTimes()
137137
},
138138
expectedErr: assert.AnError.Error(),
@@ -142,7 +142,7 @@ func TestContainersHandler(t *testing.T) {
142142
cacheAge: 2 * time.Second,
143143
cacheData: makeResponse(fakeCt),
144144
cacheDur: time.Second,
145-
setupMock: func(mcl *MockContainerLister) {
145+
setupMock: func(mcl *MockLister) {
146146
mcl.EXPECT().List(gomock.Any()).Return(makeResponse(fakeCt2), nil).AnyTimes()
147147
},
148148
expected: makeResponse(fakeCt2),
@@ -155,7 +155,7 @@ func TestContainersHandler(t *testing.T) {
155155
ctx = testutil.Context(t, testutil.WaitShort)
156156
clk = quartz.NewMock(t)
157157
ctrl = gomock.NewController(t)
158-
mockLister = NewMockContainerLister(ctrl)
158+
mockLister = NewMockLister(ctrl)
159159
now = time.Now().UTC()
160160
ch = devcontainersHandler{
161161
cacheDuration: tc.cacheDur,

agent/agentcontainers/containers_mock.go

+57
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/api.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/go-chi/chi/v5"
99

10+
"github.com/coder/coder/v2/agent/agentcontainers"
1011
"github.com/coder/coder/v2/coderd/httpapi"
1112
"github.com/coder/coder/v2/codersdk"
1213
)
@@ -35,11 +36,9 @@ func (a *agent) apiHandler() http.Handler {
3536
ignorePorts: cpy,
3637
cacheDuration: cacheDuration,
3738
}
38-
ch := &devcontainersHandler{
39-
cacheDuration: defaultGetContainersCacheDuration,
40-
}
39+
ch := agentcontainers.New(agentcontainers.WithLister(a.lister))
4140
promHandler := PrometheusMetricsHandler(a.prometheusRegistry, a.logger)
42-
r.Get("/api/v0/containers", ch.handler)
41+
r.Get("/api/v0/containers", ch.ServeHTTP)
4342
r.Get("/api/v0/listening-ports", lp.handler)
4443
r.Get("/api/v0/netcheck", a.HandleNetcheck)
4544
r.Get("/debug/logs", a.HandleHTTPDebugLogs)

agent/containers_mock.go

-57
This file was deleted.

coderd/workspaceagents.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -765,11 +765,16 @@ func (api *API) workspaceAgentListContainers(rw http.ResponseWriter, r *http.Req
765765
}
766766

767767
// Filter in-place by labels
768-
filtered := slices.DeleteFunc(cts.Containers, func(ct codersdk.WorkspaceAgentDevcontainer) bool {
769-
return !maputil.Subset(labels, ct.Labels)
770-
})
768+
for idx, ct := range cts.Containers {
769+
if !maputil.Subset(labels, ct.Labels) {
770+
cts.Containers = append(cts.Containers[:idx], cts.Containers[idx+1:]...)
771+
}
772+
}
773+
// filtered := slices.DeleteFunc(cts.Containers, func(ct codersdk.WorkspaceAgentDevcontainer) bool {
774+
// return !maputil.Subset(labels, ct.Labels)
775+
// })
771776

772-
httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspaceAgentListContainersResponse{Containers: filtered})
777+
httpapi.Write(ctx, rw, http.StatusOK, cts)
773778
}
774779

775780
// @Summary Get connection info for workspace agent

0 commit comments

Comments
 (0)