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  `