/
container_list.go
130 lines (119 loc) · 3.52 KB
/
container_list.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package server
import (
"time"
"github.com/cri-o/cri-o/oci"
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
"k8s.io/apimachinery/pkg/fields"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
)
// filterContainer returns whether passed container matches filtering criteria
func filterContainer(c *pb.Container, filter *pb.ContainerFilter) bool {
if filter != nil {
if filter.State != nil {
if c.State != filter.State.State {
return false
}
}
if filter.LabelSelector != nil {
sel := fields.SelectorFromSet(filter.LabelSelector)
if !sel.Matches(fields.Set(c.Labels)) {
return false
}
}
}
return true
}
// filterContainerList applies a protobuf-defined filter to retrieve only intended containers. Not matching
// the filter is not considered an error but will return an empty response.
func (s *Server) filterContainerList(filter *pb.ContainerFilter, origCtrList []*oci.Container) []*oci.Container {
// Filter using container id and pod id first.
if filter.Id != "" {
id, err := s.CtrIDIndex().Get(filter.Id)
if err != nil {
// If we don't find a container ID with a filter, it should not
// be considered an error. Log a warning and return an empty struct
logrus.Warnf("unable to find container ID %s", filter.Id)
return []*oci.Container{}
}
c := s.ContainerServer.GetContainer(id)
if c != nil {
switch {
case filter.PodSandboxId == "":
return []*oci.Container{c}
case c.Sandbox() == filter.PodSandboxId:
return []*oci.Container{c}
default:
return []*oci.Container{}
}
}
} else if filter.PodSandboxId != "" {
pod := s.ContainerServer.GetSandbox(filter.PodSandboxId)
if pod == nil {
return []*oci.Container{}
}
return pod.Containers().List()
}
logrus.Debug("no filters were applied, returning full container list")
return origCtrList
}
// ListContainers lists all containers by filters.
func (s *Server) ListContainers(ctx context.Context, req *pb.ListContainersRequest) (resp *pb.ListContainersResponse, err error) {
const operation = "list_containers"
defer func() {
recordOperation(operation, time.Now())
recordError(operation, err)
}()
logrus.Debugf("ListContainersRequest %+v", req)
var ctrs []*pb.Container
filter := req.GetFilter()
ctrList, err := s.ContainerServer.ListContainers()
if err != nil {
return nil, err
}
if filter != nil {
ctrList = s.filterContainerList(filter, ctrList)
}
for _, ctr := range ctrList {
// Skip over containers that are still being created
if !ctr.Created() {
continue
}
podSandboxID := ctr.Sandbox()
cState := ctr.StateNoLock()
created := ctr.CreatedAt().UnixNano()
rState := pb.ContainerState_CONTAINER_UNKNOWN
cID := ctr.ID()
img := &pb.ImageSpec{
Image: ctr.Image(),
}
c := &pb.Container{
Id: cID,
PodSandboxId: podSandboxID,
CreatedAt: created,
Labels: ctr.Labels(),
Metadata: ctr.Metadata(),
Annotations: ctr.Annotations(),
Image: img,
ImageRef: ctr.ImageRef(),
}
switch cState.Status {
case oci.ContainerStateCreated:
rState = pb.ContainerState_CONTAINER_CREATED
case oci.ContainerStateRunning:
rState = pb.ContainerState_CONTAINER_RUNNING
case oci.ContainerStateStopped:
rState = pb.ContainerState_CONTAINER_EXITED
}
c.State = rState
// Filter by other criteria such as state and labels.
if filterContainer(c, req.Filter) {
ctrs = append(ctrs, c)
}
}
resp = &pb.ListContainersResponse{
Containers: ctrs,
}
logrus.Debugf("ListContainersResponse: %+v", resp)
return resp, nil
}