cluster-autoscaler/utils/kubernetes/listers.go (241 lines of code) (raw):

/* Copyright 2016 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 kubernetes import ( "time" apiv1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/informers" client "k8s.io/client-go/kubernetes" v1appslister "k8s.io/client-go/listers/apps/v1" v1batchlister "k8s.io/client-go/listers/batch/v1" v1lister "k8s.io/client-go/listers/core/v1" v1policylister "k8s.io/client-go/listers/policy/v1" "k8s.io/client-go/tools/cache" podv1 "k8s.io/kubernetes/pkg/api/v1/pod" ) // ListerRegistry is a registry providing various listers to list pods or nodes matching conditions type ListerRegistry interface { AllNodeLister() NodeLister ReadyNodeLister() NodeLister AllPodLister() PodLister PodDisruptionBudgetLister() PodDisruptionBudgetLister DaemonSetLister() v1appslister.DaemonSetLister ReplicationControllerLister() v1lister.ReplicationControllerLister JobLister() v1batchlister.JobLister ReplicaSetLister() v1appslister.ReplicaSetLister StatefulSetLister() v1appslister.StatefulSetLister } type listerRegistryImpl struct { allNodeLister NodeLister readyNodeLister NodeLister allPodLister PodLister podDisruptionBudgetLister PodDisruptionBudgetLister daemonSetLister v1appslister.DaemonSetLister replicationControllerLister v1lister.ReplicationControllerLister jobLister v1batchlister.JobLister replicaSetLister v1appslister.ReplicaSetLister statefulSetLister v1appslister.StatefulSetLister } // NewListerRegistry returns a registry providing various listers to list pods or nodes matching conditions func NewListerRegistry(allNode NodeLister, readyNode NodeLister, allPodLister PodLister, podDisruptionBudgetLister PodDisruptionBudgetLister, daemonSetLister v1appslister.DaemonSetLister, replicationControllerLister v1lister.ReplicationControllerLister, jobLister v1batchlister.JobLister, replicaSetLister v1appslister.ReplicaSetLister, statefulSetLister v1appslister.StatefulSetLister) ListerRegistry { return listerRegistryImpl{ allNodeLister: allNode, readyNodeLister: readyNode, allPodLister: allPodLister, podDisruptionBudgetLister: podDisruptionBudgetLister, daemonSetLister: daemonSetLister, replicationControllerLister: replicationControllerLister, jobLister: jobLister, replicaSetLister: replicaSetLister, statefulSetLister: statefulSetLister, } } // NewListerRegistryWithDefaultListers returns a registry filled with listers of the default implementations func NewListerRegistryWithDefaultListers(informerFactory informers.SharedInformerFactory) ListerRegistry { allPodLister := NewAllPodLister(informerFactory.Core().V1().Pods().Lister()) readyNodeLister := NewReadyNodeLister(informerFactory.Core().V1().Nodes().Lister()) allNodeLister := NewAllNodeLister(informerFactory.Core().V1().Nodes().Lister()) podDisruptionBudgetLister := NewPodDisruptionBudgetLister(informerFactory.Policy().V1().PodDisruptionBudgets().Lister()) daemonSetLister := informerFactory.Apps().V1().DaemonSets().Lister() replicationControllerLister := informerFactory.Core().V1().ReplicationControllers().Lister() jobLister := informerFactory.Batch().V1().Jobs().Lister() replicaSetLister := informerFactory.Apps().V1().ReplicaSets().Lister() statefulSetLister := informerFactory.Apps().V1().StatefulSets().Lister() return NewListerRegistry(allNodeLister, readyNodeLister, allPodLister, podDisruptionBudgetLister, daemonSetLister, replicationControllerLister, jobLister, replicaSetLister, statefulSetLister) } // AllPodLister returns the AllPodLister registered to this registry func (r listerRegistryImpl) AllPodLister() PodLister { return r.allPodLister } // AllNodeLister returns the AllNodeLister registered to this registry func (r listerRegistryImpl) AllNodeLister() NodeLister { return r.allNodeLister } // ReadyNodeLister returns the ReadyNodeLister registered to this registry func (r listerRegistryImpl) ReadyNodeLister() NodeLister { return r.readyNodeLister } // PodDisruptionBudgetLister returns the podDisruptionBudgetLister registered to this registry func (r listerRegistryImpl) PodDisruptionBudgetLister() PodDisruptionBudgetLister { return r.podDisruptionBudgetLister } // DaemonSetLister returns the daemonSetLister registered to this registry func (r listerRegistryImpl) DaemonSetLister() v1appslister.DaemonSetLister { return r.daemonSetLister } // ReplicationControllerLister returns the replicationControllerLister registered to this registry func (r listerRegistryImpl) ReplicationControllerLister() v1lister.ReplicationControllerLister { return r.replicationControllerLister } // JobLister returns the jobLister registered to this registry func (r listerRegistryImpl) JobLister() v1batchlister.JobLister { return r.jobLister } // ReplicaSetLister returns the replicaSetLister registered to this registry func (r listerRegistryImpl) ReplicaSetLister() v1appslister.ReplicaSetLister { return r.replicaSetLister } // StatefulSetLister returns the statefulSetLister registered to this registry func (r listerRegistryImpl) StatefulSetLister() v1appslister.StatefulSetLister { return r.statefulSetLister } // PodLister lists all pods. // To filter out the scheduled or unschedulable pods the helper methods ScheduledPods and UnschedulablePods should be used. type PodLister interface { List() ([]*apiv1.Pod, error) } // isScheduled checks whether a pod is scheduled on a node or not // This method doesn't check for nil ptr, it's the responsibility of the caller func isScheduled(pod *apiv1.Pod) bool { return pod.Spec.NodeName != "" } // isDeleted checks whether a pod is deleted not // This method doesn't check for nil ptr, it's the responsibility of the caller func isDeleted(pod *apiv1.Pod) bool { return pod.GetDeletionTimestamp() != nil } // isUnschedulable checks whether a pod is unschedulable or not // This method doesn't check for nil ptr, it's the responsibility of the caller func isUnschedulable(pod *apiv1.Pod) bool { if isScheduled(pod) || isDeleted(pod) { return false } _, condition := podv1.GetPodCondition(&pod.Status, apiv1.PodScheduled) if condition == nil || condition.Status != apiv1.ConditionFalse || condition.Reason != apiv1.PodReasonUnschedulable { return false } return true } // ScheduledPods is a helper method that returns all scheduled pods from given pod list. func ScheduledPods(allPods []*apiv1.Pod) []*apiv1.Pod { var scheduledPods []*apiv1.Pod for _, pod := range allPods { if isScheduled(pod) { scheduledPods = append(scheduledPods, pod) continue } } return scheduledPods } // SchedulerUnprocessedPods is a helper method that returns all pods which are not yet processed by the specified bypassed schedulers func SchedulerUnprocessedPods(allPods []*apiv1.Pod, bypassedSchedulers map[string]bool) []*apiv1.Pod { var unprocessedPods []*apiv1.Pod for _, pod := range allPods { if canBypass := bypassedSchedulers[pod.Spec.SchedulerName]; !canBypass { continue } // Make sure it's not scheduled or deleted if isScheduled(pod) || isDeleted(pod) || isUnschedulable(pod) { continue } // Make sure that if it's not scheduled it's either // Not processed (condition is nil) // Or Reason is empty (not schedulerError, terminated, ...etc) _, condition := podv1.GetPodCondition(&pod.Status, apiv1.PodScheduled) if condition == nil || (condition.Status == apiv1.ConditionFalse && condition.Reason == "") { unprocessedPods = append(unprocessedPods, pod) } } return unprocessedPods } // UnschedulablePods is a helper method that returns all unschedulable pods from given pod list. func UnschedulablePods(allPods []*apiv1.Pod) []*apiv1.Pod { var unschedulablePods []*apiv1.Pod for _, pod := range allPods { if !isUnschedulable(pod) { continue } unschedulablePods = append(unschedulablePods, pod) } return unschedulablePods } // AllPodLister lists all pods. type AllPodLister struct { podLister v1lister.PodLister } // List returns all scheduled pods. func (lister *AllPodLister) List() ([]*apiv1.Pod, error) { var pods []*apiv1.Pod allPods, err := lister.podLister.List(labels.Everything()) if err != nil { return pods, err } for _, p := range allPods { if p.Status.Phase != apiv1.PodSucceeded && p.Status.Phase != apiv1.PodFailed { pods = append(pods, p) } } return pods, nil } // NewAllPodLister builds AllPodLister func NewAllPodLister(pl v1lister.PodLister) PodLister { return &AllPodLister{ podLister: pl, } } // NodeLister lists nodes. type NodeLister interface { List() ([]*apiv1.Node, error) Get(name string) (*apiv1.Node, error) } // nodeLister implementation. type nodeListerImpl struct { nodeLister v1lister.NodeLister filter func(*apiv1.Node) bool } // NewAllNodeLister builds a node lister that returns all nodes (ready and unready). func NewAllNodeLister(nl v1lister.NodeLister) NodeLister { return NewNodeLister(nl, nil) } // NewReadyNodeLister builds a node lister that returns only ready nodes. func NewReadyNodeLister(nl v1lister.NodeLister) NodeLister { return NewNodeLister(nl, IsNodeReadyAndSchedulable) } // NewNodeLister builds a node lister. func NewNodeLister(nl v1lister.NodeLister, filter func(*apiv1.Node) bool) NodeLister { return &nodeListerImpl{ nodeLister: nl, filter: filter, } } // List returns list of nodes. func (l *nodeListerImpl) List() ([]*apiv1.Node, error) { var nodes []*apiv1.Node var err error nodes, err = l.nodeLister.List(labels.Everything()) if err != nil { return []*apiv1.Node{}, err } if l.filter != nil { nodes = filterNodes(nodes, l.filter) } return nodes, nil } // Get returns the node with the given name. func (l *nodeListerImpl) Get(name string) (*apiv1.Node, error) { node, err := l.nodeLister.Get(name) if err != nil { return nil, err } return node, nil } func filterNodes(nodes []*apiv1.Node, predicate func(*apiv1.Node) bool) []*apiv1.Node { var filtered []*apiv1.Node for i := range nodes { if predicate(nodes[i]) { filtered = append(filtered, nodes[i]) } } return filtered } // PodDisruptionBudgetLister lists pod disruption budgets. type PodDisruptionBudgetLister interface { List() ([]*policyv1.PodDisruptionBudget, error) } // PodDisruptionBudgetListerImpl lists pod disruption budgets type PodDisruptionBudgetListerImpl struct { pdbLister v1policylister.PodDisruptionBudgetLister } // List returns all pdbs func (lister *PodDisruptionBudgetListerImpl) List() ([]*policyv1.PodDisruptionBudget, error) { return lister.pdbLister.List(labels.Everything()) } // NewPodDisruptionBudgetLister builds a pod disruption budget lister. func NewPodDisruptionBudgetLister(pdbLister v1policylister.PodDisruptionBudgetLister) PodDisruptionBudgetLister { return &PodDisruptionBudgetListerImpl{ pdbLister: pdbLister, } } // NewConfigMapListerForNamespace builds a configmap lister for the passed namespace (including all). func NewConfigMapListerForNamespace(kubeClient client.Interface, stopchannel <-chan struct{}, namespace string) v1lister.ConfigMapLister { listWatcher := cache.NewListWatchFromClient(kubeClient.CoreV1().RESTClient(), "configmaps", namespace, fields.Everything()) store, reflector := cache.NewNamespaceKeyedIndexerAndReflector(listWatcher, &apiv1.ConfigMap{}, time.Hour) lister := v1lister.NewConfigMapLister(store) go reflector.Run(stopchannel) return lister }