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 }