@@ -671,9 +671,9 @@ func (api *API) getContainers() (codersdk.WorkspaceAgentListContainersResponse,
671671 if len (api .knownDevcontainers ) > 0 {
672672 devcontainers = make ([]codersdk.WorkspaceAgentDevcontainer , 0 , len (api .knownDevcontainers ))
673673 for _ , dc := range api .knownDevcontainers {
674- // Include the agent if it's been created (we're iterating over
674+ // Include the agent if it's running (we're iterating over
675675 // copies, so mutating is fine).
676- if proc := api .injectedSubAgentProcs [dc .WorkspaceFolder ]; proc .agent .ID != uuid .Nil && dc . Container != nil && proc . containerID == dc . Container . ID {
676+ if proc := api .injectedSubAgentProcs [dc .WorkspaceFolder ]; proc .agent .ID != uuid .Nil {
677677 dc .Agent = & codersdk.WorkspaceAgentDevcontainerAgent {
678678 ID : proc .agent .ID ,
679679 Name : proc .agent .Name ,
@@ -977,7 +977,7 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
977977 )
978978
979979 // Check if subagent already exists for this devcontainer.
980- recreateSubAgent := false
980+ maybeRecreateSubAgent := false
981981 proc , injected := api .injectedSubAgentProcs [dc .WorkspaceFolder ]
982982 if injected {
983983 if proc .containerID == container .ID && proc .ctx .Err () == nil {
@@ -992,12 +992,15 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
992992 logger .Debug (ctx , "container ID changed, injecting subagent into new container" ,
993993 slog .F ("old_container_id" , proc .containerID ),
994994 )
995- recreateSubAgent = true
995+ maybeRecreateSubAgent = proc . agent . ID != uuid . Nil
996996 }
997997
998998 // Container ID changed or the subagent process is not running,
999999 // stop the existing subagent context to replace it.
10001000 proc .stop ()
1001+ } else {
1002+ // Set SubAgent defaults.
1003+ proc .agent .OperatingSystem = "linux" // Assuming Linux for devcontainers.
10011004 }
10021005
10031006 // Prepare the subAgentProcess to be used when running the subagent.
@@ -1090,36 +1093,29 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
10901093 // logger.Warn(ctx, "set CAP_NET_ADMIN on agent binary failed", slog.Error(err))
10911094 // }
10921095
1093- // Detect workspace folder by executing `pwd` in the container.
1094- // NOTE(mafredri): This is a quick and dirty way to detect the
1095- // workspace folder inside the container. In the future we will
1096- // rely more on `devcontainer read-configuration`.
1097- var pwdBuf bytes.Buffer
1098- err = api .dccli .Exec (ctx , dc .WorkspaceFolder , dc .ConfigPath , "pwd" , []string {},
1099- WithExecOutput (& pwdBuf , io .Discard ),
1100- WithExecContainerID (container .ID ),
1101- )
1102- if err != nil {
1103- return xerrors .Errorf ("check workspace folder in container: %w" , err )
1104- }
1105- directory := strings .TrimSpace (pwdBuf .String ())
1106- if directory == "" {
1107- logger .Warn (ctx , "detected workspace folder is empty, using default workspace folder" ,
1108- slog .F ("default_workspace_folder" , DevcontainerDefaultContainerWorkspaceFolder ),
1096+ subAgentConfig := proc .agent .CloneConfig (dc )
1097+ if proc .agent .ID == uuid .Nil || maybeRecreateSubAgent {
1098+ // Detect workspace folder by executing `pwd` in the container.
1099+ // NOTE(mafredri): This is a quick and dirty way to detect the
1100+ // workspace folder inside the container. In the future we will
1101+ // rely more on `devcontainer read-configuration`.
1102+ var pwdBuf bytes.Buffer
1103+ err = api .dccli .Exec (ctx , dc .WorkspaceFolder , dc .ConfigPath , "pwd" , []string {},
1104+ WithExecOutput (& pwdBuf , io .Discard ),
1105+ WithExecContainerID (container .ID ),
11091106 )
1110- directory = DevcontainerDefaultContainerWorkspaceFolder
1111- }
1112-
1113- if proc .agent .ID != uuid .Nil && recreateSubAgent {
1114- logger .Debug (ctx , "deleting existing subagent for recreation" , slog .F ("agent_id" , proc .agent .ID ))
1115- client := * api .subAgentClient .Load ()
1116- err = client .Delete (ctx , proc .agent .ID )
11171107 if err != nil {
1118- return xerrors .Errorf ("delete existing subagent failed : %w" , err )
1108+ return xerrors .Errorf ("check workspace folder in container : %w" , err )
11191109 }
1120- proc .agent = SubAgent {}
1121- }
1122- if proc .agent .ID == uuid .Nil {
1110+ directory := strings .TrimSpace (pwdBuf .String ())
1111+ if directory == "" {
1112+ logger .Warn (ctx , "detected workspace folder is empty, using default workspace folder" ,
1113+ slog .F ("default_workspace_folder" , DevcontainerDefaultContainerWorkspaceFolder ),
1114+ )
1115+ directory = DevcontainerDefaultContainerWorkspaceFolder
1116+ }
1117+ subAgentConfig .Directory = directory
1118+
11231119 displayAppsMap := map [codersdk.DisplayApp ]bool {
11241120 // NOTE(DanielleMaywood):
11251121 // We use the same defaults here as set in terraform-provider-coder.
@@ -1138,6 +1134,13 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
11381134
11391135 for _ , customization := range coderCustomization {
11401136 for app , enabled := range customization .DisplayApps {
1137+ if _ , ok := displayAppsMap [app ]; ! ok {
1138+ logger .Warn (ctx , "unknown display app in devcontainer customization, ignoring" ,
1139+ slog .F ("app" , app ),
1140+ slog .F ("enabled" , enabled ),
1141+ )
1142+ continue
1143+ }
11411144 displayAppsMap [app ] = enabled
11421145 }
11431146 }
@@ -1149,26 +1152,41 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
11491152 displayApps = append (displayApps , app )
11501153 }
11511154 }
1155+ slices .Sort (displayApps )
11521156
1157+ subAgentConfig .DisplayApps = displayApps
1158+ }
1159+
1160+ deleteSubAgent := proc .agent .ID != uuid .Nil && maybeRecreateSubAgent && ! proc .agent .EqualConfig (subAgentConfig )
1161+ if deleteSubAgent {
1162+ logger .Debug (ctx , "deleting existing subagent for recreation" , slog .F ("agent_id" , proc .agent .ID ))
1163+ client := * api .subAgentClient .Load ()
1164+ err = client .Delete (ctx , proc .agent .ID )
1165+ if err != nil {
1166+ return xerrors .Errorf ("delete existing subagent failed: %w" , err )
1167+ }
1168+ proc .agent = SubAgent {} // Clear agent to signal that we need to create a new one.
1169+ }
1170+
1171+ if proc .agent .ID == uuid .Nil {
11531172 logger .Debug (ctx , "creating new subagent" ,
1154- slog .F ("directory" , directory ),
1155- slog .F ("display_apps" , displayApps ),
1173+ slog .F ("directory" , subAgentConfig . Directory ),
1174+ slog .F ("display_apps" , subAgentConfig . DisplayApps ),
11561175 )
11571176
11581177 // Create new subagent record in the database to receive the auth token.
11591178 client := * api .subAgentClient .Load ()
1160- proc .agent , err = client .Create (ctx , SubAgent {
1161- Name : dc .Name ,
1162- Directory : directory ,
1163- OperatingSystem : "linux" , // Assuming Linux for devcontainers.
1164- Architecture : arch ,
1165- DisplayApps : displayApps ,
1166- })
1179+ newSubAgent , err := client .Create (ctx , subAgentConfig )
11671180 if err != nil {
11681181 return xerrors .Errorf ("create subagent failed: %w" , err )
11691182 }
1183+ proc .agent = newSubAgent
11701184
11711185 logger .Info (ctx , "created new subagent" , slog .F ("agent_id" , proc .agent .ID ))
1186+ } else {
1187+ logger .Debug (ctx , "subagent already exists, skipping recreation" ,
1188+ slog .F ("agent_id" , proc .agent .ID ),
1189+ )
11721190 }
11731191
11741192 api .mu .Lock () // Re-lock to update the agent.
0 commit comments