Skip to content

Commit 7ed75f2

Browse files
committed
backend-2
1 parent b1c2bf9 commit 7ed75f2

File tree

7 files changed

+141
-21
lines changed

7 files changed

+141
-21
lines changed

agent/agentcontainers/api.go

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,17 @@ type API struct {
7272
configFileModifiedTimes map[string]time.Time // By config file path.
7373
recreateSuccessTimes map[string]time.Time // By workspace folder.
7474
recreateErrorTimes map[string]time.Time // By workspace folder.
75-
injectedSubAgentProcs map[string]subAgentProcess // By container ID.
75+
injectedSubAgentProcs map[string]subAgentProcess // By workspace folder.
7676
asyncWg sync.WaitGroup
7777

7878
devcontainerLogSourceIDs map[string]uuid.UUID // By workspace folder.
7979
}
8080

8181
type subAgentProcess struct {
82-
agent SubAgent
83-
ctx context.Context
84-
stop context.CancelFunc
82+
agent SubAgent
83+
containerID string
84+
ctx context.Context
85+
stop context.CancelFunc
8586
}
8687

8788
// Option is a functional option for API.
@@ -586,7 +587,11 @@ func (api *API) processUpdatedContainersLocked(ctx context.Context, updated code
586587
dc.Dirty = true
587588
}
588589

