volcano.sh/volcano@v1.9.0/pkg/controllers/podgroup/pg_controller.go (about)

     1  /*
     2  Copyright 2019 The Volcano Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package podgroup
    18  
    19  import (
    20  	"k8s.io/apimachinery/pkg/util/wait"
    21  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    22  	"k8s.io/client-go/informers"
    23  	appinformers "k8s.io/client-go/informers/apps/v1"
    24  	coreinformers "k8s.io/client-go/informers/core/v1"
    25  	"k8s.io/client-go/kubernetes"
    26  	corelisters "k8s.io/client-go/listers/core/v1"
    27  	"k8s.io/client-go/tools/cache"
    28  	"k8s.io/client-go/util/workqueue"
    29  	"k8s.io/klog/v2"
    30  
    31  	scheduling "volcano.sh/apis/pkg/apis/scheduling/v1beta1"
    32  	vcclientset "volcano.sh/apis/pkg/client/clientset/versioned"
    33  	informerfactory "volcano.sh/apis/pkg/client/informers/externalversions"
    34  	vcinformer "volcano.sh/apis/pkg/client/informers/externalversions"
    35  	schedulinginformer "volcano.sh/apis/pkg/client/informers/externalversions/scheduling/v1beta1"
    36  	schedulinglister "volcano.sh/apis/pkg/client/listers/scheduling/v1beta1"
    37  	"volcano.sh/volcano/pkg/controllers/framework"
    38  	"volcano.sh/volcano/pkg/features"
    39  	commonutil "volcano.sh/volcano/pkg/util"
    40  )
    41  
    42  func init() {
    43  	framework.RegisterController(&pgcontroller{})
    44  }
    45  
    46  // pgcontroller the Podgroup pgcontroller type.
    47  type pgcontroller struct {
    48  	kubeClient kubernetes.Interface
    49  	vcClient   vcclientset.Interface
    50  
    51  	podInformer coreinformers.PodInformer
    52  	pgInformer  schedulinginformer.PodGroupInformer
    53  	rsInformer  appinformers.ReplicaSetInformer
    54  
    55  	informerFactory   informers.SharedInformerFactory
    56  	vcInformerFactory vcinformer.SharedInformerFactory
    57  
    58  	// A store of pods
    59  	podLister corelisters.PodLister
    60  	podSynced func() bool
    61  
    62  	// A store of podgroups
    63  	pgLister schedulinglister.PodGroupLister
    64  	pgSynced func() bool
    65  
    66  	// A store of replicaset
    67  	rsSynced func() bool
    68  
    69  	queue workqueue.RateLimitingInterface
    70  
    71  	schedulerNames []string
    72  	workers        uint32
    73  
    74  	// To determine whether inherit owner's annotations for pods when create podgroup
    75  	inheritOwnerAnnotations bool
    76  }
    77  
    78  func (pg *pgcontroller) Name() string {
    79  	return "pg-controller"
    80  }
    81  
    82  // Initialize create new Podgroup Controller.
    83  func (pg *pgcontroller) Initialize(opt *framework.ControllerOption) error {
    84  	pg.kubeClient = opt.KubeClient
    85  	pg.vcClient = opt.VolcanoClient
    86  	pg.workers = opt.WorkerThreadsForPG
    87  
    88  	pg.queue = workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
    89  
    90  	pg.schedulerNames = make([]string, len(opt.SchedulerNames))
    91  	copy(pg.schedulerNames, opt.SchedulerNames)
    92  	pg.inheritOwnerAnnotations = opt.InheritOwnerAnnotations
    93  
    94  	pg.informerFactory = opt.SharedInformerFactory
    95  	pg.podInformer = opt.SharedInformerFactory.Core().V1().Pods()
    96  	pg.podLister = pg.podInformer.Lister()
    97  	pg.podSynced = pg.podInformer.Informer().HasSynced
    98  	pg.podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
    99  		AddFunc: pg.addPod,
   100  	})
   101  
   102  	factory := informerfactory.NewSharedInformerFactory(pg.vcClient, 0)
   103  	pg.vcInformerFactory = factory
   104  	pg.pgInformer = factory.Scheduling().V1beta1().PodGroups()
   105  	pg.pgLister = pg.pgInformer.Lister()
   106  	pg.pgSynced = pg.pgInformer.Informer().HasSynced
   107  
   108  	if utilfeature.DefaultFeatureGate.Enabled(features.WorkLoadSupport) {
   109  		pg.rsInformer = pg.informerFactory.Apps().V1().ReplicaSets()
   110  		pg.rsSynced = pg.rsInformer.Informer().HasSynced
   111  		pg.rsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
   112  			AddFunc:    pg.addReplicaSet,
   113  			UpdateFunc: pg.updateReplicaSet,
   114  		})
   115  	}
   116  	return nil
   117  }
   118  
   119  // Run start NewPodgroupController.
   120  func (pg *pgcontroller) Run(stopCh <-chan struct{}) {
   121  	pg.informerFactory.Start(stopCh)
   122  	pg.vcInformerFactory.Start(stopCh)
   123  
   124  	for informerType, ok := range pg.informerFactory.WaitForCacheSync(stopCh) {
   125  		if !ok {
   126  			klog.Errorf("caches failed to sync: %v", informerType)
   127  		}
   128  	}
   129  	for informerType, ok := range pg.vcInformerFactory.WaitForCacheSync(stopCh) {
   130  		if !ok {
   131  			klog.Errorf("caches failed to sync: %v", informerType)
   132  			return
   133  		}
   134  	}
   135  
   136  	for i := 0; i < int(pg.workers); i++ {
   137  		go wait.Until(pg.worker, 0, stopCh)
   138  	}
   139  
   140  	klog.Infof("PodgroupController is running ...... ")
   141  }
   142  
   143  func (pg *pgcontroller) worker() {
   144  	for pg.processNextReq() {
   145  	}
   146  }
   147  
   148  func (pg *pgcontroller) processNextReq() bool {
   149  	obj, shutdown := pg.queue.Get()
   150  	if shutdown {
   151  		klog.Errorf("Fail to pop item from queue")
   152  		return false
   153  	}
   154  
   155  	req := obj.(podRequest)
   156  	defer pg.queue.Done(req)
   157  
   158  	pod, err := pg.podLister.Pods(req.podNamespace).Get(req.podName)
   159  	if err != nil {
   160  		klog.Errorf("Failed to get pod by <%v> from cache: %v", req, err)
   161  		return true
   162  	}
   163  
   164  	if !commonutil.Contains(pg.schedulerNames, pod.Spec.SchedulerName) {
   165  		klog.V(5).Infof("pod %v/%v field SchedulerName is not matched", pod.Namespace, pod.Name)
   166  		return true
   167  	}
   168  
   169  	if pod.Annotations != nil && pod.Annotations[scheduling.KubeGroupNameAnnotationKey] != "" {
   170  		klog.V(5).Infof("pod %v/%v has created podgroup", pod.Namespace, pod.Name)
   171  		return true
   172  	}
   173  
   174  	// normal pod use volcano
   175  	if err := pg.createNormalPodPGIfNotExist(pod); err != nil {
   176  		klog.Errorf("Failed to handle Pod <%s/%s>: %v", pod.Namespace, pod.Name, err)
   177  		pg.queue.AddRateLimited(req)
   178  		return true
   179  	}
   180  
   181  	// If no error, forget it.
   182  	pg.queue.Forget(req)
   183  
   184  	return true
   185  }