@@ -22,6 +22,7 @@ import (
22
22
"fmt"
23
23
"sort"
24
24
"strings"
25
+ "sync"
25
26
"time"
26
27
27
28
containerd "github.com/containerd/containerd/v2/client"
@@ -40,11 +41,11 @@ import (
40
41
41
42
// List prints containers according to `options`.
42
43
func List (ctx context.Context , client * containerd.Client , options types.ContainerListOptions ) ([]ListItem , error ) {
43
- containers , err := filterContainers (ctx , client , options .Filters , options .LastN , options .All )
44
+ containers , cMap , err := filterContainers (ctx , client , options .Filters , options .LastN , options .All )
44
45
if err != nil {
45
46
return nil , err
46
47
}
47
- return prepareContainers (ctx , client , containers , options )
48
+ return prepareContainers (ctx , client , containers , cMap , options )
48
49
}
49
50
50
51
// filterContainers returns containers matching the filters.
@@ -53,14 +54,14 @@ func List(ctx context.Context, client *containerd.Client, options types.Containe
53
54
// - all means showing all containers (default shows just running).
54
55
// - lastN means only showing n last created containers (includes all states). Non-positive values are ignored.
55
56
// In other words, if lastN is positive, all will be set to true.
56
- func filterContainers (ctx context.Context , client * containerd.Client , filters []string , lastN int , all bool ) ([]containerd.Container , error ) {
57
+ func filterContainers (ctx context.Context , client * containerd.Client , filters []string , lastN int , all bool ) ([]containerd.Container , map [ string ] string , error ) {
57
58
containers , err := client .Containers (ctx )
58
59
if err != nil {
59
- return nil , err
60
+ return nil , nil , err
60
61
}
61
62
filterCtx , err := foldContainerFilters (ctx , containers , filters )
62
63
if err != nil {
63
- return nil , err
64
+ return nil , nil , err
64
65
}
65
66
containers = filterCtx .MatchesFilters (ctx )
66
67
@@ -77,18 +78,36 @@ func filterContainers(ctx context.Context, client *containerd.Client, filters []
77
78
}
78
79
}
79
80
81
+ var wg sync.WaitGroup
82
+ cMap := make (map [string ]string )
83
+ var mu sync.Mutex
84
+ // formatter.ContainerStatus(ctx, c) is time consuming so we do it in goroutines and return the container's id with status as a map.
85
+ // prepareContainers func will will this map to avoid call formatter.ContainerStatus again.
86
+ for _ , c := range containers {
87
+ wg .Add (1 )
88
+ go func (ctx context.Context , c containerd.Container ) {
89
+ defer wg .Done ()
90
+ cStatus := formatter .ContainerStatus (ctx , c )
91
+ mu .Lock ()
92
+ if c .ID () != "" {
93
+ cMap [c .ID ()] = cStatus
94
+ }
95
+ mu .Unlock ()
96
+ }(ctx , c )
97
+ }
98
+ wg .Wait ()
80
99
if all || filterCtx .all {
81
- return containers , nil
100
+ return containers , cMap , nil
82
101
}
83
102
84
103
var upContainers []containerd.Container
85
104
for _ , c := range containers {
86
- cStatus := formatter . ContainerStatus ( ctx , c )
105
+ cStatus := cMap [ c . ID ()]
87
106
if strings .HasPrefix (cStatus , "Up" ) {
88
107
upContainers = append (upContainers , c )
89
108
}
90
109
}
91
- return upContainers , nil
110
+ return upContainers , cMap , nil
92
111
}
93
112
94
113
type ListItem struct {
@@ -112,7 +131,7 @@ func (x *ListItem) Label(s string) string {
112
131
return x .LabelsMap [s ]
113
132
}
114
133
115
- func prepareContainers (ctx context.Context , client * containerd.Client , containers []containerd.Container , options types.ContainerListOptions ) ([]ListItem , error ) {
134
+ func prepareContainers (ctx context.Context , client * containerd.Client , containers []containerd.Container , cMap map [ string ] string , options types.ContainerListOptions ) ([]ListItem , error ) {
116
135
listItems := make ([]ListItem , len (containers ))
117
136
snapshottersCache := map [string ]snapshots.Snapshotter {}
118
137
for i , c := range containers {
@@ -136,6 +155,13 @@ func prepareContainers(ctx context.Context, client *containerd.Client, container
136
155
if options .Truncate && len (id ) > 12 {
137
156
id = id [:12 ]
138
157
}
158
+ var status string
159
+ s , ok := cMap [c .ID ()]
160
+ if ok {
161
+ status = s
162
+ } else {
163
+ return nil , fmt .Errorf ("can't get container %s status" , c .ID ())
164
+ }
139
165
li := ListItem {
140
166
Command : formatter .InspectContainerCommand (spec , options .Truncate , true ),
141
167
CreatedAt : info .CreatedAt ,
@@ -144,7 +170,7 @@ func prepareContainers(ctx context.Context, client *containerd.Client, container
144
170
Platform : info .Labels [labels .Platform ],
145
171
Names : containerutil .GetContainerName (info .Labels ),
146
172
Ports : formatter .FormatPorts (info .Labels ),
147
- Status : formatter . ContainerStatus ( ctx , c ) ,
173
+ Status : status ,
148
174
Runtime : info .Runtime .Name ,
149
175
Labels : formatter .FormatLabels (info .Labels ),
150
176
LabelsMap : info .Labels ,
0 commit comments