github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/filters/containers.go (about)

     1  package lpfilters
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/containers/podman/v2/libpod"
     9  	"github.com/containers/podman/v2/libpod/define"
    10  	"github.com/containers/podman/v2/pkg/timetype"
    11  	"github.com/containers/podman/v2/pkg/util"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  // GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
    16  func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
    17  	switch filter {
    18  	case "id":
    19  		// we only have to match one ID
    20  		return func(c *libpod.Container) bool {
    21  			return util.StringMatchRegexSlice(c.ID(), filterValues)
    22  		}, nil
    23  	case "label":
    24  		// we have to match that all given labels exits on that container
    25  		return func(c *libpod.Container) bool {
    26  			labels := c.Labels()
    27  			for _, filterValue := range filterValues {
    28  				matched := false
    29  				filterArray := strings.SplitN(filterValue, "=", 2)
    30  				filterKey := filterArray[0]
    31  				if len(filterArray) > 1 {
    32  					filterValue = filterArray[1]
    33  				} else {
    34  					filterValue = ""
    35  				}
    36  				for labelKey, labelValue := range labels {
    37  					if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
    38  						matched = true
    39  						break
    40  					}
    41  				}
    42  				if !matched {
    43  					return false
    44  				}
    45  			}
    46  			return true
    47  		}, nil
    48  	case "name":
    49  		// we only have to match one name
    50  		return func(c *libpod.Container) bool {
    51  			return util.StringMatchRegexSlice(c.Name(), filterValues)
    52  		}, nil
    53  	case "exited":
    54  		var exitCodes []int32
    55  		for _, exitCode := range filterValues {
    56  			ec, err := strconv.ParseInt(exitCode, 10, 32)
    57  			if err != nil {
    58  				return nil, errors.Wrapf(err, "exited code out of range %q", ec)
    59  			}
    60  			exitCodes = append(exitCodes, int32(ec))
    61  		}
    62  		return func(c *libpod.Container) bool {
    63  			ec, exited, err := c.ExitCode()
    64  			if err == nil && exited {
    65  				for _, exitCode := range exitCodes {
    66  					if ec == exitCode {
    67  						return true
    68  					}
    69  				}
    70  			}
    71  			return false
    72  		}, nil
    73  	case "status":
    74  		for _, filterValue := range filterValues {
    75  			if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
    76  				return nil, errors.Errorf("%s is not a valid status", filterValue)
    77  			}
    78  		}
    79  		return func(c *libpod.Container) bool {
    80  			status, err := c.State()
    81  			if err != nil {
    82  				return false
    83  			}
    84  			state := status.String()
    85  			if status == define.ContainerStateConfigured {
    86  				state = "created"
    87  			} else if status == define.ContainerStateStopped {
    88  				state = "exited"
    89  			}
    90  			for _, filterValue := range filterValues {
    91  				if filterValue == "stopped" {
    92  					filterValue = "exited"
    93  				}
    94  				if state == filterValue {
    95  					return true
    96  				}
    97  			}
    98  			return false
    99  		}, nil
   100  	case "ancestor":
   101  		// This needs to refine to match docker
   102  		// - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
   103  		return func(c *libpod.Container) bool {
   104  			for _, filterValue := range filterValues {
   105  				containerConfig := c.Config()
   106  				if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) {
   107  					return true
   108  				}
   109  			}
   110  			return false
   111  		}, nil
   112  	case "before":
   113  		var createTime time.Time
   114  		for _, filterValue := range filterValues {
   115  			ctr, err := r.LookupContainer(filterValue)
   116  			if err != nil {
   117  				return nil, err
   118  			}
   119  			containerConfig := ctr.Config()
   120  			if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) {
   121  				createTime = containerConfig.CreatedTime
   122  			}
   123  		}
   124  		return func(c *libpod.Container) bool {
   125  			cc := c.Config()
   126  			return createTime.After(cc.CreatedTime)
   127  		}, nil
   128  	case "since":
   129  		var createTime time.Time
   130  		for _, filterValue := range filterValues {
   131  			ctr, err := r.LookupContainer(filterValue)
   132  			if err != nil {
   133  				return nil, err
   134  			}
   135  			containerConfig := ctr.Config()
   136  			if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) {
   137  				createTime = containerConfig.CreatedTime
   138  			}
   139  		}
   140  		return func(c *libpod.Container) bool {
   141  			cc := c.Config()
   142  			return createTime.Before(cc.CreatedTime)
   143  		}, nil
   144  	case "volume":
   145  		//- volume=(<volume-name>|<mount-point-destination>)
   146  		return func(c *libpod.Container) bool {
   147  			containerConfig := c.Config()
   148  			var dest string
   149  			for _, filterValue := range filterValues {
   150  				arr := strings.SplitN(filterValue, ":", 2)
   151  				source := arr[0]
   152  				if len(arr) == 2 {
   153  					dest = arr[1]
   154  				}
   155  				for _, mount := range containerConfig.Spec.Mounts {
   156  					if dest != "" && (mount.Source == source && mount.Destination == dest) {
   157  						return true
   158  					}
   159  					if dest == "" && mount.Source == source {
   160  						return true
   161  					}
   162  				}
   163  				for _, vname := range containerConfig.NamedVolumes {
   164  					if dest != "" && (vname.Name == source && vname.Dest == dest) {
   165  						return true
   166  					}
   167  					if dest == "" && vname.Name == source {
   168  						return true
   169  					}
   170  				}
   171  			}
   172  			return false
   173  		}, nil
   174  	case "health":
   175  		return func(c *libpod.Container) bool {
   176  			hcStatus, err := c.HealthCheckStatus()
   177  			if err != nil {
   178  				return false
   179  			}
   180  			for _, filterValue := range filterValues {
   181  				if hcStatus == filterValue {
   182  					return true
   183  				}
   184  			}
   185  			return false
   186  		}, nil
   187  	case "until":
   188  		if len(filterValues) != 1 {
   189  			return nil, errors.Errorf("specify exactly one timestamp for %s", filter)
   190  		}
   191  		ts, err := timetype.GetTimestamp(filterValues[0], time.Now())
   192  		if err != nil {
   193  			return nil, err
   194  		}
   195  		seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
   196  		if err != nil {
   197  			return nil, err
   198  		}
   199  		until := time.Unix(seconds, nanoseconds)
   200  		return func(c *libpod.Container) bool {
   201  			if !until.IsZero() && c.CreatedTime().After((until)) {
   202  				return true
   203  			}
   204  			return false
   205  		}, nil
   206  	}
   207  	return nil, errors.Errorf("%s is an invalid filter", filter)
   208  }