@@ -10,7 +10,6 @@ import (
10
10
"github.com/Sirupsen/logrus"
11
11
"github.com/docker/docker/api/types"
12
12
"github.com/docker/docker/api/types/filters"
13
- networktypes "github.com/docker/docker/api/types/network"
14
13
"github.com/docker/docker/container"
15
14
"github.com/docker/docker/image"
16
15
"github.com/docker/docker/volume"
@@ -47,7 +46,7 @@ type iterationAction int
47
46
48
47
// containerReducer represents a reducer for a container.
49
48
// Returns the object to serialize by the api.
50
- type containerReducer func (* container.Container , * listContext ) (* types.Container , error )
49
+ type containerReducer func (* container.Snapshot , * listContext ) (* types.Container , error )
51
50
52
51
const (
53
52
// includeContainer is the action to include a container in the reducer.
@@ -83,9 +82,9 @@ type listContext struct {
83
82
exitAllowed []int
84
83
85
84
// beforeFilter is a filter to ignore containers that appear before the one given
86
- beforeFilter * container.Container
85
+ beforeFilter * container.Snapshot
87
86
// sinceFilter is a filter to stop the filtering when the iterator arrive to the given container
88
- sinceFilter * container.Container
87
+ sinceFilter * container.Snapshot
89
88
90
89
// taskFilter tells if we should filter based on wether a container is part of a task
91
90
taskFilter bool
@@ -102,7 +101,7 @@ type listContext struct {
102
101
}
103
102
104
103
// byContainerCreated is a temporary type used to sort a list of containers by creation time.
105
- type byContainerCreated []* container.Container
104
+ type byContainerCreated []container.Snapshot
106
105
107
106
func (r byContainerCreated ) Len () int { return len (r ) }
108
107
func (r byContainerCreated ) Swap (i , j int ) { r [i ], r [j ] = r [j ], r [i ] }
@@ -115,15 +114,17 @@ func (daemon *Daemon) Containers(config *types.ContainerListOptions) ([]*types.C
115
114
return daemon .reduceContainers (config , daemon .transformContainer )
116
115
}
117
116
118
- func (daemon * Daemon ) filterByNameIDMatches (ctx * listContext ) [] * container.Container {
117
+ func (daemon * Daemon ) filterByNameIDMatches (view * container. View , ctx * listContext ) ([] container.Snapshot , error ) {
119
118
idSearch := false
120
119
names := ctx .filters .Get ("name" )
121
120
ids := ctx .filters .Get ("id" )
122
121
if len (names )+ len (ids ) == 0 {
123
122
// if name or ID filters are not in use, return to
124
123
// standard behavior of walking the entire container
125
124
// list from the daemon's in-memory store
126
- return daemon .List ()
125
+ all , err := view .All ()
126
+ sort .Sort (sort .Reverse (byContainerCreated (all )))
127
+ return all , err
127
128
}
128
129
129
130
// idSearch will determine if we limit name matching to the IDs
@@ -158,38 +159,46 @@ func (daemon *Daemon) filterByNameIDMatches(ctx *listContext) []*container.Conta
158
159
}
159
160
}
160
161
161
- cntrs := make ([]* container.Container , 0 , len (matches ))
162
+ cntrs := make ([]container.Snapshot , 0 , len (matches ))
162
163
for id := range matches {
163
- if c := daemon .containers .Get (id ); c != nil {
164
- cntrs = append (cntrs , c )
164
+ c , err := view .Get (id )
165
+ if err != nil {
166
+ return nil , err
167
+ }
168
+ if c != nil {
169
+ cntrs = append (cntrs , * c )
165
170
}
166
171
}
167
172
168
173
// Restore sort-order after filtering
169
174
// Created gives us nanosec resolution for sorting
170
175
sort .Sort (sort .Reverse (byContainerCreated (cntrs )))
171
176
172
- return cntrs
177
+ return cntrs , nil
173
178
}
174
179
175
180
// reduceContainers parses the user's filtering options and generates the list of containers to return based on a reducer.
176
181
func (daemon * Daemon ) reduceContainers (config * types.ContainerListOptions , reducer containerReducer ) ([]* types.Container , error ) {
177
182
var (
183
+ view = daemon .containersReplica .Snapshot ()
178
184
containers = []* types.Container {}
179
185
)
180
186
181
- ctx , err := daemon .foldFilter (config )
187
+ ctx , err := daemon .foldFilter (view , config )
182
188
if err != nil {
183
189
return nil , err
184
190
}
185
191
186
192
// fastpath to only look at a subset of containers if specific name
187
193
// or ID matches were provided by the user--otherwise we potentially
188
- // end up locking and querying many more containers than intended
189
- containerList := daemon .filterByNameIDMatches (ctx )
194
+ // end up querying many more containers than intended
195
+ containerList , err := daemon .filterByNameIDMatches (view , ctx )
196
+ if err != nil {
197
+ return nil , err
198
+ }
190
199
191
- for _ , container := range containerList {
192
- t , err := daemon .reducePsContainer (container , ctx , reducer )
200
+ for i := range containerList {
201
+ t , err := daemon .reducePsContainer (& containerList [ i ] , ctx , reducer )
193
202
if err != nil {
194
203
if err != errStopIteration {
195
204
return nil , err
@@ -206,23 +215,17 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc
206
215
}
207
216
208
217
// reducePsContainer is the basic representation for a container as expected by the ps command.
209
- func (daemon * Daemon ) reducePsContainer (container * container.Container , ctx * listContext , reducer containerReducer ) (* types.Container , error ) {
210
- container .Lock ()
211
-
218
+ func (daemon * Daemon ) reducePsContainer (container * container.Snapshot , ctx * listContext , reducer containerReducer ) (* types.Container , error ) {
212
219
// filter containers to return
213
- action := includeContainerInList (container , ctx )
214
- switch action {
220
+ switch includeContainerInList (container , ctx ) {
215
221
case excludeContainer :
216
- container .Unlock ()
217
222
return nil , nil
218
223
case stopIteration :
219
- container .Unlock ()
220
224
return nil , errStopIteration
221
225
}
222
226
223
227
// transform internal container struct into api structs
224
228
newC , err := reducer (container , ctx )
225
- container .Unlock ()
226
229
if err != nil {
227
230
return nil , err
228
231
}
@@ -237,7 +240,7 @@ func (daemon *Daemon) reducePsContainer(container *container.Container, ctx *lis
237
240
}
238
241
239
242
// foldFilter generates the container filter based on the user's filtering options.
240
- func (daemon * Daemon ) foldFilter (config * types.ContainerListOptions ) (* listContext , error ) {
243
+ func (daemon * Daemon ) foldFilter (view * container. View , config * types.ContainerListOptions ) (* listContext , error ) {
241
244
psFilters := config .Filters
242
245
243
246
if err := psFilters .Validate (acceptedPsFilterTags ); err != nil {
@@ -294,18 +297,18 @@ func (daemon *Daemon) foldFilter(config *types.ContainerListOptions) (*listConte
294
297
return nil , err
295
298
}
296
299
297
- var beforeContFilter , sinceContFilter * container.Container
300
+ var beforeContFilter , sinceContFilter * container.Snapshot
298
301
299
302
err = psFilters .WalkValues ("before" , func (value string ) error {
300
- beforeContFilter , err = daemon . GetContainer (value )
303
+ beforeContFilter , err = view . Get (value )
301
304
return err
302
305
})
303
306
if err != nil {
304
307
return nil , err
305
308
}
306
309
307
310
err = psFilters .WalkValues ("since" , func (value string ) error {
308
- sinceContFilter , err = daemon . GetContainer (value )
311
+ sinceContFilter , err = view . Get (value )
309
312
return err
310
313
})
311
314
if err != nil {
@@ -383,7 +386,7 @@ func portOp(key string, filter map[nat.Port]bool) func(value string) error {
383
386
384
387
// includeContainerInList decides whether a container should be included in the output or not based in the filter.
385
388
// It also decides if the iteration should be stopped or not.
386
- func includeContainerInList (container * container.Container , ctx * listContext ) iterationAction {
389
+ func includeContainerInList (container * container.Snapshot , ctx * listContext ) iterationAction {
387
390
// Do not include container if it's in the list before the filter container.
388
391
// Set the filter container to nil to include the rest of containers after this one.
389
392
if ctx .beforeFilter != nil {
@@ -422,7 +425,7 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
422
425
}
423
426
424
427
// Do not include container if any of the labels don't match
425
- if ! ctx .filters .MatchKVList ("label" , container .Config . Labels ) {
428
+ if ! ctx .filters .MatchKVList ("label" , container .Labels ) {
426
429
return excludeContainer
427
430
}
428
431
@@ -440,7 +443,7 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
440
443
if len (ctx .exitAllowed ) > 0 {
441
444
shouldSkip := true
442
445
for _ , code := range ctx .exitAllowed {
443
- if code == container .ExitCode () && ! container .Running && ! container .StartedAt .IsZero () {
446
+ if code == container .ExitCode && ! container .Running && ! container .StartedAt .IsZero () {
444
447
shouldSkip = false
445
448
break
446
449
}
@@ -451,28 +454,34 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
451
454
}
452
455
453
456
// Do not include container if its status doesn't match the filter
454
- if ! ctx .filters .Match ("status" , container .State . StateString () ) {
457
+ if ! ctx .filters .Match ("status" , container .State ) {
455
458
return excludeContainer
456
459
}
457
460
458
461
// Do not include container if its health doesn't match the filter
459
- if ! ctx .filters .ExactMatch ("health" , container .State . HealthString () ) {
462
+ if ! ctx .filters .ExactMatch ("health" , container .Health ) {
460
463
return excludeContainer
461
464
}
462
465
463
466
if ctx .filters .Include ("volume" ) {
464
- volumesByName := make (map [string ]* volume .MountPoint )
465
- for _ , m := range container .MountPoints {
467
+ volumesByName := make (map [string ]types .MountPoint )
468
+ for _ , m := range container .Mounts {
466
469
if m .Name != "" {
467
470
volumesByName [m .Name ] = m
468
471
} else {
469
472
volumesByName [m .Source ] = m
470
473
}
471
474
}
475
+ volumesByDestination := make (map [string ]types.MountPoint )
476
+ for _ , m := range container .Mounts {
477
+ if m .Destination != "" {
478
+ volumesByDestination [m .Destination ] = m
479
+ }
480
+ }
472
481
473
482
volumeExist := fmt .Errorf ("volume mounted in container" )
474
483
err := ctx .filters .WalkValues ("volume" , func (value string ) error {
475
- if _ , exist := container . MountPoints [value ]; exist {
484
+ if _ , exist := volumesByDestination [value ]; exist {
476
485
return volumeExist
477
486
}
478
487
if _ , exist := volumesByName [value ]; exist {
@@ -489,7 +498,7 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
489
498
if len (ctx .images ) == 0 {
490
499
return excludeContainer
491
500
}
492
- if ! ctx .images [container .ImageID ] {
501
+ if ! ctx .images [image . ID ( container .ImageID ) ] {
493
502
return excludeContainer
494
503
}
495
504
}
@@ -501,7 +510,7 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
501
510
return networkExist
502
511
}
503
512
for _ , nw := range container .NetworkSettings .Networks {
504
- if nw . EndpointSettings == nil {
513
+ if nw == nil {
505
514
continue
506
515
}
507
516
if strings .HasPrefix (nw .NetworkID , value ) {
@@ -518,7 +527,7 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
518
527
if len (ctx .publish ) > 0 {
519
528
shouldSkip := true
520
529
for port := range ctx .publish {
521
- if _ , ok := container .HostConfig . PortBindings [port ]; ok {
530
+ if _ , ok := container .PublishPorts [port ]; ok {
522
531
shouldSkip = false
523
532
break
524
533
}
@@ -531,7 +540,7 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
531
540
if len (ctx .expose ) > 0 {
532
541
shouldSkip := true
533
542
for port := range ctx .expose {
534
- if _ , ok := container .Config . ExposedPorts [port ]; ok {
543
+ if _ , ok := container .ExposedPorts [port ]; ok {
535
544
shouldSkip = false
536
545
break
537
546
}
@@ -545,104 +554,38 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
545
554
}
546
555
547
556
// transformContainer generates the container type expected by the docker ps command.
548
- func (daemon * Daemon ) transformContainer (container * container.Container , ctx * listContext ) (* types.Container , error ) {
557
+ func (daemon * Daemon ) transformContainer (container * container.Snapshot , ctx * listContext ) (* types.Container , error ) {
549
558
newC := & types.Container {
550
- ID : container .ID ,
551
- Names : ctx .names [container .ID ],
552
- ImageID : container .ImageID .String (),
559
+ ID : container .ID ,
560
+ Names : ctx .names [container .ID ],
561
+ ImageID : container .ImageID ,
562
+ Command : container .Command ,
563
+ Created : container .Created .Unix (),
564
+ State : container .State ,
565
+ Status : container .Status ,
566
+ NetworkSettings : & container .NetworkSettings ,
567
+ Ports : container .Ports ,
568
+ Labels : container .Labels ,
569
+ Mounts : container .Mounts ,
553
570
}
554
571
if newC .Names == nil {
555
572
// Dead containers will often have no name, so make sure the response isn't null
556
573
newC .Names = []string {}
557
574
}
575
+ newC .HostConfig .NetworkMode = container .HostConfig .NetworkMode
558
576
559
- image := container .Config . Image // if possible keep the original ref
560
- if image != container .ImageID . String () {
577
+ image := container .Image // if possible keep the original ref
578
+ if image != container .ImageID {
561
579
id , _ , err := daemon .GetImageIDAndPlatform (image )
562
580
if _ , isDNE := err .(ErrImageDoesNotExist ); err != nil && ! isDNE {
563
581
return nil , err
564
582
}
565
- if err != nil || id != container .ImageID {
566
- image = container .ImageID . String ()
583
+ if err != nil || id . String () != container .ImageID {
584
+ image = container .ImageID
567
585
}
568
586
}
569
587
newC .Image = image
570
588
571
- if len (container .Args ) > 0 {
572
- args := []string {}
573
- for _ , arg := range container .Args {
574
- if strings .Contains (arg , " " ) {
575
- args = append (args , fmt .Sprintf ("'%s'" , arg ))
576
- } else {
577
- args = append (args , arg )
578
- }
579
- }
580
- argsAsString := strings .Join (args , " " )
581
-
582
- newC .Command = fmt .Sprintf ("%s %s" , container .Path , argsAsString )
583
- } else {
584
- newC .Command = container .Path
585
- }
586
- newC .Created = container .Created .Unix ()
587
- newC .State = container .State .StateString ()
588
- newC .Status = container .State .String ()
589
- newC .HostConfig .NetworkMode = string (container .HostConfig .NetworkMode )
590
- // copy networks to avoid races
591
- networks := make (map [string ]* networktypes.EndpointSettings )
592
- for name , network := range container .NetworkSettings .Networks {
593
- if network == nil || network .EndpointSettings == nil {
594
- continue
595
- }
596
- networks [name ] = & networktypes.EndpointSettings {
597
- EndpointID : network .EndpointID ,
598
- Gateway : network .Gateway ,
599
- IPAddress : network .IPAddress ,
600
- IPPrefixLen : network .IPPrefixLen ,
601
- IPv6Gateway : network .IPv6Gateway ,
602
- GlobalIPv6Address : network .GlobalIPv6Address ,
603
- GlobalIPv6PrefixLen : network .GlobalIPv6PrefixLen ,
604
- MacAddress : network .MacAddress ,
605
- NetworkID : network .NetworkID ,
606
- }
607
- if network .IPAMConfig != nil {
608
- networks [name ].IPAMConfig = & networktypes.EndpointIPAMConfig {
609
- IPv4Address : network .IPAMConfig .IPv4Address ,
610
- IPv6Address : network .IPAMConfig .IPv6Address ,
611
- }
612
- }
613
- }
614
- newC .NetworkSettings = & types.SummaryNetworkSettings {Networks : networks }
615
-
616
- newC .Ports = []types.Port {}
617
- for port , bindings := range container .NetworkSettings .Ports {
618
- p , err := nat .ParsePort (port .Port ())
619
- if err != nil {
620
- return nil , err
621
- }
622
- if len (bindings ) == 0 {
623
- newC .Ports = append (newC .Ports , types.Port {
624
- PrivatePort : uint16 (p ),
625
- Type : port .Proto (),
626
- })
627
- continue
628
- }
629
- for _ , binding := range bindings {
630
- h , err := nat .ParsePort (binding .HostPort )
631
- if err != nil {
632
- return nil , err
633
- }
634
- newC .Ports = append (newC .Ports , types.Port {
635
- PrivatePort : uint16 (p ),
636
- PublicPort : uint16 (h ),
637
- Type : port .Proto (),
638
- IP : binding .HostIP ,
639
- })
640
- }
641
- }
642
-
643
- newC .Labels = container .Config .Labels
644
- newC .Mounts = addMountPoints (container )
645
-
646
589
return newC , nil
647
590
}
648
591
0 commit comments