Skip to content

Commit 1dd3133

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

File tree

8 files changed

+118
-87
lines changed

8 files changed

+118
-87
lines changed

agent/agent.go

Lines changed: 7 additions & 0 deletions
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

Lines changed: 29 additions & 9 deletions
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

Lines changed: 5 additions & 5 deletions
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

Lines changed: 8 additions & 8 deletions
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

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/api.go

Lines changed: 3 additions & 4 deletions
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

Lines changed: 0 additions & 57 deletions
This file was deleted.

coderd/workspaceagents.go

Lines changed: 9 additions & 4 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy