@@ -14,6 +14,8 @@ import (
14
14
"github.com/containers/common/pkg/util"
15
15
"github.com/containers/podman/v5/libpod"
16
16
"github.com/containers/podman/v5/libpod/define"
17
+ "github.com/containers/podman/v5/pkg/domain/entities/types"
18
+ "github.com/containers/storage"
17
19
)
18
20
19
21
// GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
@@ -282,6 +284,10 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
282
284
}
283
285
return false
284
286
}, filterValueError
287
+ case "command" :
288
+ return func (c * libpod.Container ) bool {
289
+ return util .StringMatchRegexSlice (c .Command ()[0 ], filterValues )
290
+ }, nil
285
291
}
286
292
return nil , fmt .Errorf ("%s is an invalid filter" , filter )
287
293
}
@@ -315,3 +321,112 @@ func prepareUntilFilterFunc(filterValues []string) (func(container *libpod.Conta
315
321
return false
316
322
}, nil
317
323
}
324
+
325
+ // GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
326
+ func GenerateExternalContainerFilterFuncs (filter string , filterValues []string , r * libpod.Runtime ) (func (listContainer * types.ListContainer ) bool , error ) {
327
+ switch filter {
328
+ case "id" :
329
+ return func (listContainer * types.ListContainer ) bool {
330
+ return filters .FilterID (listContainer .ContainerID (), filterValues )
331
+ }, nil
332
+ case "name" :
333
+ // we only have to match one name
334
+ return func (listContainer * types.ListContainer ) bool {
335
+ namesList := listContainer .NamesList ()
336
+
337
+ for _ , f := range filterValues {
338
+ f = strings .ReplaceAll (f , "/" , "" )
339
+ if util .StringMatchRegexSlice (f , namesList ) {
340
+ return true
341
+ }
342
+ }
343
+
344
+ return false
345
+ }, nil
346
+ case "command" :
347
+ return func (listContainer * types.ListContainer ) bool {
348
+ return util .StringMatchRegexSlice (listContainer .Commands ()[0 ], filterValues )
349
+ }, nil
350
+ case "ancestor" :
351
+ // This needs to refine to match docker
352
+ // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
353
+ return func (listContainer * types.ListContainer ) bool {
354
+ for _ , filterValue := range filterValues {
355
+ rootfsImageID , rootfsImageName := listContainer .ImageInfo ()
356
+ var imageTag string
357
+ var imageNameWithoutTag string
358
+ // Compare with ImageID, ImageName
359
+ // Will match ImageName if running image has tag latest for other tags exact complete filter must be given
360
+ name , tag , hasColon := strings .Cut (rootfsImageName , ":" )
361
+ if hasColon {
362
+ imageNameWithoutTag = name
363
+ imageTag = tag
364
+ }
365
+
366
+ if (rootfsImageID == filterValue ) ||
367
+ util .StringMatchRegexSlice (rootfsImageName , filterValues ) ||
368
+ (util .StringMatchRegexSlice (imageNameWithoutTag , filterValues ) && imageTag == "latest" ) {
369
+ return true
370
+ }
371
+ }
372
+ return false
373
+ }, nil
374
+ case "before" :
375
+ var createTime time.Time
376
+ var externCons []storage.Container
377
+ externCons , err := r .StorageContainers ()
378
+ if err != nil {
379
+ return nil , err
380
+ }
381
+
382
+ for _ , filterValue := range filterValues {
383
+ for _ , ctr := range externCons {
384
+ if slices .Contains (ctr .Names , filterValue ) {
385
+ if createTime .IsZero () || createTime .After (ctr .Created ) {
386
+ createTime = ctr .Created
387
+ }
388
+ }
389
+ }
390
+ }
391
+
392
+ return func (listContainer * types.ListContainer ) bool {
393
+ return createTime .After (listContainer .CreatedTime ())
394
+ }, nil
395
+ case "since" :
396
+ var createTime time.Time
397
+ var externCons []storage.Container
398
+ externCons , err := r .StorageContainers ()
399
+ if err != nil {
400
+ return nil , err
401
+ }
402
+
403
+ for _ , filterValue := range filterValues {
404
+ for _ , ctr := range externCons {
405
+ if slices .Contains (ctr .Names , filterValue ) {
406
+ if createTime .IsZero () || createTime .After (ctr .Created ) {
407
+ createTime = ctr .Created
408
+ }
409
+ }
410
+ }
411
+ }
412
+
413
+ return func (listContainer * types.ListContainer ) bool {
414
+ return createTime .Before (listContainer .CreatedTime ())
415
+ }, nil
416
+ case "until" :
417
+ until , err := filters .ComputeUntilTimestamp (filterValues )
418
+ if err != nil {
419
+ return nil , err
420
+ }
421
+ return func (listContainer * types.ListContainer ) bool {
422
+ if ! until .IsZero () && listContainer .CreatedTime ().Before (until ) {
423
+ return true
424
+ }
425
+ return false
426
+ }, nil
427
+ case "restart-policy" , "network" , "pod" , "volume" , "health" , "label" , "exited" , "status" :
428
+ return nil , fmt .Errorf ("filter %s is not applicable for external containers" , filter )
429
+ }
430
+
431
+ return nil , fmt .Errorf ("%s is an invalid filter" , filter )
432
+ }
0 commit comments