github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/shared/pod.go (about) 1 package shared 2 3 import ( 4 "strconv" 5 "strings" 6 7 "github.com/containers/libpod/libpod" 8 "github.com/containers/libpod/libpod/define" 9 "github.com/containers/libpod/pkg/util" 10 "github.com/cri-o/ocicni/pkg/ocicni" 11 "github.com/docker/go-connections/nat" 12 "github.com/pkg/errors" 13 ) 14 15 // TODO GetPodStatus and CreatePodStatusResults should removed once the adapter 16 // and shared packages are reworked. It has now been duplicated in libpod proper. 17 18 // GetPodStatus determines the status of the pod based on the 19 // statuses of the containers in the pod. 20 // Returns a string representation of the pod status 21 func GetPodStatus(pod *libpod.Pod) (string, error) { 22 ctrStatuses, err := pod.Status() 23 if err != nil { 24 return define.PodStateErrored, err 25 } 26 return CreatePodStatusResults(ctrStatuses) 27 } 28 29 func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) { 30 ctrNum := len(ctrStatuses) 31 if ctrNum == 0 { 32 return define.PodStateCreated, nil 33 } 34 statuses := map[string]int{ 35 define.PodStateStopped: 0, 36 define.PodStateRunning: 0, 37 define.PodStatePaused: 0, 38 define.PodStateCreated: 0, 39 define.PodStateErrored: 0, 40 } 41 for _, ctrStatus := range ctrStatuses { 42 switch ctrStatus { 43 case define.ContainerStateExited: 44 fallthrough 45 case define.ContainerStateStopped: 46 statuses[define.PodStateStopped]++ 47 case define.ContainerStateRunning: 48 statuses[define.PodStateRunning]++ 49 case define.ContainerStatePaused: 50 statuses[define.PodStatePaused]++ 51 case define.ContainerStateCreated, define.ContainerStateConfigured: 52 statuses[define.PodStateCreated]++ 53 default: 54 statuses[define.PodStateErrored]++ 55 } 56 } 57 58 switch { 59 case statuses[define.PodStateRunning] > 0: 60 return define.PodStateRunning, nil 61 case statuses[define.PodStatePaused] == ctrNum: 62 return define.PodStatePaused, nil 63 case statuses[define.PodStateStopped] == ctrNum: 64 return define.PodStateExited, nil 65 case statuses[define.PodStateStopped] > 0: 66 return define.PodStateStopped, nil 67 case statuses[define.PodStateErrored] > 0: 68 return define.PodStateErrored, nil 69 default: 70 return define.PodStateCreated, nil 71 } 72 } 73 74 // GetNamespaceOptions transforms a slice of kernel namespaces 75 // into a slice of pod create options. Currently, not all 76 // kernel namespaces are supported, and they will be returned in an error 77 func GetNamespaceOptions(ns []string) ([]libpod.PodCreateOption, error) { 78 var options []libpod.PodCreateOption 79 var erroredOptions []libpod.PodCreateOption 80 for _, toShare := range ns { 81 switch toShare { 82 case "cgroup": 83 options = append(options, libpod.WithPodCgroups()) 84 case "net": 85 options = append(options, libpod.WithPodNet()) 86 case "mnt": 87 return erroredOptions, errors.Errorf("Mount sharing functionality not supported on pod level") 88 case "pid": 89 options = append(options, libpod.WithPodPID()) 90 case "user": 91 return erroredOptions, errors.Errorf("User sharing functionality not supported on pod level") 92 case "ipc": 93 options = append(options, libpod.WithPodIPC()) 94 case "uts": 95 options = append(options, libpod.WithPodUTS()) 96 case "": 97 case "none": 98 return erroredOptions, nil 99 default: 100 return erroredOptions, errors.Errorf("Invalid kernel namespace to share: %s. Options are: net, pid, ipc, uts or none", toShare) 101 } 102 } 103 return options, nil 104 } 105 106 // CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands 107 func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) { 108 var portBindings []ocicni.PortMapping 109 // The conversion from []string to natBindings is temporary while mheon reworks the port 110 // deduplication code. Eventually that step will not be required. 111 _, natBindings, err := nat.ParsePortSpecs(ports) 112 if err != nil { 113 return nil, err 114 } 115 for containerPb, hostPb := range natBindings { 116 var pm ocicni.PortMapping 117 pm.ContainerPort = int32(containerPb.Int()) 118 for _, i := range hostPb { 119 var hostPort int 120 var err error 121 pm.HostIP = i.HostIP 122 if i.HostPort == "" { 123 hostPort = containerPb.Int() 124 } else { 125 hostPort, err = strconv.Atoi(i.HostPort) 126 if err != nil { 127 return nil, errors.Wrapf(err, "unable to convert host port to integer") 128 } 129 } 130 131 pm.HostPort = int32(hostPort) 132 pm.Protocol = containerPb.Proto() 133 portBindings = append(portBindings, pm) 134 } 135 } 136 return portBindings, nil 137 } 138 139 // GetPodsWithFilters uses the cliconfig to categorize if the latest pod is required. 140 func GetPodsWithFilters(r *libpod.Runtime, filters string) ([]*libpod.Pod, error) { 141 filterFuncs, err := GenerateFilterFunction(r, strings.Split(filters, ",")) 142 if err != nil { 143 return nil, err 144 } 145 return FilterAllPodsWithFilterFunc(r, filterFuncs...) 146 } 147 148 // FilterAllPodsWithFilterFunc retrieves all pods 149 // Filters can be provided which will determine which pods are included in the 150 // output. Multiple filters are handled by ANDing their output, so only pods 151 // matching all filters are returned 152 func FilterAllPodsWithFilterFunc(r *libpod.Runtime, filters ...libpod.PodFilter) ([]*libpod.Pod, error) { 153 pods, err := r.Pods(filters...) 154 if err != nil { 155 return nil, err 156 } 157 return pods, nil 158 } 159 160 // GenerateFilterFunction basically gets the filters based on the input by the user 161 // and filter the pod list based on the criteria. 162 func GenerateFilterFunction(r *libpod.Runtime, filters []string) ([]libpod.PodFilter, error) { 163 var filterFuncs []libpod.PodFilter 164 for _, f := range filters { 165 filterSplit := strings.SplitN(f, "=", 2) 166 if len(filterSplit) < 2 { 167 return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) 168 } 169 generatedFunc, err := generatePodFilterFuncs(filterSplit[0], filterSplit[1]) 170 if err != nil { 171 return nil, errors.Wrapf(err, "invalid filter") 172 } 173 filterFuncs = append(filterFuncs, generatedFunc) 174 } 175 176 return filterFuncs, nil 177 } 178 func generatePodFilterFuncs(filter, filterValue string) ( 179 func(pod *libpod.Pod) bool, error) { 180 switch filter { 181 case "ctr-ids": 182 return func(p *libpod.Pod) bool { 183 ctrIds, err := p.AllContainersByID() 184 if err != nil { 185 return false 186 } 187 return util.StringInSlice(filterValue, ctrIds) 188 }, nil 189 case "ctr-names": 190 return func(p *libpod.Pod) bool { 191 ctrs, err := p.AllContainers() 192 if err != nil { 193 return false 194 } 195 for _, ctr := range ctrs { 196 if filterValue == ctr.Name() { 197 return true 198 } 199 } 200 return false 201 }, nil 202 case "ctr-number": 203 return func(p *libpod.Pod) bool { 204 ctrIds, err := p.AllContainersByID() 205 if err != nil { 206 return false 207 } 208 209 fVint, err2 := strconv.Atoi(filterValue) 210 if err2 != nil { 211 return false 212 } 213 return len(ctrIds) == fVint 214 }, nil 215 case "ctr-status": 216 if !util.StringInSlice(filterValue, 217 []string{"created", "restarting", "running", "paused", 218 "exited", "unknown"}) { 219 return nil, errors.Errorf("%s is not a valid status", filterValue) 220 } 221 return func(p *libpod.Pod) bool { 222 ctr_statuses, err := p.Status() 223 if err != nil { 224 return false 225 } 226 for _, ctr_status := range ctr_statuses { 227 state := ctr_status.String() 228 if ctr_status == define.ContainerStateConfigured { 229 state = "created" 230 } 231 if state == filterValue { 232 return true 233 } 234 } 235 return false 236 }, nil 237 case "id": 238 return func(p *libpod.Pod) bool { 239 return strings.Contains(p.ID(), filterValue) 240 }, nil 241 case "name": 242 return func(p *libpod.Pod) bool { 243 return strings.Contains(p.Name(), filterValue) 244 }, nil 245 case "status": 246 if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created"}) { 247 return nil, errors.Errorf("%s is not a valid pod status", filterValue) 248 } 249 return func(p *libpod.Pod) bool { 250 status, err := p.GetPodStatus() 251 if err != nil { 252 return false 253 } 254 if strings.ToLower(status) == filterValue { 255 return true 256 } 257 return false 258 }, nil 259 case "label": 260 var filterArray = strings.SplitN(filterValue, "=", 2) 261 var filterKey = filterArray[0] 262 if len(filterArray) > 1 { 263 filterValue = filterArray[1] 264 } else { 265 filterValue = "" 266 } 267 return func(p *libpod.Pod) bool { 268 for labelKey, labelValue := range p.Labels() { 269 if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) { 270 return true 271 } 272 } 273 return false 274 }, nil 275 } 276 return nil, errors.Errorf("%s is an invalid filter", filter) 277 } 278 279 var DefaultKernelNamespaces = "cgroup,ipc,net,uts"