k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/registry/scheduling/rest/storage_scheduling.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes 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 rest
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"time"
    23  
    24  	"k8s.io/klog/v2"
    25  
    26  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    29  	"k8s.io/apimachinery/pkg/util/wait"
    30  	"k8s.io/apiserver/pkg/registry/generic"
    31  	"k8s.io/apiserver/pkg/registry/rest"
    32  	genericapiserver "k8s.io/apiserver/pkg/server"
    33  	serverstorage "k8s.io/apiserver/pkg/server/storage"
    34  	schedulingclient "k8s.io/client-go/kubernetes/typed/scheduling/v1"
    35  	"k8s.io/kubernetes/pkg/api/legacyscheme"
    36  	"k8s.io/kubernetes/pkg/apis/scheduling"
    37  	schedulingapiv1 "k8s.io/kubernetes/pkg/apis/scheduling/v1"
    38  	priorityclassstore "k8s.io/kubernetes/pkg/registry/scheduling/priorityclass/storage"
    39  )
    40  
    41  const PostStartHookName = "scheduling/bootstrap-system-priority-classes"
    42  
    43  type RESTStorageProvider struct{}
    44  
    45  var _ genericapiserver.PostStartHookProvider = RESTStorageProvider{}
    46  
    47  func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, error) {
    48  	apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(scheduling.GroupName, legacyscheme.Scheme, legacyscheme.ParameterCodec, legacyscheme.Codecs)
    49  
    50  	if storageMap, err := p.v1Storage(apiResourceConfigSource, restOptionsGetter); err != nil {
    51  		return genericapiserver.APIGroupInfo{}, err
    52  	} else if len(storageMap) > 0 {
    53  		apiGroupInfo.VersionedResourcesStorageMap[schedulingapiv1.SchemeGroupVersion.Version] = storageMap
    54  	}
    55  
    56  	return apiGroupInfo, nil
    57  }
    58  
    59  func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
    60  	storage := map[string]rest.Storage{}
    61  
    62  	// priorityclasses
    63  	if resource := "priorityclasses"; apiResourceConfigSource.ResourceEnabled(schedulingapiv1.SchemeGroupVersion.WithResource(resource)) {
    64  		if priorityClassStorage, err := priorityclassstore.NewREST(restOptionsGetter); err != nil {
    65  			return nil, err
    66  		} else {
    67  			storage[resource] = priorityClassStorage
    68  		}
    69  	}
    70  
    71  	return storage, nil
    72  }
    73  
    74  func (p RESTStorageProvider) PostStartHook() (string, genericapiserver.PostStartHookFunc, error) {
    75  	return PostStartHookName, AddSystemPriorityClasses(), nil
    76  }
    77  
    78  func AddSystemPriorityClasses() genericapiserver.PostStartHookFunc {
    79  	return func(hookContext genericapiserver.PostStartHookContext) error {
    80  		// Adding system priority classes is important. If they fail to add, many critical system
    81  		// components may fail and cluster may break.
    82  		err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
    83  			schedClientSet, err := schedulingclient.NewForConfig(hookContext.LoopbackClientConfig)
    84  			if err != nil {
    85  				utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
    86  				return false, nil
    87  			}
    88  
    89  			for _, pc := range schedulingapiv1.SystemPriorityClasses() {
    90  				_, err := schedClientSet.PriorityClasses().Get(context.TODO(), pc.Name, metav1.GetOptions{})
    91  				if err != nil {
    92  					if apierrors.IsNotFound(err) {
    93  						_, err := schedClientSet.PriorityClasses().Create(context.TODO(), pc, metav1.CreateOptions{})
    94  						if err == nil || apierrors.IsAlreadyExists(err) {
    95  							klog.Infof("created PriorityClass %s with value %v", pc.Name, pc.Value)
    96  							continue
    97  						}
    98  						// ServiceUnavailble error is returned when the API server is blocked by storage version updates
    99  						if apierrors.IsServiceUnavailable(err) {
   100  							klog.Infof("going to retry, unable to create PriorityClass %s: %v", pc.Name, err)
   101  							return false, nil
   102  						}
   103  						return false, err
   104  					} else {
   105  						// Unable to get the priority class for reasons other than "not found".
   106  						klog.Warningf("unable to get PriorityClass %v: %v. Retrying...", pc.Name, err)
   107  						return false, nil
   108  					}
   109  				}
   110  			}
   111  			klog.Infof("all system priority classes are created successfully or already exist.")
   112  			return true, nil
   113  		})
   114  		// if we're never able to make it through initialization, kill the API server.
   115  		if err != nil {
   116  			return fmt.Errorf("unable to add default system priority classes: %v", err)
   117  		}
   118  		return nil
   119  	}
   120  }
   121  
   122  func (p RESTStorageProvider) GroupName() string {
   123  	return scheduling.GroupName
   124  }