diff --git a/controller/api/public/grpc_server.go b/controller/api/public/grpc_server.go index dd953b7d3..e74a9f764 100644 --- a/controller/api/public/grpc_server.go +++ b/controller/api/public/grpc_server.go @@ -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) { 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 // report from that instance and its process start time 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") } + 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 := "" namespace := "" if req.GetNamespace() != "" { namespace = req.GetNamespace() - } else if req.GetSelector().GetResource().GetNamespace() != "" { - namespace = req.GetSelector().GetResource().GetNamespace() - } else if req.GetSelector().GetResource().GetType() == pkgK8s.Namespace { - namespace = req.GetSelector().GetResource().GetName() + } else if targetOwner.GetNamespace() != "" { + namespace = targetOwner.GetNamespace() + } else if targetOwner.GetType() == pkgK8s.Namespace { + namespace = targetOwner.GetName() } if 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 if namespace != "" { - pods, err = s.k8sAPI.Pod().Lister().Pods(namespace).List(labels.Everything()) + pods, err = s.k8sAPI.Pod().Lister().Pods(namespace).List(labelSelector) } else { - pods, err = s.k8sAPI.Pod().Lister().List(labels.Everything()) + pods, err = s.k8sAPI.Pod().Lister().List(labelSelector) } if err != nil { @@ -126,6 +137,18 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb 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] status := string(pod.Status.Phase) @@ -162,7 +185,6 @@ func (s *grpcServer) ListPods(ctx context.Context, req *pb.ListPodsRequest) (*pb ProxyVersion: proxyVersion, } - ownerKind, ownerName := s.k8sAPI.GetOwnerKindAndName(pod) namespacedOwnerName := pod.Namespace + "/" + ownerName switch ownerKind { diff --git a/controller/api/public/grpc_server_test.go b/controller/api/public/grpc_server_test.go index feeb95d98..ff752cb82 100644 --- a/controller/api/public/grpc_server_test.go +++ b/controller/api/public/grpc_server_test.go @@ -227,6 +227,166 @@ spec: res: &pb.ListPodsResponse{}, 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 {