Add possibility to filter by owner and label in ListPods (#2161)

Signed-off-by: Alena Varkockova <varkockova.a@gmail.com>
This commit is contained in:
Alena Varkockova 2019-01-29 03:50:29 +01:00 committed by Kevin Lingerfelt
parent ea61630f9d
commit 2691dda5ce
2 changed files with 189 additions and 7 deletions

View File

@ -72,6 +72,8 @@ func (*grpcServer) Version(ctx context.Context, req *pb.Empty) (*pb.VersionInfo,
func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb.ListPodsResponse, error) { func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb.ListPodsResponse, error) {
log.Debugf("ListPods request: %+v", req) log.Debugf("ListPods request: %+v", req)
targetOwner := req.GetSelector().GetResource()
// Reports is a map from instance name to the absolute time of the most recent // Reports is a map from instance name to the absolute time of the most recent
// report from that instance and its process start time // report from that instance and its process start time
reports := make(map[string]podReport) reports := make(map[string]podReport)
@ -80,14 +82,23 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb
return nil, errors.New("cannot set both namespace and resource in the request. These are mutually exclusive") return nil, errors.New("cannot set both namespace and resource in the request. These are mutually exclusive")
} }
labelSelector := labels.Everything()
if s := req.GetSelector().GetLabelSelector(); s != "" {
var err error
labelSelector, err = labels.Parse(s)
if err != nil {
return nil, fmt.Errorf("invalid label selector \"%s\": %s", s, err)
}
}
nsQuery := "" nsQuery := ""
namespace := "" namespace := ""
if req.GetNamespace() != "" { if req.GetNamespace() != "" {
namespace = req.GetNamespace() namespace = req.GetNamespace()
} else if req.GetSelector().GetResource().GetNamespace() != "" { } else if targetOwner.GetNamespace() != "" {
namespace = req.GetSelector().GetResource().GetNamespace() namespace = targetOwner.GetNamespace()
} else if req.GetSelector().GetResource().GetType() == pkgK8s.Namespace { } else if targetOwner.GetType() == pkgK8s.Namespace {
namespace = req.GetSelector().GetResource().GetName() namespace = targetOwner.GetName()
} }
if namespace != "" { if namespace != "" {
nsQuery = fmt.Sprintf("namespace=\"%s\"", namespace) nsQuery = fmt.Sprintf("namespace=\"%s\"", namespace)
@ -111,9 +122,9 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb
var pods []*k8sV1.Pod var pods []*k8sV1.Pod
if namespace != "" { if namespace != "" {
pods, err = s.k8sAPI.Pod().Lister().Pods(namespace).List(labels.Everything()) pods, err = s.k8sAPI.Pod().Lister().Pods(namespace).List(labelSelector)
} else { } else {
pods, err = s.k8sAPI.Pod().Lister().List(labels.Everything()) pods, err = s.k8sAPI.Pod().Lister().List(labelSelector)
} }
if err != nil { if err != nil {
@ -126,6 +137,18 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb
continue continue
} }
ownerKind, ownerName := s.k8sAPI.GetOwnerKindAndName(pod)
// filter out pods without matching owner
if targetOwner.GetNamespace() != "" && targetOwner.GetNamespace() != pod.GetNamespace() {
continue
}
if targetOwner.GetType() != "" && targetOwner.GetType() != ownerKind {
continue
}
if targetOwner.GetName() != "" && targetOwner.GetName() != ownerName {
continue
}
updated, added := reports[pod.Name] updated, added := reports[pod.Name]
status := string(pod.Status.Phase) status := string(pod.Status.Phase)
@ -162,7 +185,6 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb
ProxyVersion: proxyVersion, ProxyVersion: proxyVersion,
} }
ownerKind, ownerName := s.k8sAPI.GetOwnerKindAndName(pod)
namespacedOwnerName := pod.Namespace + "/" + ownerName namespacedOwnerName := pod.Namespace + "/" + ownerName
switch ownerKind { switch ownerKind {

View File

@ -227,6 +227,166 @@ spec:
res: &pb.ListPodsResponse{}, res: &pb.ListPodsResponse{},
promReqNamespace: "testnamespace", promReqNamespace: "testnamespace",
}, },
// non-matching owner type -> no pod in the result
listPodsExpected{
err: nil,
promRes: model.Vector{
&model.Sample{
Metric: model.Metric{"pod": "emojivoto-meshed"},
Timestamp: 456,
},
},
k8sRes: []string{`
apiVersion: v1
kind: Pod
metadata:
name: emojivoto-meshed
namespace: emojivoto
labels:
pod-template-hash: hash-meshed
ownerReferences:
- apiVersion: extensions/v1beta1
kind: Deployment
name: meshed-deployment
status:
phase: Running
podIP: 1.2.3.4
`,
},
req: &pb.ListPodsRequest{
Selector: &pb.ResourceSelection{
Resource: &pb.Resource{
Type: pkgK8s.Pod,
Name: "non-existing-pod",
},
},
},
res: &pb.ListPodsResponse{},
},
// matching owner type -> pod is part of the result
listPodsExpected{
err: nil,
promRes: model.Vector{
&model.Sample{
Metric: model.Metric{"pod": "emojivoto-meshed"},
Timestamp: 456,
},
},
k8sRes: []string{`
apiVersion: v1
kind: Pod
metadata:
name: emojivoto-meshed
namespace: emojivoto
labels:
pod-template-hash: hash-meshed
ownerReferences:
- apiVersion: extensions/v1beta1
kind: Deployment
name: meshed-deployment
status:
phase: Running
podIP: 1.2.3.4
`,
},
req: &pb.ListPodsRequest{
Selector: &pb.ResourceSelection{
Resource: &pb.Resource{
Type: pkgK8s.Deployment,
Name: "meshed-deployment",
},
},
},
res: &pb.ListPodsResponse{
Pods: []*pb.Pod{
&pb.Pod{
Name: "emojivoto/emojivoto-meshed",
Added: true,
SinceLastReport: &duration.Duration{},
Status: "Running",
PodIP: "1.2.3.4",
Owner: &pb.Pod_Deployment{Deployment: "emojivoto/meshed-deployment"},
},
},
},
},
// matching label in request -> pod is in the response
listPodsExpected{
err: nil,
promRes: model.Vector{
&model.Sample{
Metric: model.Metric{"pod": "emojivoto-meshed"},
Timestamp: 456,
},
},
k8sRes: []string{`
apiVersion: v1
kind: Pod
metadata:
name: emojivoto-meshed
namespace: emojivoto
labels:
pod-template-hash: hash-meshed
ownerReferences:
- apiVersion: extensions/v1beta1
kind: Deployment
name: meshed-deployment
status:
phase: Running
podIP: 1.2.3.4
`,
},
req: &pb.ListPodsRequest{
Selector: &pb.ResourceSelection{
LabelSelector: "pod-template-hash=hash-meshed",
},
},
res: &pb.ListPodsResponse{
Pods: []*pb.Pod{
&pb.Pod{
Name: "emojivoto/emojivoto-meshed",
Added: true,
SinceLastReport: &duration.Duration{},
Status: "Running",
PodIP: "1.2.3.4",
Owner: &pb.Pod_Deployment{Deployment: "emojivoto/meshed-deployment"},
},
},
},
},
// NOT matching label in request -> pod is NOT in the response
listPodsExpected{
err: nil,
promRes: model.Vector{
&model.Sample{
Metric: model.Metric{"pod": "emojivoto-meshed"},
Timestamp: 456,
},
},
k8sRes: []string{`
apiVersion: v1
kind: Pod
metadata:
name: emojivoto-meshed
namespace: emojivoto
labels:
pod-template-hash: hash-meshed
ownerReferences:
- apiVersion: extensions/v1beta1
kind: Deployment
name: meshed-deployment
status:
phase: Running
podIP: 1.2.3.4
`,
},
req: &pb.ListPodsRequest{
Selector: &pb.ResourceSelection{
LabelSelector: "non-existent-label=value",
},
},
res: &pb.ListPodsResponse{},
},
} }
for _, exp := range expectations { for _, exp := range expectations {