@@ -162,23 +162,28 @@ func (dei *DockerEnvInfoer) ModifyCommand(cmd string, args ...string) (string, [
162
162
// devcontainerEnv is a helper function that inspects the container labels to
163
163
// find the required environment variables for running a command in the container.
164
164
func devcontainerEnv (ctx context.Context , execer agentexec.Execer , container string ) ([]string , error ) {
165
- ins , stderr , err := runDockerInspect (ctx , execer , container )
165
+ stdout , stderr , err := runDockerInspect (ctx , execer , container )
166
166
if err != nil {
167
167
return nil , xerrors .Errorf ("inspect container: %w: %q" , err , stderr )
168
168
}
169
169
170
+ ins , _ , err := convertDockerInspect (stdout )
171
+ if err != nil {
172
+ return nil , xerrors .Errorf ("inspect container: %w" , err )
173
+ }
174
+
170
175
if len (ins ) != 1 {
171
176
return nil , xerrors .Errorf ("inspect container: expected 1 container, got %d" , len (ins ))
172
177
}
173
178
174
179
in := ins [0 ]
175
- if in .Config . Labels == nil {
180
+ if in .Labels == nil {
176
181
return nil , nil
177
182
}
178
183
179
184
// We want to look for the devcontainer metadata, which is in the
180
185
// value of the label `devcontainer.metadata`.
181
- rawMeta , ok := in .Config . Labels ["devcontainer.metadata" ]
186
+ rawMeta , ok := in .Labels ["devcontainer.metadata" ]
182
187
if ! ok {
183
188
return nil , nil
184
189
}
@@ -279,42 +284,36 @@ func (dcl *DockerCLILister) List(ctx context.Context) (codersdk.WorkspaceAgentLi
279
284
return codersdk.WorkspaceAgentListContainersResponse {}, xerrors .Errorf ("run docker inspect: %w" , err )
280
285
}
281
286
282
- for _ , in := range ins {
283
- out , warns := convertDockerInspect (in )
284
- res .Warnings = append (res .Warnings , warns ... )
285
- res .Containers = append (res .Containers , out )
286
- }
287
-
288
- if dockerPsStderr != "" {
289
- res .Warnings = append (res .Warnings , dockerPsStderr )
290
- }
291
287
if dockerInspectStderr != "" {
292
288
res .Warnings = append (res .Warnings , dockerInspectStderr )
293
289
}
294
290
291
+ outs , warns , err := convertDockerInspect (ins )
292
+ if err != nil {
293
+ return codersdk.WorkspaceAgentListContainersResponse {}, xerrors .Errorf ("convert docker inspect output: %w" , err )
294
+ }
295
+ res .Warnings = append (res .Warnings , warns ... )
296
+ res .Containers = append (res .Containers , outs ... )
297
+
295
298
return res , nil
296
299
}
297
300
298
301
// runDockerInspect is a helper function that runs `docker inspect` on the given
299
302
// container IDs and returns the parsed output.
300
303
// The stderr output is also returned for logging purposes.
301
- func runDockerInspect (ctx context.Context , execer agentexec.Execer , ids ... string ) ([] dockerInspect , string , error ) {
304
+ func runDockerInspect (ctx context.Context , execer agentexec.Execer , ids ... string ) (stdout , stderr string , err error ) {
302
305
var stdoutBuf , stderrBuf bytes.Buffer
303
306
cmd := execer .CommandContext (ctx , "docker" , append ([]string {"inspect" }, ids ... )... )
304
307
cmd .Stdout = & stdoutBuf
305
308
cmd .Stderr = & stderrBuf
306
- err := cmd .Run ()
307
- stderr := strings .TrimSpace (stderrBuf .String ())
309
+ err = cmd .Run ()
310
+ stdout = strings .TrimSpace (stdoutBuf .String ())
311
+ stderr = strings .TrimSpace (stderrBuf .String ())
308
312
if err != nil {
309
- return nil , stderr , err
313
+ return stdout , stderr , err
310
314
}
311
315
312
- var ins []dockerInspect
313
- if err := json .NewDecoder (& stdoutBuf ).Decode (& ins ); err != nil {
314
- return nil , stderr , xerrors .Errorf ("decode docker inspect output: %w" , err )
315
- }
316
-
317
- return ins , stderr , nil
316
+ return stdoutBuf .String (), stderr , nil
318
317
}
319
318
320
319
// To avoid a direct dependency on the Docker API, we use the docker CLI
@@ -367,50 +366,59 @@ func (dis dockerInspectState) String() string {
367
366
return sb .String ()
368
367
}
369
368
370
- func convertDockerInspect (in dockerInspect ) (codersdk.WorkspaceAgentDevcontainer , []string ) {
369
+ func convertDockerInspect (raw string ) ([] codersdk.WorkspaceAgentDevcontainer , []string , error ) {
371
370
var warns []string
372
- out := codersdk.WorkspaceAgentDevcontainer {
373
- CreatedAt : in .Created ,
374
- // Remove the leading slash from the container name
375
- FriendlyName : strings .TrimPrefix (in .Name , "/" ),
376
- ID : in .ID ,
377
- Image : in .Config .Image ,
378
- Labels : in .Config .Labels ,
379
- Ports : make ([]codersdk.WorkspaceAgentListeningPort , 0 ),
380
- Running : in .State .Running ,
381
- Status : in .State .String (),
382
- Volumes : make (map [string ]string , len (in .Mounts )),
383
- }
384
-
385
- if in .HostConfig .PortBindings == nil {
386
- in .HostConfig .PortBindings = make (map [string ]any )
387
- }
388
- portKeys := maps .Keys (in .HostConfig .PortBindings )
389
- // Sort the ports for deterministic output.
390
- sort .Strings (portKeys )
391
- for _ , p := range portKeys {
392
- if port , network , err := convertDockerPort (p ); err != nil {
393
- warns = append (warns , err .Error ())
394
- } else {
395
- out .Ports = append (out .Ports , codersdk.WorkspaceAgentListeningPort {
396
- Network : network ,
397
- Port : port ,
398
- })
399
- }
371
+ var ins []dockerInspect
372
+ if err := json .NewDecoder (strings .NewReader (raw )).Decode (& ins ); err != nil {
373
+ return nil , nil , xerrors .Errorf ("decode docker inspect output: %w" , err )
400
374
}
375
+ outs := make ([]codersdk.WorkspaceAgentDevcontainer , 0 , len (ins ))
401
376
402
- if in .Mounts == nil {
403
- in .Mounts = []dockerInspectMount {}
404
- }
405
- // Sort the mounts for deterministic output.
406
- sort .Slice (in .Mounts , func (i , j int ) bool {
407
- return in .Mounts [i ].Source < in .Mounts [j ].Source
408
- })
409
- for _ , k := range in .Mounts {
410
- out .Volumes [k .Source ] = k .Destination
377
+ for _ , in := range ins {
378
+ out := codersdk.WorkspaceAgentDevcontainer {
379
+ CreatedAt : in .Created ,
380
+ // Remove the leading slash from the container name
381
+ FriendlyName : strings .TrimPrefix (in .Name , "/" ),
382
+ ID : in .ID ,
383
+ Image : in .Config .Image ,
384
+ Labels : in .Config .Labels ,
385
+ Ports : make ([]codersdk.WorkspaceAgentListeningPort , 0 ),
386
+ Running : in .State .Running ,
387
+ Status : in .State .String (),
388
+ Volumes : make (map [string ]string , len (in .Mounts )),
389
+ }
390
+
391
+ if in .HostConfig .PortBindings == nil {
392
+ in .HostConfig .PortBindings = make (map [string ]any )
393
+ }
394
+ portKeys := maps .Keys (in .HostConfig .PortBindings )
395
+ // Sort the ports for deterministic output.
396
+ sort .Strings (portKeys )
397
+ for _ , p := range portKeys {
398
+ if port , network , err := convertDockerPort (p ); err != nil {
399
+ warns = append (warns , err .Error ())
400
+ } else {
401
+ out .Ports = append (out .Ports , codersdk.WorkspaceAgentListeningPort {
402
+ Network : network ,
403
+ Port : port ,
404
+ })
405
+ }
406
+ }
407
+
408
+ if in .Mounts == nil {
409
+ in .Mounts = []dockerInspectMount {}
410
+ }
411
+ // Sort the mounts for deterministic output.
412
+ sort .Slice (in .Mounts , func (i , j int ) bool {
413
+ return in .Mounts [i ].Source < in .Mounts [j ].Source
414
+ })
415
+ for _ , k := range in .Mounts {
416
+ out .Volumes [k .Source ] = k .Destination
417
+ }
418
+ outs = append (outs , out )
411
419
}
412
420
413
- return out , warns
421
+ return outs , warns , nil
414
422
}
415
423
416
424
// convertDockerPort converts a Docker port string to a port number and network
0 commit comments