sigs.k8s.io/kubebuilder/v3@v3.14.0/pkg/plugins/golang/v2/scaffolds/internal/templates/main.go (about) 1 /* 2 Copyright 2019 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 templates 18 19 import ( 20 "fmt" 21 "path/filepath" 22 23 "sigs.k8s.io/kubebuilder/v3/pkg/machinery" 24 ) 25 26 const defaultMainPath = "main.go" 27 28 var _ machinery.Template = &Main{} 29 30 // Main scaffolds a file that defines the controller manager entry point 31 type Main struct { 32 machinery.TemplateMixin 33 machinery.BoilerplateMixin 34 machinery.DomainMixin 35 machinery.RepositoryMixin 36 } 37 38 // SetTemplateDefaults implements file.Template 39 func (f *Main) SetTemplateDefaults() error { 40 if f.Path == "" { 41 f.Path = filepath.Join(defaultMainPath) 42 } 43 44 f.TemplateBody = fmt.Sprintf(mainTemplate, 45 machinery.NewMarkerFor(f.Path, importMarker), 46 machinery.NewMarkerFor(f.Path, addSchemeMarker), 47 machinery.NewMarkerFor(f.Path, setupMarker), 48 ) 49 50 return nil 51 } 52 53 var _ machinery.Inserter = &MainUpdater{} 54 55 // MainUpdater updates main.go to run Controllers 56 type MainUpdater struct { //nolint:maligned 57 machinery.RepositoryMixin 58 machinery.MultiGroupMixin 59 machinery.ResourceMixin 60 61 // Flags to indicate which parts need to be included when updating the file 62 WireResource, WireController, WireWebhook bool 63 } 64 65 // GetPath implements file.Builder 66 func (*MainUpdater) GetPath() string { 67 return defaultMainPath 68 } 69 70 // GetIfExistsAction implements file.Builder 71 func (*MainUpdater) GetIfExistsAction() machinery.IfExistsAction { 72 return machinery.OverwriteFile 73 } 74 75 const ( 76 importMarker = "imports" 77 addSchemeMarker = "scheme" 78 setupMarker = "builder" 79 ) 80 81 // GetMarkers implements file.Inserter 82 func (f *MainUpdater) GetMarkers() []machinery.Marker { 83 return []machinery.Marker{ 84 machinery.NewMarkerFor(defaultMainPath, importMarker), 85 machinery.NewMarkerFor(defaultMainPath, addSchemeMarker), 86 machinery.NewMarkerFor(defaultMainPath, setupMarker), 87 } 88 } 89 90 const ( 91 apiImportCodeFragment = `%s "%s" 92 ` 93 controllerImportCodeFragment = `"%s/controllers" 94 ` 95 multiGroupControllerImportCodeFragment = `%scontroller "%s/controllers/%s" 96 ` 97 addschemeCodeFragment = `utilruntime.Must(%s.AddToScheme(scheme)) 98 ` 99 reconcilerSetupCodeFragment = `if err = (&controllers.%sReconciler{ 100 Client: mgr.GetClient(), 101 Log: ctrl.Log.WithName("controllers").WithName("%s"), 102 Scheme: mgr.GetScheme(), 103 }).SetupWithManager(mgr); err != nil { 104 setupLog.Error(err, "unable to create controller", "controller", "%s") 105 os.Exit(1) 106 } 107 ` 108 multiGroupReconcilerSetupCodeFragment = `if err = (&%scontroller.%sReconciler{ 109 Client: mgr.GetClient(), 110 Log: ctrl.Log.WithName("controllers").WithName("%s"), 111 Scheme: mgr.GetScheme(), 112 }).SetupWithManager(mgr); err != nil { 113 setupLog.Error(err, "unable to create controller", "controller", "%s") 114 os.Exit(1) 115 } 116 ` 117 webhookSetupCodeFragment = `if err = (&%s.%s{}).SetupWebhookWithManager(mgr); err != nil { 118 setupLog.Error(err, "unable to create webhook", "webhook", "%s") 119 os.Exit(1) 120 } 121 ` 122 ) 123 124 // GetCodeFragments implements file.Inserter 125 func (f *MainUpdater) GetCodeFragments() machinery.CodeFragmentsMap { 126 fragments := make(machinery.CodeFragmentsMap, 3) 127 128 // If resource is not being provided we are creating the file, not updating it 129 if f.Resource == nil { 130 return fragments 131 } 132 133 // Generate import code fragments 134 imports := make([]string, 0) 135 if f.WireResource { 136 imports = append(imports, fmt.Sprintf(apiImportCodeFragment, f.Resource.ImportAlias(), f.Resource.Path)) 137 } 138 139 if f.WireController { 140 if !f.MultiGroup { 141 imports = append(imports, fmt.Sprintf(controllerImportCodeFragment, f.Repo)) 142 } else { 143 imports = append(imports, fmt.Sprintf(multiGroupControllerImportCodeFragment, 144 f.Resource.PackageName(), f.Repo, f.Resource.Group)) 145 } 146 } 147 148 // Generate add scheme code fragments 149 addScheme := make([]string, 0) 150 if f.WireResource { 151 addScheme = append(addScheme, fmt.Sprintf(addschemeCodeFragment, f.Resource.ImportAlias())) 152 } 153 154 // Generate setup code fragments 155 setup := make([]string, 0) 156 if f.WireController { 157 if !f.MultiGroup { 158 setup = append(setup, fmt.Sprintf(reconcilerSetupCodeFragment, 159 f.Resource.Kind, f.Resource.Kind, f.Resource.Kind)) 160 } else { 161 setup = append(setup, fmt.Sprintf(multiGroupReconcilerSetupCodeFragment, 162 f.Resource.PackageName(), f.Resource.Kind, f.Resource.Kind, f.Resource.Kind)) 163 } 164 } 165 if f.WireWebhook { 166 setup = append(setup, fmt.Sprintf(webhookSetupCodeFragment, 167 f.Resource.ImportAlias(), f.Resource.Kind, f.Resource.Kind)) 168 } 169 170 // Only store code fragments in the map if the slices are non-empty 171 if len(imports) != 0 { 172 fragments[machinery.NewMarkerFor(defaultMainPath, importMarker)] = imports 173 } 174 if len(addScheme) != 0 { 175 fragments[machinery.NewMarkerFor(defaultMainPath, addSchemeMarker)] = addScheme 176 } 177 if len(setup) != 0 { 178 fragments[machinery.NewMarkerFor(defaultMainPath, setupMarker)] = setup 179 } 180 181 return fragments 182 } 183 184 var mainTemplate = `{{ .Boilerplate }} 185 186 package main 187 188 import ( 189 "flag" 190 "os" 191 "k8s.io/apimachinery/pkg/runtime" 192 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 193 clientgoscheme "k8s.io/client-go/kubernetes/scheme" 194 _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 195 ctrl "sigs.k8s.io/controller-runtime" 196 "sigs.k8s.io/controller-runtime/pkg/log/zap" 197 %s 198 ) 199 200 var ( 201 scheme = runtime.NewScheme() 202 setupLog = ctrl.Log.WithName("setup") 203 ) 204 205 func init() { 206 utilruntime.Must(clientgoscheme.AddToScheme(scheme)) 207 208 %s 209 } 210 211 func main() { 212 var metricsAddr string 213 var enableLeaderElection bool 214 flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") 215 flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, 216 "Enable leader election for controller manager. " + 217 "Enabling this will ensure there is only one active controller manager.") 218 flag.Parse() 219 220 ctrl.SetLogger(zap.New(zap.UseDevMode(true))) 221 222 mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ 223 Scheme: scheme, 224 MetricsBindAddress: metricsAddr, 225 Port: 9443, 226 LeaderElection: enableLeaderElection, 227 LeaderElectionID: "{{ hashFNV .Repo }}.{{ .Domain }}", 228 }) 229 if err != nil { 230 setupLog.Error(err, "unable to start manager") 231 os.Exit(1) 232 } 233 234 %s 235 236 setupLog.Info("starting manager") 237 if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 238 setupLog.Error(err, "problem running manager") 239 os.Exit(1) 240 } 241 } 242 `