@@ -671,9 +671,9 @@ func (api *API) getContainers() (codersdk.WorkspaceAgentListContainersResponse,
671
671
if len (api .knownDevcontainers ) > 0 {
672
672
devcontainers = make ([]codersdk.WorkspaceAgentDevcontainer , 0 , len (api .knownDevcontainers ))
673
673
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
675
675
// 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 {
677
677
dc .Agent = & codersdk.WorkspaceAgentDevcontainerAgent {
678
678
ID : proc .agent .ID ,
679
679
Name : proc .agent .Name ,
@@ -977,7 +977,7 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
977
977
)
978
978
979
979
// Check if subagent already exists for this devcontainer.
980
- recreateSubAgent := false
980
+ maybeRecreateSubAgent := false
981
981
proc , injected := api .injectedSubAgentProcs [dc .WorkspaceFolder ]
982
982
if injected {
983
983
if proc .containerID == container .ID && proc .ctx .Err () == nil {
@@ -992,12 +992,15 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
992
992
logger .Debug (ctx , "container ID changed, injecting subagent into new container" ,
993
993
slog .F ("old_container_id" , proc .containerID ),
994
994
)
995
- recreateSubAgent = true
995
+ maybeRecreateSubAgent = proc . agent . ID != uuid . Nil
996
996
}
997
997
998
998
// Container ID changed or the subagent process is not running,
999
999
// stop the existing subagent context to replace it.
1000
1000
proc .stop ()
1001
+ } else {
1002
+ // Set SubAgent defaults.
1003
+ proc .agent .OperatingSystem = "linux" // Assuming Linux for devcontainers.
1001
1004
}
1002
1005
1003
1006
// Prepare the subAgentProcess to be used when running the subagent.
@@ -1090,36 +1093,29 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
1090
1093
// logger.Warn(ctx, "set CAP_NET_ADMIN on agent binary failed", slog.Error(err))
1091
1094
// }
1092
1095
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 ),
1109
1106
)
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 )
1117
1107
if err != nil {
1118
- return xerrors .Errorf ("delete existing subagent failed : %w" , err )
1108
+ return xerrors .Errorf ("check workspace folder in container : %w" , err )
1119
1109
}
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
+
1123
1119
displayAppsMap := map [codersdk.DisplayApp ]bool {
1124
1120
// NOTE(DanielleMaywood):
1125
1121
// 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
1138
1134
1139
1135
for _ , customization := range coderCustomization {
1140
1136
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
+ }
1141
1144
displayAppsMap [app ] = enabled
1142
1145
}
1143
1146
}
@@ -1149,26 +1152,41 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
1149
1152
displayApps = append (displayApps , app )
1150
1153
}
1151
1154
}
1155
+ slices .Sort (displayApps )
1152
1156
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 {
1153
1172
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 ),
1156
1175
)
1157
1176
1158
1177
// Create new subagent record in the database to receive the auth token.
1159
1178
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 )
1167
1180
if err != nil {
1168
1181
return xerrors .Errorf ("create subagent failed: %w" , err )
1169
1182
}
1183
+ proc .agent = newSubAgent
1170
1184
1171
1185
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
+ )
1172
1190
}
1173
1191
1174
1192
api .mu .Lock () // Re-lock to update the agent.
0 commit comments