diff --git a/controllers/imageupdateautomation_controller.go b/controllers/imageupdateautomation_controller.go index 378f4204..70080edb 100644 --- a/controllers/imageupdateautomation_controller.go +++ b/controllers/imageupdateautomation_controller.go @@ -86,6 +86,8 @@ type ImageUpdateAutomationReconciler struct { helper.Metrics NoCrossNamespaceRef bool + + features map[string]bool } type ImageUpdateAutomationReconcilerOptions struct { @@ -255,8 +257,13 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(ctx context.Context, req ctr return failWithError(err) } + gitImplementation := origin.Spec.GitImplementation + if goGitOnly, _ := r.features[features.ForceGoGitImplementation]; goGitOnly { + gitImplementation = sourcev1.GoGitImplementation + } + var gitClient git.RepositoryClient - switch origin.Spec.GitImplementation { + switch gitImplementation { case sourcev1.LibGit2Implementation: gitClient, err = libgit2.NewClient(tmp, authOpts) case sourcev1.GoGitImplementation, "": @@ -268,7 +275,7 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(ctx context.Context, req ctr gitClient, err = gogit.NewClient(tmp, authOpts, opts...) default: - err = fmt.Errorf("failed to create git client; referred GitRepository has invalid implementation: %s", origin.Spec.GitImplementation) + err = fmt.Errorf("failed to create git client; referred GitRepository has invalid implementation: %s", gitImplementation) } if err != nil { return failWithError(err) @@ -423,6 +430,10 @@ func (r *ImageUpdateAutomationReconciler) SetupWithManager(mgr ctrl.Manager, opt return err } + if r.features == nil { + r.features = features.FeatureGates() + } + return ctrl.NewControllerManagedBy(mgr). For(&imagev1.ImageUpdateAutomation{}, builder.WithPredicates( predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}))). diff --git a/controllers/suite_test.go b/controllers/suite_test.go index a033cd94..d4dd01ef 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -35,6 +35,7 @@ import ( sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-automation-controller/api/v1beta1" + "github.com/fluxcd/image-automation-controller/internal/features" // +kubebuilder:scaffold:imports ) @@ -60,19 +61,34 @@ func TestMain(m *testing.M) { utilruntime.Must(sourcev1.AddToScheme(scheme.Scheme)) utilruntime.Must(imagev1.AddToScheme(scheme.Scheme)) + if err := transport.InitManagedTransport(); err != nil { + panic(fmt.Sprintf("failed to initialize libgit2 managed transport: %v", err)) + } + + code := runTestsWithFeatures(m, nil) + if code != 0 { + fmt.Println("failed with default feature values") + os.Exit(code) + } + + code = runTestsWithFeatures(m, map[string]bool{ + features.ForceGoGitImplementation: false, + }) + + os.Exit(code) +} + +func runTestsWithFeatures(m *testing.M, feats map[string]bool) int { testEnv = testenv.New(testenv.WithCRDPath( filepath.Join("..", "config", "crd", "bases"), filepath.Join("testdata", "crds"), )) - if err := transport.InitManagedTransport(); err != nil { - panic(fmt.Sprintf("failed to initialize libgit2 managed transport: %v", err)) - } - controllerName := "image-automation-controller" if err := (&ImageUpdateAutomationReconciler{ Client: testEnv, EventRecorder: testEnv.GetEventRecorderFor(controllerName), + features: feats, }).SetupWithManager(testEnv, ImageUpdateAutomationReconcilerOptions{}); err != nil { panic(fmt.Sprintf("failed to start ImageUpdateAutomationReconciler: %v", err)) } @@ -92,7 +108,7 @@ func TestMain(m *testing.M) { panic(fmt.Sprintf("failed to stop the test environment: %v", err)) } - os.Exit(code) + return code } // This provides a regression assurance for image-automation-controller/#339. diff --git a/internal/features/features.go b/internal/features/features.go index a015fe68..fbe34f8f 100644 --- a/internal/features/features.go +++ b/internal/features/features.go @@ -25,12 +25,23 @@ const ( // GitForcePushBranch enables the use of "force push" when push branches // are configured. GitForcePushBranch = "GitForcePushBranch" + + // ForceGoGitImplementation ignores the value set for gitImplementation + // of a GitRepository object and ensures that go-git is used for all git operations. + // + // When enabled, libgit2 won't be initialized, nor will any git2go cgo + // code be called. + ForceGoGitImplementation = "ForceGoGitImplementation" ) var features = map[string]bool{ // GitForcePushBranch // opt-out from v0.27 GitForcePushBranch: true, + + // ForceGoGitImplementation + // opt-out from v0.27 + ForceGoGitImplementation: true, } // DefaultFeatureGates contains a list of all supported feature gates and diff --git a/main.go b/main.go index 2639c665..f6460071 100644 --- a/main.go +++ b/main.go @@ -163,9 +163,11 @@ func main() { } // +kubebuilder:scaffold:builder - if err = transport.InitManagedTransport(); err != nil { - setupLog.Error(err, "unable to initialize libgit2 managed transport") - os.Exit(1) + if gogitOnly, _ := features.Enabled(features.ForceGoGitImplementation); !gogitOnly { + if err = transport.InitManagedTransport(); err != nil { + setupLog.Error(err, "unable to initialize libgit2 managed transport") + os.Exit(1) + } } setupLog.Info("starting manager")