sigs.k8s.io/kueue@v0.6.2/pkg/config/config.go (about) 1 /* 2 Copyright 2023 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 config 18 19 import ( 20 "bytes" 21 "fmt" 22 "os" 23 24 "k8s.io/apimachinery/pkg/api/equality" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime" 27 "k8s.io/apimachinery/pkg/runtime/serializer" 28 ctrl "sigs.k8s.io/controller-runtime" 29 "sigs.k8s.io/controller-runtime/pkg/webhook" 30 31 configapi "sigs.k8s.io/kueue/apis/config/v1beta1" 32 ) 33 34 // fromFile provides an alternative to the deprecated ctrl.ConfigFile().AtPath(path).OfKind(&cfg) 35 func fromFile(path string, scheme *runtime.Scheme, cfg *configapi.Configuration) error { 36 content, err := os.ReadFile(path) 37 if err != nil { 38 return err 39 } 40 41 codecs := serializer.NewCodecFactory(scheme) 42 43 // Regardless of if the bytes are of any external version, 44 // it will be read successfully and converted into the internal version 45 return runtime.DecodeInto(codecs.UniversalDecoder(), content, cfg) 46 } 47 48 // addTo provides an alternative to the deprecated o.AndFrom(&cfg) 49 func addTo(o *ctrl.Options, cfg *configapi.Configuration) { 50 addLeaderElectionTo(o, cfg) 51 if o.Metrics.BindAddress == "" && cfg.Metrics.BindAddress != "" { 52 o.Metrics.BindAddress = cfg.Metrics.BindAddress 53 } 54 55 if o.PprofBindAddress == "" && cfg.PprofBindAddress != "" { 56 o.PprofBindAddress = cfg.PprofBindAddress 57 } 58 59 if o.HealthProbeBindAddress == "" && cfg.Health.HealthProbeBindAddress != "" { 60 o.HealthProbeBindAddress = cfg.Health.HealthProbeBindAddress 61 } 62 63 if o.ReadinessEndpointName == "" && cfg.Health.ReadinessEndpointName != "" { 64 o.ReadinessEndpointName = cfg.Health.ReadinessEndpointName 65 } 66 67 if o.LivenessEndpointName == "" && cfg.Health.LivenessEndpointName != "" { 68 o.LivenessEndpointName = cfg.Health.LivenessEndpointName 69 } 70 71 if o.WebhookServer == nil && cfg.Webhook.Port != nil { 72 wo := webhook.Options{} 73 if cfg.Webhook.Port != nil { 74 wo.Port = *cfg.Webhook.Port 75 } 76 if cfg.Webhook.Host != "" { 77 wo.Host = cfg.Webhook.Host 78 } 79 80 if cfg.Webhook.CertDir != "" { 81 wo.CertDir = cfg.Webhook.CertDir 82 } 83 o.WebhookServer = webhook.NewServer(wo) 84 } 85 86 if cfg.Controller != nil { 87 if o.Controller.CacheSyncTimeout == 0 && cfg.Controller.CacheSyncTimeout != nil { 88 o.Controller.CacheSyncTimeout = *cfg.Controller.CacheSyncTimeout 89 } 90 91 if len(o.Controller.GroupKindConcurrency) == 0 && len(cfg.Controller.GroupKindConcurrency) > 0 { 92 o.Controller.GroupKindConcurrency = cfg.Controller.GroupKindConcurrency 93 } 94 } 95 } 96 97 func addLeaderElectionTo(o *ctrl.Options, cfg *configapi.Configuration) { 98 if cfg.LeaderElection == nil { 99 // The source does not have any configuration; noop 100 return 101 } 102 103 if !o.LeaderElection && cfg.LeaderElection.LeaderElect != nil { 104 o.LeaderElection = *cfg.LeaderElection.LeaderElect 105 } 106 107 if o.LeaderElectionResourceLock == "" && cfg.LeaderElection.ResourceLock != "" { 108 o.LeaderElectionResourceLock = cfg.LeaderElection.ResourceLock 109 } 110 111 if o.LeaderElectionNamespace == "" && cfg.LeaderElection.ResourceNamespace != "" { 112 o.LeaderElectionNamespace = cfg.LeaderElection.ResourceNamespace 113 } 114 115 if o.LeaderElectionID == "" && cfg.LeaderElection.ResourceName != "" { 116 o.LeaderElectionID = cfg.LeaderElection.ResourceName 117 } 118 119 if o.LeaseDuration == nil && !equality.Semantic.DeepEqual(cfg.LeaderElection.LeaseDuration, metav1.Duration{}) { 120 o.LeaseDuration = &cfg.LeaderElection.LeaseDuration.Duration 121 } 122 123 if o.RenewDeadline == nil && !equality.Semantic.DeepEqual(cfg.LeaderElection.RenewDeadline, metav1.Duration{}) { 124 o.RenewDeadline = &cfg.LeaderElection.RenewDeadline.Duration 125 } 126 127 if o.RetryPeriod == nil && !equality.Semantic.DeepEqual(cfg.LeaderElection.RetryPeriod, metav1.Duration{}) { 128 o.RetryPeriod = &cfg.LeaderElection.RetryPeriod.Duration 129 } 130 } 131 132 func Encode(scheme *runtime.Scheme, cfg *configapi.Configuration) (string, error) { 133 codecs := serializer.NewCodecFactory(scheme) 134 const mediaType = runtime.ContentTypeYAML 135 info, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType) 136 if !ok { 137 return "", fmt.Errorf("unable to locate encoder -- %q is not a supported media type", mediaType) 138 } 139 140 encoder := codecs.EncoderForVersion(info.Serializer, configapi.GroupVersion) 141 buf := new(bytes.Buffer) 142 if err := encoder.Encode(cfg, buf); err != nil { 143 return "", err 144 } 145 return buf.String(), nil 146 } 147 148 // Load returns a set of controller options and configuration from the given file, if the config file path is empty 149 // it used the default configapi values. 150 func Load(scheme *runtime.Scheme, configFile string) (ctrl.Options, configapi.Configuration, error) { 151 var err error 152 options := ctrl.Options{ 153 Scheme: scheme, 154 } 155 156 cfg := configapi.Configuration{} 157 if configFile == "" { 158 scheme.Default(&cfg) 159 } else { 160 err := fromFile(configFile, scheme, &cfg) 161 if err != nil { 162 return options, cfg, err 163 } 164 } 165 if err := validate(&cfg).ToAggregate(); err != nil { 166 return options, cfg, err 167 } 168 addTo(&options, &cfg) 169 return options, cfg, err 170 } 171 172 func WaitForPodsReadyIsEnabled(cfg *configapi.Configuration) bool { 173 return cfg.WaitForPodsReady != nil && cfg.WaitForPodsReady.Enable 174 }