589-
if _, injected := api.injectedSubAgentProcs[dc.Container.ID]; !injected && dc.Status == codersdk.WorkspaceAgentDevcontainerStatusRunning {
590+
proc, injected := api.injectedSubAgentProcs[dc.WorkspaceFolder]
591+
if injected && proc.containerID != dc.Container.ID {
592+
injected = false // The container ID changed, we need to re-inject.
593+
}
594+
if !injected && dc.Status == codersdk.WorkspaceAgentDevcontainerStatusRunning {
590595
err := api.injectSubAgentIntoContainerLocked(ctx, dc)
591596
if err != nil {
592597
logger.Error(ctx, "inject subagent into container failed", slog.Error(err))
@@ -660,10 +665,22 @@ func (api *API) getContainers() (codersdk.WorkspaceAgentListContainersResponse,
660665
if len(api.knownDevcontainers) > 0 {
661666
devcontainers = make([]codersdk.WorkspaceAgentDevcontainer, 0, len(api.knownDevcontainers))
662667
for _, dc := range api.knownDevcontainers {
668+
// Include the agent if it's been created (we're iterating over
669+
// copies, so mutating is fine).
670+
if dc.Container != nil {
671+
if proc := api.injectedSubAgentProcs[dc.WorkspaceFolder]; proc.agent.ID != uuid.Nil && proc.containerID == dc.Container.ID {
672+
dc.Agent = &codersdk.WorkspaceAgentDevcontainerAgent{
673+
ID: proc.agent.ID,
674+
Name: proc.agent.Name,
675+
Directory: proc.agent.Directory,
676+
}
677+
}
678+
}
679+
663680
devcontainers = append(devcontainers, dc)
664681
}
665682
slices.SortFunc(devcontainers, func(a, b codersdk.WorkspaceAgentDevcontainer) int {
666-
return strings.Compare(a.ID.String(), b.ID.String())
683+
return strings.Compare(a.Name, b.Name)
667684
})
668685
}
669686

@@ -975,9 +992,25 @@ func (api *API) injectSubAgentIntoContainerLocked(ctx context.Context, dc coders
975992
return xerrors.New("container is nil, cannot inject subagent")
976993
}
977994

995+
logger := api.logger.With(
996+
slog.F("devcontainer_id", dc.ID),
997+
slog.F("devcontainer_name", dc.Name),
998+
slog.F("workspace_folder", dc.WorkspaceFolder),
999+
slog.F("config_path", dc.ConfigPath),
1000+
slog.F("container_id", container.ID),
1001+
slog.F("container_name", container.FriendlyName),
1002+
)
1003+
9781004
// Skip if subagent already exists for this container.
979-
if _, injected := api.injectedSubAgentProcs[container.ID]; injected || api.closed {
980-
return nil
1005+
if proc, injected := api.injectedSubAgentProcs[dc.WorkspaceFolder]; injected || api.closed {
1006+
if proc.containerID == container.ID {
1007+
return nil
1008+
}
1009+
1010+
// If the subagent is already injected but the container ID has
1011+
// changed, we need to inject it into the new container.
1012+
logger.Debug(ctx, "injecting subagent into new container")
1013+
proc.stop()
9811014
}
9821015

9831016
// Mark subagent as being injected immediately with a placeholder.
@@ -1010,13 +1043,6 @@ func (api *API) injectSubAgentIntoContainerLocked(ctx context.Context, dc coders
10101043
api.mu.Unlock()
10111044
defer api.mu.Lock() // Re-lock.
10121045

1013-
logger := api.logger.With(
1014-
slog.F("devcontainer_id", dc.ID),
1015-
slog.F("devcontainer_name", dc.Name),
1016-
slog.F("workspace_folder", dc.WorkspaceFolder),
1017-
slog.F("config_path", dc.ConfigPath),
1018-
)
1019-
10201046
arch, err := api.ccli.DetectArchitecture(ctx, container.ID)
10211047
if err != nil {
10221048
return xerrors.Errorf("detect architecture: %w", err)
@@ -1145,7 +1171,9 @@ func (api *API) runSubAgentInContainer(ctx context.Context, dc codersdk.Workspac
11451171
}
11461172

11471173
api.mu.Lock()
1148-
delete(api.injectedSubAgentProcs, container.ID)
1174+
if api.injectedSubAgentProcs[dc.WorkspaceFolder].containerID == container.ID {
1175+
delete(api.injectedSubAgentProcs, dc.WorkspaceFolder)
1176+
}
11491177
api.mu.Unlock()
11501178

11511179
logger.Debug(ctx, "agent process cleanup complete")
@@ -1160,10 +1188,11 @@ func (api *API) runSubAgentInContainer(ctx context.Context, dc codersdk.Workspac
11601188
return
11611189
}
11621190
// Update the placeholder with a valid subagent, context and stop.
1163-
api.injectedSubAgentProcs[container.ID] = subAgentProcess{
1164-
agent: agent,
1165-
ctx: agentCtx,
1166-
stop: agentStop,
1191+
api.injectedSubAgentProcs[dc.WorkspaceFolder] = subAgentProcess{
1192+
agent: agent,
1193+
containerID: container.ID,
1194+
ctx: agentCtx,
1195+
stop: agentStop,
11671196
}
11681197
api.mu.Unlock()
11691198

@@ -1195,7 +1224,11 @@ func (api *API) Close() error {
11951224
api.closed = true
11961225

11971226
for _, proc := range api.injectedSubAgentProcs {
1198-
api.logger.Debug(api.ctx, "canceling subagent process", slog.F("agent_name", proc.agent.Name), slog.F("agent_id", proc.agent.ID))
1227+
api.logger.Debug(api.ctx, "canceling subagent process",
1228+
slog.F("agent_name", proc.agent.Name),
1229+
slog.F("agent_id", proc.agent.ID),
1230+
slog.F("container_id", proc.containerID),
1231+
)
11991232
proc.stop()
12001233
}
12011234

coderd/apidoc/docs.go

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

coderd/apidoc/swagger.json

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

codersdk/workspaceagents.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,15 @@ type WorkspaceAgentDevcontainer struct {
422422
Status WorkspaceAgentDevcontainerStatus `json:"status"`
423423
Dirty bool `json:"dirty"`
424424
Container *WorkspaceAgentContainer `json:"container,omitempty"`
425+
Agent *WorkspaceAgentDevcontainerAgent `json:"agent,omitempty"`
426+
}
427+
428+
// WorkspaceAgentDevcontainerAgent represents the sub agent for a
429+
// devcontainer.
430+
type WorkspaceAgentDevcontainerAgent struct {
431+
ID uuid.UUID `json:"id" format:"uuid"`
432+
Name string `json:"name"`
433+
Directory string `json:"directory"`
425434
}
426435

427436
// WorkspaceAgentContainer describes a devcontainer of some sort

docs/reference/api/agents.md

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

docs/reference/api/schemas.md

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

site/src/api/typesGenerated.ts

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

0 commit comments

Comments
 (0)