diff --git a/pkg/controller/deployment/deployment_controller.go b/pkg/controller/deployment/deployment_controller.go index 10068fd6cd5..c2495717192 100644 --- a/pkg/controller/deployment/deployment_controller.go +++ b/pkg/controller/deployment/deployment_controller.go @@ -231,7 +231,7 @@ func (dc *DeploymentController) addReplicaSet(obj interface{}) { // getDeploymentsForReplicaSet returns a list of Deployments that potentially // match a ReplicaSet. func (dc *DeploymentController) getDeploymentsForReplicaSet(rs *apps.ReplicaSet) []*apps.Deployment { - deployments, err := dc.dLister.GetDeploymentsForReplicaSet(rs) + deployments, err := util.GetDeploymentsForReplicaSet(dc.dLister, rs) if err != nil || len(deployments) == 0 { return nil } diff --git a/pkg/controller/deployment/util/BUILD b/pkg/controller/deployment/util/BUILD index 3d9f752248b..9cf77121c5a 100644 --- a/pkg/controller/deployment/util/BUILD +++ b/pkg/controller/deployment/util/BUILD @@ -18,11 +18,13 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/apps/v1:go_default_library", + "//staging/src/k8s.io/client-go/listers/apps/v1:go_default_library", "//vendor/k8s.io/klog:go_default_library", "//vendor/k8s.io/utils/integer:go_default_library", ], @@ -46,6 +48,7 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library", "//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library", + "//staging/src/k8s.io/client-go/informers:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/client-go/testing:go_default_library", ], diff --git a/pkg/controller/deployment/util/deployment_util.go b/pkg/controller/deployment/util/deployment_util.go index 36e83f28aef..f951ea1581a 100644 --- a/pkg/controller/deployment/util/deployment_util.go +++ b/pkg/controller/deployment/util/deployment_util.go @@ -24,18 +24,19 @@ import ( "strings" "time" - "k8s.io/klog" - apps "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" intstrutil "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/wait" appsclient "k8s.io/client-go/kubernetes/typed/apps/v1" + appslisters "k8s.io/client-go/listers/apps/v1" + "k8s.io/klog" "k8s.io/kubernetes/pkg/controller" labelsutil "k8s.io/kubernetes/pkg/util/labels" "k8s.io/utils/integer" @@ -912,3 +913,38 @@ func HasProgressDeadline(d *apps.Deployment) bool { func HasRevisionHistoryLimit(d *apps.Deployment) bool { return d.Spec.RevisionHistoryLimit != nil && *d.Spec.RevisionHistoryLimit != math.MaxInt32 } + +// GetDeploymentsForReplicaSet returns a list of Deployments that potentially +// match a ReplicaSet. Only the one specified in the ReplicaSet's ControllerRef +// will actually manage it. +// Returns an error only if no matching Deployments are found. +func GetDeploymentsForReplicaSet(deploymentLister appslisters.DeploymentLister, rs *apps.ReplicaSet) ([]*apps.Deployment, error) { + if len(rs.Labels) == 0 { + return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name) + } + + // TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label + dList, err := deploymentLister.Deployments(rs.Namespace).List(labels.Everything()) + if err != nil { + return nil, err + } + + var deployments []*apps.Deployment + for _, d := range dList { + selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector) + if err != nil { + return nil, fmt.Errorf("invalid label selector: %v", err) + } + // If a deployment with a nil or empty selector creeps in, it should match nothing, not everything. + if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) { + continue + } + deployments = append(deployments, d) + } + + if len(deployments) == 0 { + return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels) + } + + return deployments, nil +} diff --git a/pkg/controller/deployment/util/deployment_util_test.go b/pkg/controller/deployment/util/deployment_util_test.go index 38fed0e4fbc..18613f072fd 100644 --- a/pkg/controller/deployment/util/deployment_util_test.go +++ b/pkg/controller/deployment/util/deployment_util_test.go @@ -34,6 +34,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apiserver/pkg/storage/names" + "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" "k8s.io/kubernetes/pkg/controller" @@ -1402,3 +1403,84 @@ func TestReplicasAnnotationsNeedUpdate(t *testing.T) { }) } } + +func TestGetDeploymentsForReplicaSet(t *testing.T) { + fakeInformerFactory := informers.NewSharedInformerFactory(&fake.Clientset{}, 0*time.Second) + var deployments []*apps.Deployment + for i := 0; i < 3; i++ { + deployment := &apps.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("deployment-%d", i), + Namespace: "test", + }, + Spec: apps.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": fmt.Sprintf("test-%d", i), + }, + }, + }, + } + deployments = append(deployments, deployment) + fakeInformerFactory.Apps().V1().Deployments().Informer().GetStore().Add(deployment) + } + var rss []*apps.ReplicaSet + for i := 0; i < 5; i++ { + rs := &apps.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: fmt.Sprintf("test-replicaSet-%d", i), + Labels: map[string]string{ + "app": fmt.Sprintf("test-%d", i), + "label": fmt.Sprintf("label-%d", i), + }, + }, + } + rss = append(rss, rs) + } + tests := []struct { + name string + rs *apps.ReplicaSet + err error + expect []*apps.Deployment + }{ + { + name: "GetDeploymentsForReplicaSet for rs-0", + rs: rss[0], + expect: []*apps.Deployment{deployments[0]}, + }, + { + name: "GetDeploymentsForReplicaSet for rs-1", + rs: rss[1], + expect: []*apps.Deployment{deployments[1]}, + }, + { + name: "GetDeploymentsForReplicaSet for rs-2", + rs: rss[2], + expect: []*apps.Deployment{deployments[2]}, + }, + { + name: "GetDeploymentsForReplicaSet for rs-3", + rs: rss[3], + err: fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rss[3].Name, rss[3].Namespace, rss[3].Labels), + }, + { + name: "GetDeploymentsForReplicaSet for rs-4", + rs: rss[4], + err: fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rss[4].Name, rss[4].Namespace, rss[4].Labels), + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + get, err := GetDeploymentsForReplicaSet(fakeInformerFactory.Apps().V1().Deployments().Lister(), test.rs) + if err != nil { + if err.Error() != test.err.Error() { + t.Errorf("Error from GetDeploymentsForReplicaSet: %v", err) + } + } else if !reflect.DeepEqual(get, test.expect) { + t.Errorf("Expect deployments %v, but got %v", test.expect, get) + } + }) + } + +} diff --git a/pkg/controller/service/BUILD b/pkg/controller/service/BUILD index bf6941e0eb0..a262265ff77 100644 --- a/pkg/controller/service/BUILD +++ b/pkg/controller/service/BUILD @@ -12,6 +12,7 @@ go_library( deps = [ "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", diff --git a/pkg/controller/service/controller.go b/pkg/controller/service/controller.go index b6908c1f446..bc0f698a781 100644 --- a/pkg/controller/service/controller.go +++ b/pkg/controller/service/controller.go @@ -26,6 +26,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -372,7 +373,7 @@ func (s *Controller) syncLoadBalancerIfNeeded(service *v1.Service, key string) ( } func (s *Controller) ensureLoadBalancer(service *v1.Service) (*v1.LoadBalancerStatus, error) { - nodes, err := s.nodeLister.ListWithPredicate(getNodeConditionPredicate()) + nodes, err := listWithPredicate(s.nodeLister, getNodeConditionPredicate()) if err != nil { return nil, err } @@ -601,7 +602,7 @@ func nodeSlicesEqualForLB(x, y []*v1.Node) bool { return nodeNames(x).Equal(nodeNames(y)) } -func getNodeConditionPredicate() corelisters.NodeConditionPredicate { +func getNodeConditionPredicate() NodeConditionPredicate { return func(node *v1.Node) bool { // We add the master to the node list, but its unschedulable. So we use this to filter // the master. @@ -645,7 +646,7 @@ func getNodeConditionPredicate() corelisters.NodeConditionPredicate { // nodeSyncLoop handles updating the hosts pointed to by all load // balancers whenever the set of nodes in the cluster changes. func (s *Controller) nodeSyncLoop() { - newHosts, err := s.nodeLister.ListWithPredicate(getNodeConditionPredicate()) + newHosts, err := listWithPredicate(s.nodeLister, getNodeConditionPredicate()) if err != nil { runtime.HandleError(fmt.Errorf("Failed to retrieve current set of nodes from node lister: %v", err)) return @@ -847,3 +848,24 @@ func (s *Controller) patchStatus(service *v1.Service, previousStatus, newStatus _, err := patch(s.kubeClient.CoreV1(), service, updated) return err } + +// NodeConditionPredicate is a function that indicates whether the given node's conditions meet +// some set of criteria defined by the function. +type NodeConditionPredicate func(node *v1.Node) bool + +// listWithPredicate gets nodes that matches predicate function. +func listWithPredicate(nodeLister corelisters.NodeLister, predicate NodeConditionPredicate) ([]*v1.Node, error) { + nodes, err := nodeLister.List(labels.Everything()) + if err != nil { + return nil, err + } + + var filtered []*v1.Node + for i := range nodes { + if predicate(nodes[i]) { + filtered = append(filtered, nodes[i]) + } + } + + return filtered, nil +} diff --git a/pkg/controller/service/controller_test.go b/pkg/controller/service/controller_test.go index 967d323e743..55ca8dde47f 100644 --- a/pkg/controller/service/controller_test.go +++ b/pkg/controller/service/controller_test.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "reflect" + "sort" "strings" "testing" "time" @@ -1428,3 +1429,67 @@ func Test_getNodeConditionPredicate(t *testing.T) { }) } } + +func TestListWithPredicate(t *testing.T) { + fakeInformerFactory := informers.NewSharedInformerFactory(&fake.Clientset{}, 0*time.Second) + var nodes []*v1.Node + for i := 0; i < 5; i++ { + var phase v1.NodePhase + if i%2 == 0 { + phase = v1.NodePending + } else { + phase = v1.NodeRunning + } + node := &v1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("node-%d", i), + }, + Status: v1.NodeStatus{ + Phase: phase, + }, + } + nodes = append(nodes, node) + fakeInformerFactory.Core().V1().Nodes().Informer().GetStore().Add(node) + } + + tests := []struct { + name string + predicate NodeConditionPredicate + expect []*v1.Node + }{ + { + name: "ListWithPredicate filter Running node", + predicate: func(node *v1.Node) bool { + return node.Status.Phase == v1.NodeRunning + }, + expect: []*v1.Node{nodes[1], nodes[3]}, + }, + { + name: "ListWithPredicate filter Pending node", + predicate: func(node *v1.Node) bool { + return node.Status.Phase == v1.NodePending + }, + expect: []*v1.Node{nodes[0], nodes[2], nodes[4]}, + }, + { + name: "ListWithPredicate filter Terminated node", + predicate: func(node *v1.Node) bool { + return node.Status.Phase == v1.NodeTerminated + }, + expect: nil, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + get, err := listWithPredicate(fakeInformerFactory.Core().V1().Nodes().Lister(), test.predicate) + sort.Slice(get, func(i, j int) bool { + return get[i].Name < get[j].Name + }) + if err != nil { + t.Errorf("Error from ListWithPredicate: %v", err) + } else if !reflect.DeepEqual(get, test.expect) { + t.Errorf("Expect nodes %v, but got %v", test.expect, get) + } + }) + } +} diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index f942cf4c2aa..02c938705a9 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -243,7 +243,6 @@ go_test( "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", - "//staging/src/k8s.io/client-go/listers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/testing:go_default_library", "//staging/src/k8s.io/client-go/tools/record:go_default_library", diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index c42b35be7e3..db1b8d1efc5 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -39,7 +39,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes/fake" - corelisters "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/record" "k8s.io/client-go/util/flowcontrol" cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing" @@ -446,10 +445,6 @@ func (nl testNodeLister) List(_ labels.Selector) (ret []*v1.Node, err error) { return nl.nodes, nil } -func (nl testNodeLister) ListWithPredicate(_ corelisters.NodeConditionPredicate) ([]*v1.Node, error) { - return nl.nodes, nil -} - func checkPodStatus(t *testing.T, kl *Kubelet, pod *v1.Pod, phase v1.PodPhase) { status, found := kl.statusManager.GetPodStatus(pod.UID) require.True(t, found, "Status of pod %q is not found in the status map", pod.UID) diff --git a/pkg/scheduler/algorithm/predicates/predicates.go b/pkg/scheduler/algorithm/predicates/predicates.go index 592dcbb6aab..48c0d6510a7 100644 --- a/pkg/scheduler/algorithm/predicates/predicates.go +++ b/pkg/scheduler/algorithm/predicates/predicates.go @@ -1003,7 +1003,7 @@ func (s *ServiceAffinity) serviceAffinityMetadataProducer(pm *predicateMetadata) return } // Store services which match the pod. - matchingPodServices, err := s.serviceLister.GetPodServices(pm.pod) + matchingPodServices, err := schedulerlisters.GetPodServices(s.serviceLister, pm.pod) if err != nil { klog.Errorf("Error precomputing service affinity: could not list services: %v", err) } diff --git a/pkg/scheduler/algorithm/priorities/metadata.go b/pkg/scheduler/algorithm/priorities/metadata.go index fa39fdb3f75..7726c45972c 100644 --- a/pkg/scheduler/algorithm/priorities/metadata.go +++ b/pkg/scheduler/algorithm/priorities/metadata.go @@ -105,7 +105,7 @@ func (pmf *MetadataFactory) PriorityMetadata( // getFirstServiceSelector returns one selector of services the given pod. func getFirstServiceSelector(pod *v1.Pod, sl corelisters.ServiceLister) (firstServiceSelector labels.Selector) { - if services, err := sl.GetPodServices(pod); err == nil && len(services) > 0 { + if services, err := schedulerlisters.GetPodServices(sl, pod); err == nil && len(services) > 0 { return labels.SelectorFromSet(services[0].Spec.Selector) } return nil @@ -117,7 +117,7 @@ func getSelector(pod *v1.Pod, sl corelisters.ServiceLister, cl corelisters.Repli // Since services, RCs, RSs and SSs match the pod, they won't have conflicting // labels. Merging is safe. - if services, err := sl.GetPodServices(pod); err == nil { + if services, err := schedulerlisters.GetPodServices(sl, pod); err == nil { for _, service := range services { labelSet = labels.Merge(labelSet, service.Spec.Selector) } diff --git a/pkg/scheduler/listers/BUILD b/pkg/scheduler/listers/BUILD index 3e8d3f4ca68..698e5f8c91a 100644 --- a/pkg/scheduler/listers/BUILD +++ b/pkg/scheduler/listers/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", @@ -9,6 +9,19 @@ go_library( "//pkg/scheduler/nodeinfo:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", + "//staging/src/k8s.io/client-go/listers/core/v1:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["listers_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/client-go/informers:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", ], ) diff --git a/pkg/scheduler/listers/fake/listers.go b/pkg/scheduler/listers/fake/listers.go index 2856f6c8bd7..567b9612ee4 100644 --- a/pkg/scheduler/listers/fake/listers.go +++ b/pkg/scheduler/listers/fake/listers.go @@ -63,7 +63,16 @@ type ServiceLister []*v1.Service // Services returns nil. func (f ServiceLister) Services(namespace string) corelisters.ServiceNamespaceLister { - return nil + var services []*v1.Service + for i := range f { + if f[i].Namespace == namespace { + services = append(services, f[i]) + } + } + return &serviceNamespaceLister{ + services: services, + namespace: namespace, + } } // List returns v1.ServiceList, the list of all services. @@ -71,22 +80,18 @@ func (f ServiceLister) List(labels.Selector) ([]*v1.Service, error) { return f, nil } -// GetPodServices gets the services that have the selector that match the labels on the given pod. -func (f ServiceLister) GetPodServices(pod *v1.Pod) (services []*v1.Service, err error) { - var selector labels.Selector +// serviceNamespaceLister is implementation of ServiceNamespaceLister returned by Services() above. +type serviceNamespaceLister struct { + services []*v1.Service + namespace string +} - for i := range f { - service := f[i] - // consider only services that are in the same namespace as the pod - if service.Namespace != pod.Namespace { - continue - } - selector = labels.Set(service.Spec.Selector).AsSelectorPreValidated() - if selector.Matches(labels.Set(pod.Labels)) { - services = append(services, service) - } - } - return +func (f *serviceNamespaceLister) Get(name string) (*v1.Service, error) { + return nil, fmt.Errorf("not implemented") +} + +func (f *serviceNamespaceLister) List(selector labels.Selector) ([]*v1.Service, error) { + return f.services, nil } var _ corelisters.ReplicationControllerLister = &ControllerLister{} diff --git a/pkg/scheduler/listers/listers.go b/pkg/scheduler/listers/listers.go index 984493f0e17..5efcbc82b29 100644 --- a/pkg/scheduler/listers/listers.go +++ b/pkg/scheduler/listers/listers.go @@ -19,6 +19,7 @@ package listers import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" + v1listers "k8s.io/client-go/listers/core/v1" schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo" ) @@ -49,3 +50,27 @@ type SharedLister interface { Pods() PodLister NodeInfos() NodeInfoLister } + +// GetPodServices gets the services that have the selector that match the labels on the given pod. +// TODO: this should be moved to ServiceAffinity plugin once that plugin is ready. +func GetPodServices(serviceLister v1listers.ServiceLister, pod *v1.Pod) ([]*v1.Service, error) { + allServices, err := serviceLister.Services(pod.Namespace).List(labels.Everything()) + if err != nil { + return nil, err + } + + var services []*v1.Service + for i := range allServices { + service := allServices[i] + if service.Spec.Selector == nil { + // services with nil selectors match nothing, not everything. + continue + } + selector := labels.Set(service.Spec.Selector).AsSelectorPreValidated() + if selector.Matches(labels.Set(pod.Labels)) { + services = append(services, service) + } + } + + return services, nil +} diff --git a/pkg/scheduler/listers/listers_test.go b/pkg/scheduler/listers/listers_test.go new file mode 100644 index 00000000000..238df6325a5 --- /dev/null +++ b/pkg/scheduler/listers/listers_test.go @@ -0,0 +1,105 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package listers + +import ( + "fmt" + "reflect" + "testing" + "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes/fake" +) + +func TestGetPodServices(t *testing.T) { + fakeInformerFactory := informers.NewSharedInformerFactory(&fake.Clientset{}, 0*time.Second) + var services []*v1.Service + for i := 0; i < 3; i++ { + service := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("service-%d", i), + Namespace: "test", + }, + Spec: v1.ServiceSpec{ + Selector: map[string]string{ + "app": fmt.Sprintf("test-%d", i), + }, + }, + } + services = append(services, service) + fakeInformerFactory.Core().V1().Services().Informer().GetStore().Add(service) + } + var pods []*v1.Pod + for i := 0; i < 5; i++ { + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: fmt.Sprintf("test-pod-%d", i), + Labels: map[string]string{ + "app": fmt.Sprintf("test-%d", i), + "label": fmt.Sprintf("label-%d", i), + }, + }, + } + pods = append(pods, pod) + } + + tests := []struct { + name string + pod *v1.Pod + expect []*v1.Service + }{ + { + name: "GetPodServices for pod-0", + pod: pods[0], + expect: []*v1.Service{services[0]}, + }, + { + name: "GetPodServices for pod-1", + pod: pods[1], + expect: []*v1.Service{services[1]}, + }, + { + name: "GetPodServices for pod-2", + pod: pods[2], + expect: []*v1.Service{services[2]}, + }, + { + name: "GetPodServices for pod-3", + pod: pods[3], + expect: nil, + }, + { + name: "GetPodServices for pod-4", + pod: pods[4], + expect: nil, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + get, err := GetPodServices(fakeInformerFactory.Core().V1().Services().Lister(), test.pod) + if err != nil { + t.Errorf("Error from GetPodServices: %v", err) + } else if !reflect.DeepEqual(get, test.expect) { + t.Errorf("Expect services %v, but got %v", test.expect, get) + } + }) + } +} diff --git a/staging/src/k8s.io/client-go/listers/apps/v1/BUILD b/staging/src/k8s.io/client-go/listers/apps/v1/BUILD index 32aaa37e7ba..a7f29ce901d 100644 --- a/staging/src/k8s.io/client-go/listers/apps/v1/BUILD +++ b/staging/src/k8s.io/client-go/listers/apps/v1/BUILD @@ -7,7 +7,6 @@ go_library( "daemonset.go", "daemonset_expansion.go", "deployment.go", - "deployment_expansion.go", "expansion_generated.go", "replicaset.go", "replicaset_expansion.go", diff --git a/staging/src/k8s.io/client-go/listers/apps/v1/deployment_expansion.go b/staging/src/k8s.io/client-go/listers/apps/v1/deployment_expansion.go deleted file mode 100644 index 7802eca5a5e..00000000000 --- a/staging/src/k8s.io/client-go/listers/apps/v1/deployment_expansion.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "fmt" - - apps "k8s.io/api/apps/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" -) - -// DeploymentListerExpansion allows custom methods to be added to -// DeploymentLister. -type DeploymentListerExpansion interface { - GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error) -} - -// DeploymentNamespaceListerExpansion allows custom methods to be added to -// DeploymentNamespaceLister. -type DeploymentNamespaceListerExpansion interface{} - -// GetDeploymentsForReplicaSet returns a list of Deployments that potentially -// match a ReplicaSet. Only the one specified in the ReplicaSet's ControllerRef -// will actually manage it. -// Returns an error only if no matching Deployments are found. -func (s *deploymentLister) GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error) { - if len(rs.Labels) == 0 { - return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name) - } - - // TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label - dList, err := s.Deployments(rs.Namespace).List(labels.Everything()) - if err != nil { - return nil, err - } - - var deployments []*apps.Deployment - for _, d := range dList { - selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector) - if err != nil { - return nil, fmt.Errorf("invalid label selector: %v", err) - } - // If a deployment with a nil or empty selector creeps in, it should match nothing, not everything. - if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) { - continue - } - deployments = append(deployments, d) - } - - if len(deployments) == 0 { - return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels) - } - - return deployments, nil -} diff --git a/staging/src/k8s.io/client-go/listers/apps/v1/expansion_generated.go b/staging/src/k8s.io/client-go/listers/apps/v1/expansion_generated.go index 7f5815f79d5..0c357589d07 100644 --- a/staging/src/k8s.io/client-go/listers/apps/v1/expansion_generated.go +++ b/staging/src/k8s.io/client-go/listers/apps/v1/expansion_generated.go @@ -25,3 +25,11 @@ type ControllerRevisionListerExpansion interface{} // ControllerRevisionNamespaceListerExpansion allows custom methods to be added to // ControllerRevisionNamespaceLister. type ControllerRevisionNamespaceListerExpansion interface{} + +// DeploymentListerExpansion allows custom methods to be added to +// DeploymentLister. +type DeploymentListerExpansion interface{} + +// DeploymentNamespaceListerExpansion allows custom methods to be added to +// DeploymentNamespaceLister. +type DeploymentNamespaceListerExpansion interface{} diff --git a/staging/src/k8s.io/client-go/listers/apps/v1beta2/BUILD b/staging/src/k8s.io/client-go/listers/apps/v1beta2/BUILD index cbef24da637..fb8e5680b8f 100644 --- a/staging/src/k8s.io/client-go/listers/apps/v1beta2/BUILD +++ b/staging/src/k8s.io/client-go/listers/apps/v1beta2/BUILD @@ -12,7 +12,6 @@ go_library( "daemonset.go", "daemonset_expansion.go", "deployment.go", - "deployment_expansion.go", "expansion_generated.go", "replicaset.go", "replicaset_expansion.go", diff --git a/staging/src/k8s.io/client-go/listers/apps/v1beta2/deployment_expansion.go b/staging/src/k8s.io/client-go/listers/apps/v1beta2/deployment_expansion.go deleted file mode 100644 index 1537167a0df..00000000000 --- a/staging/src/k8s.io/client-go/listers/apps/v1beta2/deployment_expansion.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1beta2 - -import ( - "fmt" - - apps "k8s.io/api/apps/v1beta2" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" -) - -// DeploymentListerExpansion allows custom methods to be added to -// DeploymentLister. -type DeploymentListerExpansion interface { - GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error) -} - -// DeploymentNamespaceListerExpansion allows custom methods to be added to -// DeploymentNamespaceLister. -type DeploymentNamespaceListerExpansion interface{} - -// GetDeploymentsForReplicaSet returns a list of Deployments that potentially -// match a ReplicaSet. Only the one specified in the ReplicaSet's ControllerRef -// will actually manage it. -// Returns an error only if no matching Deployments are found. -func (s *deploymentLister) GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error) { - if len(rs.Labels) == 0 { - return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name) - } - - // TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label - dList, err := s.Deployments(rs.Namespace).List(labels.Everything()) - if err != nil { - return nil, err - } - - var deployments []*apps.Deployment - for _, d := range dList { - selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector) - if err != nil { - return nil, fmt.Errorf("invalid label selector: %v", err) - } - // If a deployment with a nil or empty selector creeps in, it should match nothing, not everything. - if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) { - continue - } - deployments = append(deployments, d) - } - - if len(deployments) == 0 { - return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels) - } - - return deployments, nil -} diff --git a/staging/src/k8s.io/client-go/listers/apps/v1beta2/expansion_generated.go b/staging/src/k8s.io/client-go/listers/apps/v1beta2/expansion_generated.go index bac6ccb9a7a..b6d202118ed 100644 --- a/staging/src/k8s.io/client-go/listers/apps/v1beta2/expansion_generated.go +++ b/staging/src/k8s.io/client-go/listers/apps/v1beta2/expansion_generated.go @@ -25,3 +25,11 @@ type ControllerRevisionListerExpansion interface{} // ControllerRevisionNamespaceListerExpansion allows custom methods to be added to // ControllerRevisionNamespaceLister. type ControllerRevisionNamespaceListerExpansion interface{} + +// DeploymentListerExpansion allows custom methods to be added to +// DeploymentLister. +type DeploymentListerExpansion interface{} + +// DeploymentNamespaceListerExpansion allows custom methods to be added to +// DeploymentNamespaceLister. +type DeploymentNamespaceListerExpansion interface{} diff --git a/staging/src/k8s.io/client-go/listers/core/v1/BUILD b/staging/src/k8s.io/client-go/listers/core/v1/BUILD index 458cd280227..3ceba86612b 100644 --- a/staging/src/k8s.io/client-go/listers/core/v1/BUILD +++ b/staging/src/k8s.io/client-go/listers/core/v1/BUILD @@ -16,7 +16,6 @@ go_library( "limitrange.go", "namespace.go", "node.go", - "node_expansion.go", "persistentvolume.go", "persistentvolumeclaim.go", "pod.go", @@ -26,7 +25,6 @@ go_library( "resourcequota.go", "secret.go", "service.go", - "service_expansion.go", "serviceaccount.go", ], importmap = "k8s.io/kubernetes/vendor/k8s.io/client-go/listers/core/v1", diff --git a/staging/src/k8s.io/client-go/listers/core/v1/expansion_generated.go b/staging/src/k8s.io/client-go/listers/core/v1/expansion_generated.go index fac0221b88e..2168a7f4834 100644 --- a/staging/src/k8s.io/client-go/listers/core/v1/expansion_generated.go +++ b/staging/src/k8s.io/client-go/listers/core/v1/expansion_generated.go @@ -58,6 +58,10 @@ type LimitRangeNamespaceListerExpansion interface{} // NamespaceLister. type NamespaceListerExpansion interface{} +// NodeListerExpansion allows custom methods to be added to +// NodeLister. +type NodeListerExpansion interface{} + // PersistentVolumeListerExpansion allows custom methods to be added to // PersistentVolumeLister. type PersistentVolumeListerExpansion interface{} @@ -102,6 +106,14 @@ type SecretListerExpansion interface{} // SecretNamespaceLister. type SecretNamespaceListerExpansion interface{} +// ServiceListerExpansion allows custom methods to be added to +// ServiceLister. +type ServiceListerExpansion interface{} + +// ServiceNamespaceListerExpansion allows custom methods to be added to +// ServiceNamespaceLister. +type ServiceNamespaceListerExpansion interface{} + // ServiceAccountListerExpansion allows custom methods to be added to // ServiceAccountLister. type ServiceAccountListerExpansion interface{} diff --git a/staging/src/k8s.io/client-go/listers/core/v1/node_expansion.go b/staging/src/k8s.io/client-go/listers/core/v1/node_expansion.go deleted file mode 100644 index 9e5c55ab35e..00000000000 --- a/staging/src/k8s.io/client-go/listers/core/v1/node_expansion.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/labels" -) - -// NodeConditionPredicate is a function that indicates whether the given node's conditions meet -// some set of criteria defined by the function. -type NodeConditionPredicate func(node *v1.Node) bool - -// NodeListerExpansion allows custom methods to be added to -// NodeLister. -type NodeListerExpansion interface { - ListWithPredicate(predicate NodeConditionPredicate) ([]*v1.Node, error) -} - -func (l *nodeLister) ListWithPredicate(predicate NodeConditionPredicate) ([]*v1.Node, error) { - nodes, err := l.List(labels.Everything()) - if err != nil { - return nil, err - } - - var filtered []*v1.Node - for i := range nodes { - if predicate(nodes[i]) { - filtered = append(filtered, nodes[i]) - } - } - - return filtered, nil -} diff --git a/staging/src/k8s.io/client-go/listers/core/v1/service_expansion.go b/staging/src/k8s.io/client-go/listers/core/v1/service_expansion.go deleted file mode 100644 index e283d2509dc..00000000000 --- a/staging/src/k8s.io/client-go/listers/core/v1/service_expansion.go +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/labels" -) - -// ServiceListerExpansion allows custom methods to be added to -// ServiceLister. -type ServiceListerExpansion interface { - GetPodServices(pod *v1.Pod) ([]*v1.Service, error) -} - -// ServiceNamespaceListerExpansion allows custom methods to be added to -// ServiceNamespaceLister. -type ServiceNamespaceListerExpansion interface{} - -// TODO: Move this back to scheduler as a helper function that takes a Store, -// rather than a method of ServiceLister. -func (s *serviceLister) GetPodServices(pod *v1.Pod) ([]*v1.Service, error) { - allServices, err := s.Services(pod.Namespace).List(labels.Everything()) - if err != nil { - return nil, err - } - - var services []*v1.Service - for i := range allServices { - service := allServices[i] - if service.Spec.Selector == nil { - // services with nil selectors match nothing, not everything. - continue - } - selector := labels.Set(service.Spec.Selector).AsSelectorPreValidated() - if selector.Matches(labels.Set(pod.Labels)) { - services = append(services, service) - } - } - - return services, nil -} diff --git a/staging/src/k8s.io/client-go/listers/extensions/v1beta1/BUILD b/staging/src/k8s.io/client-go/listers/extensions/v1beta1/BUILD index 98f2e254740..853979b42a4 100644 --- a/staging/src/k8s.io/client-go/listers/extensions/v1beta1/BUILD +++ b/staging/src/k8s.io/client-go/listers/extensions/v1beta1/BUILD @@ -12,7 +12,6 @@ go_library( "daemonset.go", "daemonset_expansion.go", "deployment.go", - "deployment_expansion.go", "expansion_generated.go", "ingress.go", "networkpolicy.go", diff --git a/staging/src/k8s.io/client-go/listers/extensions/v1beta1/deployment_expansion.go b/staging/src/k8s.io/client-go/listers/extensions/v1beta1/deployment_expansion.go deleted file mode 100644 index b9a14167e0e..00000000000 --- a/staging/src/k8s.io/client-go/listers/extensions/v1beta1/deployment_expansion.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1beta1 - -import ( - "fmt" - - extensions "k8s.io/api/extensions/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" -) - -// DeploymentListerExpansion allows custom methods to be added to -// DeploymentLister. -type DeploymentListerExpansion interface { - GetDeploymentsForReplicaSet(rs *extensions.ReplicaSet) ([]*extensions.Deployment, error) -} - -// DeploymentNamespaceListerExpansion allows custom methods to be added to -// DeploymentNamespaceLister. -type DeploymentNamespaceListerExpansion interface{} - -// GetDeploymentsForReplicaSet returns a list of Deployments that potentially -// match a ReplicaSet. Only the one specified in the ReplicaSet's ControllerRef -// will actually manage it. -// Returns an error only if no matching Deployments are found. -func (s *deploymentLister) GetDeploymentsForReplicaSet(rs *extensions.ReplicaSet) ([]*extensions.Deployment, error) { - if len(rs.Labels) == 0 { - return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name) - } - - // TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label - dList, err := s.Deployments(rs.Namespace).List(labels.Everything()) - if err != nil { - return nil, err - } - - var deployments []*extensions.Deployment - for _, d := range dList { - selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector) - if err != nil { - return nil, fmt.Errorf("invalid label selector: %v", err) - } - // If a deployment with a nil or empty selector creeps in, it should match nothing, not everything. - if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) { - continue - } - deployments = append(deployments, d) - } - - if len(deployments) == 0 { - return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels) - } - - return deployments, nil -} diff --git a/staging/src/k8s.io/client-go/listers/extensions/v1beta1/expansion_generated.go b/staging/src/k8s.io/client-go/listers/extensions/v1beta1/expansion_generated.go index 6d55ae9b8b7..5599219d9e5 100644 --- a/staging/src/k8s.io/client-go/listers/extensions/v1beta1/expansion_generated.go +++ b/staging/src/k8s.io/client-go/listers/extensions/v1beta1/expansion_generated.go @@ -18,6 +18,14 @@ limitations under the License. package v1beta1 +// DeploymentListerExpansion allows custom methods to be added to +// DeploymentLister. +type DeploymentListerExpansion interface{} + +// DeploymentNamespaceListerExpansion allows custom methods to be added to +// DeploymentNamespaceLister. +type DeploymentNamespaceListerExpansion interface{} + // IngressListerExpansion allows custom methods to be added to // IngressLister. type IngressListerExpansion interface{}