volcano.sh/volcano@v1.9.0/pkg/controllers/queue/queue_controller_action.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 queue
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"reflect"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/client-go/tools/cache"
    27  	"k8s.io/klog/v2"
    28  
    29  	"volcano.sh/apis/pkg/apis/bus/v1alpha1"
    30  	schedulingv1beta1 "volcano.sh/apis/pkg/apis/scheduling/v1beta1"
    31  	"volcano.sh/volcano/pkg/controllers/queue/state"
    32  )
    33  
    34  func (c *queuecontroller) syncQueue(queue *schedulingv1beta1.Queue, updateStateFn state.UpdateQueueStatusFn) error {
    35  	klog.V(4).Infof("Begin to sync queue %s.", queue.Name)
    36  	defer klog.V(4).Infof("End sync queue %s.", queue.Name)
    37  
    38  	podGroups := c.getPodGroups(queue.Name)
    39  	queueStatus := schedulingv1beta1.QueueStatus{}
    40  
    41  	for _, pgKey := range podGroups {
    42  		// Ignore error here, tt can not occur.
    43  		ns, name, _ := cache.SplitMetaNamespaceKey(pgKey)
    44  
    45  		// TODO: check NotFound error and sync local cache.
    46  		pg, err := c.pgLister.PodGroups(ns).Get(name)
    47  		if err != nil {
    48  			return err
    49  		}
    50  
    51  		switch pg.Status.Phase {
    52  		case schedulingv1beta1.PodGroupPending:
    53  			queueStatus.Pending++
    54  		case schedulingv1beta1.PodGroupRunning:
    55  			queueStatus.Running++
    56  		case schedulingv1beta1.PodGroupUnknown:
    57  			queueStatus.Unknown++
    58  		case schedulingv1beta1.PodGroupInqueue:
    59  			queueStatus.Inqueue++
    60  		}
    61  	}
    62  
    63  	if updateStateFn != nil {
    64  		updateStateFn(&queueStatus, podGroups)
    65  	} else {
    66  		queueStatus.State = queue.Status.State
    67  	}
    68  
    69  	queueStatus.Allocated = queue.Status.Allocated.DeepCopy()
    70  	// queue.status.allocated will be updated after every session close in volcano scheduler, we should not depend on it because session may be time-consuming,
    71  	// and queue.status.allocated can't be updated timely. We initialize queue.status.allocated and update it here explicitly
    72  	// to avoid update queue err because update will fail when queue.status.allocated is nil.
    73  	if queueStatus.Allocated == nil {
    74  		queueStatus.Allocated = v1.ResourceList{}
    75  	}
    76  
    77  	// ignore update when status does not change
    78  	if reflect.DeepEqual(queueStatus, queue.Status) {
    79  		return nil
    80  	}
    81  
    82  	newQueue := queue.DeepCopy()
    83  	newQueue.Status = queueStatus
    84  	if _, err := c.vcClient.SchedulingV1beta1().Queues().UpdateStatus(context.TODO(), newQueue, metav1.UpdateOptions{}); err != nil {
    85  		klog.Errorf("Failed to update status of Queue %s: %v.", newQueue.Name, err)
    86  		return err
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  func (c *queuecontroller) openQueue(queue *schedulingv1beta1.Queue, updateStateFn state.UpdateQueueStatusFn) error {
    93  	klog.V(4).Infof("Begin to open queue %s.", queue.Name)
    94  
    95  	newQueue := queue.DeepCopy()
    96  	newQueue.Status.State = schedulingv1beta1.QueueStateOpen
    97  
    98  	if queue.Status.State != newQueue.Status.State {
    99  		if _, err := c.vcClient.SchedulingV1beta1().Queues().Update(context.TODO(), newQueue, metav1.UpdateOptions{}); err != nil {
   100  			c.recorder.Event(newQueue, v1.EventTypeWarning, string(v1alpha1.OpenQueueAction),
   101  				fmt.Sprintf("Open queue failed for %v", err))
   102  			return err
   103  		}
   104  
   105  		c.recorder.Event(newQueue, v1.EventTypeNormal, string(v1alpha1.OpenQueueAction), "Open queue succeed")
   106  	} else {
   107  		return nil
   108  	}
   109  
   110  	q, err := c.vcClient.SchedulingV1beta1().Queues().Get(context.TODO(), newQueue.Name, metav1.GetOptions{})
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	newQueue = q.DeepCopy()
   116  	if updateStateFn != nil {
   117  		updateStateFn(&newQueue.Status, nil)
   118  	} else {
   119  		return fmt.Errorf("internal error, update state function should be provided")
   120  	}
   121  
   122  	if queue.Status.State != newQueue.Status.State {
   123  		if _, err := c.vcClient.SchedulingV1beta1().Queues().UpdateStatus(context.TODO(), newQueue, metav1.UpdateOptions{}); err != nil {
   124  			c.recorder.Event(newQueue, v1.EventTypeWarning, string(v1alpha1.OpenQueueAction),
   125  				fmt.Sprintf("Update queue status from %s to %s failed for %v",
   126  					queue.Status.State, newQueue.Status.State, err))
   127  			return err
   128  		}
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  func (c *queuecontroller) closeQueue(queue *schedulingv1beta1.Queue, updateStateFn state.UpdateQueueStatusFn) error {
   135  	klog.V(4).Infof("Begin to close queue %s.", queue.Name)
   136  
   137  	newQueue := queue.DeepCopy()
   138  	newQueue.Status.State = schedulingv1beta1.QueueStateClosed
   139  
   140  	if queue.Status.State != newQueue.Status.State {
   141  		if _, err := c.vcClient.SchedulingV1beta1().Queues().Update(context.TODO(), newQueue, metav1.UpdateOptions{}); err != nil {
   142  			c.recorder.Event(newQueue, v1.EventTypeWarning, string(v1alpha1.CloseQueueAction),
   143  				fmt.Sprintf("Close queue failed for %v", err))
   144  			return err
   145  		}
   146  
   147  		c.recorder.Event(newQueue, v1.EventTypeNormal, string(v1alpha1.CloseQueueAction), "Close queue succeed")
   148  	} else {
   149  		return nil
   150  	}
   151  
   152  	q, err := c.vcClient.SchedulingV1beta1().Queues().Get(context.TODO(), newQueue.Name, metav1.GetOptions{})
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	newQueue = q.DeepCopy()
   158  	podGroups := c.getPodGroups(newQueue.Name)
   159  	if updateStateFn != nil {
   160  		updateStateFn(&newQueue.Status, podGroups)
   161  	} else {
   162  		return fmt.Errorf("internal error, update state function should be provided")
   163  	}
   164  
   165  	if queue.Status.State != newQueue.Status.State {
   166  		if _, err := c.vcClient.SchedulingV1beta1().Queues().UpdateStatus(context.TODO(), newQueue, metav1.UpdateOptions{}); err != nil {
   167  			c.recorder.Event(newQueue, v1.EventTypeWarning, string(v1alpha1.CloseQueueAction),
   168  				fmt.Sprintf("Update queue status from %s to %s failed for %v",
   169  					queue.Status.State, newQueue.Status.State, err))
   170  			return err
   171  		}
   172  	}
   173  
   174  	return nil
   175  }