sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/cmd/prow-controller-manager/main.go (about) 1 /* 2 Copyright 2020 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 main 18 19 import ( 20 "context" 21 "errors" 22 "flag" 23 "fmt" 24 "os" 25 26 "github.com/sirupsen/logrus" 27 uberzap "go.uber.org/zap" 28 "k8s.io/apimachinery/pkg/labels" 29 utilerrors "k8s.io/apimachinery/pkg/util/errors" 30 "k8s.io/apimachinery/pkg/util/sets" 31 ctrlruntimelog "sigs.k8s.io/controller-runtime/pkg/log" 32 "sigs.k8s.io/controller-runtime/pkg/log/zap" 33 "sigs.k8s.io/controller-runtime/pkg/manager" 34 "sigs.k8s.io/prow/pkg/pjutil" 35 "sigs.k8s.io/prow/pkg/pjutil/pprof" 36 "sigs.k8s.io/prow/pkg/scheduler" 37 38 "sigs.k8s.io/prow/pkg/flagutil" 39 prowflagutil "sigs.k8s.io/prow/pkg/flagutil" 40 configflagutil "sigs.k8s.io/prow/pkg/flagutil/config" 41 "sigs.k8s.io/prow/pkg/interrupts" 42 "sigs.k8s.io/prow/pkg/io" 43 "sigs.k8s.io/prow/pkg/logrusutil" 44 "sigs.k8s.io/prow/pkg/metrics" 45 "sigs.k8s.io/prow/pkg/plank" 46 47 _ "sigs.k8s.io/prow/pkg/version" 48 ) 49 50 var allControllers = sets.New(plank.ControllerName, scheduler.ControllerName) 51 52 type options struct { 53 totURL string 54 55 config configflagutil.ConfigOptions 56 selector string 57 enabledControllers prowflagutil.Strings 58 59 dryRun bool 60 kubernetes prowflagutil.KubernetesOptions 61 github prowflagutil.GitHubOptions // TODO(fejta): remove 62 instrumentationOptions prowflagutil.InstrumentationOptions 63 storage prowflagutil.StorageClientOptions 64 } 65 66 func gatherOptions(fs *flag.FlagSet, args ...string) options { 67 var o options 68 o.enabledControllers = prowflagutil.NewStrings(plank.ControllerName) 69 fs.StringVar(&o.totURL, "tot-url", "", "Tot URL") 70 71 fs.StringVar(&o.selector, "label-selector", labels.Everything().String(), "Label selector to be applied in prowjobs. See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors for constructing a label selector.") 72 fs.Var(&o.enabledControllers, "enable-controller", fmt.Sprintf("Controllers to enable. Can be passed multiple times. Defaults to controllers: %s", plank.ControllerName)) 73 74 fs.BoolVar(&o.dryRun, "dry-run", true, "Whether or not to make mutating API calls to GitHub.") 75 for _, group := range []flagutil.OptionGroup{&o.kubernetes, &o.github, &o.instrumentationOptions, &o.config, &o.storage} { 76 group.AddFlags(fs) 77 } 78 79 fs.Parse(args) 80 return o 81 } 82 83 func (o *options) Validate() error { 84 o.github.AllowAnonymous = true 85 86 var errs []error 87 for _, group := range []flagutil.OptionGroup{&o.kubernetes, &o.github, &o.instrumentationOptions, &o.config, &o.storage} { 88 if err := group.Validate(o.dryRun); err != nil { 89 errs = append(errs, err) 90 } 91 } 92 93 for _, enabledController := range o.enabledControllers.Strings() { 94 if !allControllers.Has(enabledController) { 95 errs = append(errs, fmt.Errorf("unknown controller %s was configured via --enabled-controller", enabledController)) 96 } 97 } 98 99 if n := len(allControllers.Intersection(sets.New(o.enabledControllers.Strings()...))); n == 0 { 100 errs = append(errs, errors.New("no controllers configured")) 101 } 102 103 if _, err := labels.Parse(o.selector); err != nil { 104 errs = append(errs, fmt.Errorf("parse label selector: %w", err)) 105 } 106 107 return utilerrors.NewAggregate(errs) 108 } 109 110 func main() { 111 logrusutil.ComponentInit() 112 113 o := gatherOptions(flag.NewFlagSet(os.Args[0], flag.ExitOnError), os.Args[1:]...) 114 if err := o.Validate(); err != nil { 115 logrus.WithError(err).Fatal("Invalid options") 116 } 117 118 defer interrupts.WaitForGracefulShutdown() 119 120 health := pjutil.NewHealthOnPort(o.instrumentationOptions.HealthPort) // Start liveness endpoint 121 pprof.Instrument(o.instrumentationOptions) 122 123 configAgent, err := o.config.ConfigAgent() 124 if err != nil { 125 logrus.WithError(err).Fatal("Error starting config agent.") 126 } 127 cfg := configAgent.Config 128 o.kubernetes.SetDisabledClusters(sets.New(cfg().DisabledClusters...)) 129 130 var logOpts []zap.Opts 131 if cfg().LogLevel == "debug" { 132 logOpts = append(logOpts, func(o *zap.Options) { 133 lvl := uberzap.NewAtomicLevelAt(uberzap.DebugLevel) 134 o.Level = &lvl 135 }) 136 } 137 ctrlruntimelog.SetLogger(zap.New(logOpts...)) 138 139 infrastructureClusterConfig, err := o.kubernetes.InfrastructureClusterConfig(o.dryRun) 140 if err != nil { 141 logrus.WithError(err).Fatal("Error getting infrastructure cluster config.") 142 } 143 opts := manager.Options{ 144 MetricsBindAddress: "0", 145 Namespace: cfg().ProwJobNamespace, 146 LeaderElection: true, 147 LeaderElectionNamespace: cfg().ProwJobNamespace, 148 LeaderElectionID: "prow-controller-manager-leader-lock", 149 } 150 mgr, err := manager.New(infrastructureClusterConfig, opts) 151 if err != nil { 152 logrus.WithError(err).Fatal("Error creating manager") 153 } 154 155 // The watch apimachinery doesn't support restarts, so just exit the 156 // binary if a build cluster can be connected later. 157 callBack := func() { 158 logrus.Info("Build cluster that failed to connect initially now worked, exiting to trigger a restart.") 159 interrupts.Terminate() 160 } 161 162 buildClusterManagers, err := o.kubernetes.BuildClusterManagers(o.dryRun, 163 plank.RequiredTestPodVerbs(), 164 callBack, 165 func(o *manager.Options) { 166 o.Namespace = cfg().PodNamespace 167 }, 168 ) 169 if err != nil { 170 logrus.WithError(err).Error("Failed to construct build cluster managers. Please check that the kubeconfig secrets are correct, and that RBAC roles on the build cluster allow Prow's service account to list pods on it.") 171 } 172 173 for buildClusterName, buildClusterManager := range buildClusterManagers { 174 if err := mgr.Add(buildClusterManager); err != nil { 175 logrus.WithError(err).WithFields(logrus.Fields{ 176 "cluster": buildClusterName, 177 }).Fatalf("Failed to add build cluster manager to main manager") 178 } 179 } 180 181 opener, err := io.NewOpener(context.Background(), o.storage.GCSCredentialsFile, o.storage.S3CredentialsFile) 182 if err != nil { 183 logrus.WithError(err).Fatal("Error creating opener") 184 } 185 186 // The watch apimachinery doesn't support restarts, so just exit the binary if a kubeconfig changes 187 // to make the kubelet restart us. 188 if err := o.kubernetes.AddKubeconfigChangeCallback(func() { 189 logrus.Info("Kubeconfig changed, exiting to trigger a restart") 190 interrupts.Terminate() 191 }); err != nil { 192 logrus.WithError(err).Fatal("Failed to register kubeconfig change callback") 193 } 194 195 enabledControllersSet := sets.New(o.enabledControllers.Strings()...) 196 knownClusters, err := o.kubernetes.KnownClusters(o.dryRun) 197 if err != nil { 198 logrus.WithError(err).Fatal("Failed to resolve known clusters in kubeconfig.") 199 } 200 201 if enabledControllersSet.Has(plank.ControllerName) { 202 if err := plank.Add(mgr, buildClusterManagers, knownClusters, cfg, opener, o.totURL, o.selector); err != nil { 203 logrus.WithError(err).Fatal("Failed to add plank to manager") 204 } 205 } 206 207 if enabledControllersSet.Has(scheduler.ControllerName) { 208 if err := scheduler.Add(mgr, cfg, 1); err != nil { 209 logrus.WithError(err).Fatal("Failed to add scheduler to manager") 210 } 211 } 212 213 // Expose prometheus metrics 214 metrics.ExposeMetrics("plank", cfg().PushGateway, o.instrumentationOptions.MetricsPort) 215 // Serve readiness endpoint 216 health.ServeReady() 217 218 if err := mgr.Start(interrupts.Context()); err != nil { 219 logrus.WithError(err).Fatal("failed to start manager") 220 } 221 222 logrus.Info("Controller ended gracefully") 223 }