Skip to content

Commit 9afa5ea

Browse files
committed
add WithContainerLabelIncludeFilter
1 parent 591a9bf commit 9afa5ea

File tree

1 file changed

+67
-39
lines changed

1 file changed

+67
-39
lines changed

agent/agentcontainers/api.go

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,23 @@ const (
4242
// API is responsible for container-related operations in the agent.
4343
// It provides methods to list and manage containers.
4444
type API struct {
45-
ctx context.Context
46-
cancel context.CancelFunc
47-
watcherDone chan struct{}
48-
updaterDone chan struct{}
49-
initialUpdateDone chan struct{} // Closed after first update in updaterLoop.
50-
updateTrigger chan chan error // Channel to trigger manual refresh.
51-
updateInterval time.Duration // Interval for periodic container updates.
52-
logger slog.Logger
53-
watcher watcher.Watcher
54-
execer agentexec.Execer
55-
ccli ContainerCLI
56-
dccli DevcontainerCLI
57-
clock quartz.Clock
58-
scriptLogger func(logSourceID uuid.UUID) ScriptLogger
59-
subAgentClient SubAgentClient
60-
subAgentURL string
45+
ctx context.Context
46+
cancel context.CancelFunc
47+
watcherDone chan struct{}
48+
updaterDone chan struct{}
49+
initialUpdateDone chan struct{} // Closed after first update in updaterLoop.
50+
updateTrigger chan chan error // Channel to trigger manual refresh.
51+
updateInterval time.Duration // Interval for periodic container updates.
52+
logger slog.Logger
53+
watcher watcher.Watcher
54+
execer agentexec.Execer
55+
ccli ContainerCLI
56+
containerLabelIncludeFilter map[string]string // Labels to filter containers by.
57+
dccli DevcontainerCLI
58+
clock quartz.Clock
59+
scriptLogger func(logSourceID uuid.UUID) ScriptLogger
60+
subAgentClient SubAgentClient
61+
subAgentURL string
6162

6263
mu sync.RWMutex
6364
closed bool
@@ -106,6 +107,16 @@ func WithContainerCLI(ccli ContainerCLI) Option {
106107
}
107108
}
108109

110+
// WithContainerLabelIncludeFilter sets a label filter for containers.
111+
// This option can be given multiple times to filter by multiple labels.
112+
// The behavior is such that only containers matching one or more of the
113+
// provided labels will be included.
114+
func WithContainerLabelIncludeFilter(label, value string) Option {
115+
return func(api *API) {
116+
api.containerLabelIncludeFilter[label] = value
117+
}
118+
}
119+
109120
// WithDevcontainerCLI sets the DevcontainerCLI implementation to use.
110121
// This can be used in tests to modify @devcontainer/cli behavior.
111122
func WithDevcontainerCLI(dccli DevcontainerCLI) Option {
@@ -198,24 +209,25 @@ func WithScriptLogger(scriptLogger func(logSourceID uuid.UUID) ScriptLogger) Opt
198209
func NewAPI(logger slog.Logger, options ...Option) *API {
199210
ctx, cancel := context.WithCancel(context.Background())
200211
api := &API{
201-
ctx: ctx,
202-
cancel: cancel,
203-
watcherDone: make(chan struct{}),
204-
updaterDone: make(chan struct{}),
205-
initialUpdateDone: make(chan struct{}),
206-
updateTrigger: make(chan chan error),
207-
updateInterval: defaultUpdateInterval,
208-
logger: logger,
209-
clock: quartz.NewReal(),
210-
execer: agentexec.DefaultExecer,
211-
subAgentClient: noopSubAgentClient{},
212-
devcontainerNames: make(map[string]bool),
213-
knownDevcontainers: make(map[string]codersdk.WorkspaceAgentDevcontainer),
214-
configFileModifiedTimes: make(map[string]time.Time),
215-
recreateSuccessTimes: make(map[string]time.Time),
216-
recreateErrorTimes: make(map[string]time.Time),
217-
scriptLogger: func(uuid.UUID) ScriptLogger { return noopScriptLogger{} },
218-
injectedSubAgentProcs: make(map[string]subAgentProcess),
212+
ctx: ctx,
213+
cancel: cancel,
214+
watcherDone: make(chan struct{}),
215+
updaterDone: make(chan struct{}),
216+
initialUpdateDone: make(chan struct{}),
217+
updateTrigger: make(chan chan error),
218+
updateInterval: defaultUpdateInterval,
219+
logger: logger,
220+
clock: quartz.NewReal(),
221+
execer: agentexec.DefaultExecer,
222+
subAgentClient: noopSubAgentClient{},
223+
containerLabelIncludeFilter: make(map[string]string),
224+
devcontainerNames: make(map[string]bool),
225+
knownDevcontainers: make(map[string]codersdk.WorkspaceAgentDevcontainer),
226+
configFileModifiedTimes: make(map[string]time.Time),
227+
recreateSuccessTimes: make(map[string]time.Time),
228+
recreateErrorTimes: make(map[string]time.Time),
229+
scriptLogger: func(uuid.UUID) ScriptLogger { return noopScriptLogger{} },
230+
injectedSubAgentProcs: make(map[string]subAgentProcess),
219231
}
220232
// The ctx and logger must be set before applying options to avoid
221233
// nil pointer dereference.
@@ -266,7 +278,7 @@ func (api *API) watcherLoop() {
266278
continue
267279
}
268280

269-
now := api.clock.Now("watcherLoop")
281+
now := api.clock.Now("agentcontainers", "watcherLoop")
270282
switch {
271283
case event.Has(fsnotify.Create | fsnotify.Write):
272284
api.logger.Debug(api.ctx, "devcontainer config file changed", slog.F("file", event.Name))
@@ -333,9 +345,9 @@ func (api *API) updaterLoop() {
333345
}
334346

335347
return nil // Always nil to keep the ticker going.
336-
}, "updaterLoop")
348+
}, "agentcontainers", "updaterLoop")
337349
defer func() {
338-
if err := ticker.Wait("updaterLoop"); err != nil && !errors.Is(err, context.Canceled) {
350+
if err := ticker.Wait("agentcontainers", "updaterLoop"); err != nil && !errors.Is(err, context.Canceled) {
339351
api.logger.Error(api.ctx, "updater loop ticker failed", slog.Error(err))
340352
}
341353
}()
@@ -481,6 +493,22 @@ func (api *API) processUpdatedContainersLocked(ctx context.Context, updated code
481493
slog.F("config_file", configFile),
482494
)
483495

496+
if len(api.containerLabelIncludeFilter) > 0 {
497+
var ok bool
498+
for label, value := range api.containerLabelIncludeFilter {
499+
if v, found := container.Labels[label]; found && v == value {
500+
ok = true
501+
}
502+
}
503+
// Verbose debug logging is fine here since typically filters
504+
// are only used in development or testing environments.
505+
if !ok {
506+
logger.Debug(ctx, "container does not match include filter, ignoring dev container", slog.F("container_labels", container.Labels), slog.F("include_filter", api.containerLabelIncludeFilter))
507+
continue
508+
}
509+
logger.Debug(ctx, "container matches include filter, processing dev container", slog.F("container_labels", container.Labels), slog.F("include_filter", api.containerLabelIncludeFilter))
510+
}
511+
484512
if dc, ok := api.knownDevcontainers[workspaceFolder]; ok {
485513
// If no config path is set, this devcontainer was defined
486514
// in Terraform without the optional config file. Assume the
@@ -781,7 +809,7 @@ func (api *API) recreateDevcontainer(dc codersdk.WorkspaceAgentDevcontainer, con
781809
dc.Container.DevcontainerStatus = dc.Status
782810
}
783811
api.knownDevcontainers[dc.WorkspaceFolder] = dc
784-
api.recreateErrorTimes[dc.WorkspaceFolder] = api.clock.Now("recreate", "errorTimes")
812+
api.recreateErrorTimes[dc.WorkspaceFolder] = api.clock.Now("agentcontainers", "recreate", "errorTimes")
785813
api.mu.Unlock()
786814
return
787815
}
@@ -803,7 +831,7 @@ func (api *API) recreateDevcontainer(dc codersdk.WorkspaceAgentDevcontainer, con
803831
dc.Container.DevcontainerStatus = dc.Status
804832
}
805833
dc.Dirty = false
806-
api.recreateSuccessTimes[dc.WorkspaceFolder] = api.clock.Now("recreate", "successTimes")
834+
api.recreateSuccessTimes[dc.WorkspaceFolder] = api.clock.Now("agentcontainers", "recreate", "successTimes")
807835
api.knownDevcontainers[dc.WorkspaceFolder] = dc
808836
api.mu.Unlock()
809837

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