Skip to content

Commit a6072c3

Browse files
authored
Merge pull request #819 from aryan9600/remove-unmanaged-transport
libgit2: decommission unmanaged transport
2 parents 8f3cf12 + 0978a7a commit a6072c3

18 files changed

+492
-1166
lines changed

controllers/gitrepository_controller.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ import (
5656
"github.com/fluxcd/source-controller/internal/reconcile/summarize"
5757
"github.com/fluxcd/source-controller/internal/util"
5858
"github.com/fluxcd/source-controller/pkg/git"
59-
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
6059
"github.com/fluxcd/source-controller/pkg/git/strategy"
6160
"github.com/fluxcd/source-controller/pkg/sourceignore"
6261
)
@@ -116,6 +115,9 @@ type GitRepositoryReconciler struct {
116115

117116
Storage *Storage
118117
ControllerName string
118+
// Libgit2TransportInitialized lets the reconciler know whether
119+
// libgit2 transport was intialized successfully.
120+
Libgit2TransportInitialized func() bool
119121

120122
requeueDependency time.Duration
121123
features map[string]bool
@@ -428,6 +430,12 @@ func (r *GitRepositoryReconciler) reconcileStorage(ctx context.Context,
428430
// change, it short-circuits the whole reconciliation with an early return.
429431
func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
430432
obj *sourcev1.GitRepository, commit *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error) {
433+
// Exit early, if we need to use libgit2 AND managed transport hasn't been intialized.
434+
if !r.Libgit2TransportInitialized() && obj.Spec.GitImplementation == sourcev1.LibGit2Implementation {
435+
return sreconcile.ResultEmpty, serror.NewStalling(
436+
errors.New("libgit2 managed transport not initialized"), "Libgit2TransportNotEnabled",
437+
)
438+
}
431439
// Configure authentication strategy to access the source
432440
var authOpts *git.AuthOptions
433441
var err error
@@ -745,8 +753,8 @@ func (r *GitRepositoryReconciler) gitCheckout(ctx context.Context,
745753
return nil, e
746754
}
747755

748-
// managed GIT transport only affects the libgit2 implementation
749-
if managed.Enabled() && obj.Spec.GitImplementation == sourcev1.LibGit2Implementation {
756+
// this is needed only for libgit2, due to managed transport.
757+
if obj.Spec.GitImplementation == sourcev1.LibGit2Implementation {
750758
// We set the TransportOptionsURL of this set of authentication options here by constructing
751759
// a unique URL that won't clash in a multi tenant environment. This unique URL is used by
752760
// libgit2 managed transports. This enables us to bypass the inbuilt credentials callback in

controllers/gitrepository_controller_test.go

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import (
6262
sreconcile "github.com/fluxcd/source-controller/internal/reconcile"
6363
"github.com/fluxcd/source-controller/internal/reconcile/summarize"
6464
"github.com/fluxcd/source-controller/pkg/git"
65+
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
6566
)
6667

6768
const (
@@ -149,6 +150,10 @@ var (
149150
testGitImplementations = []string{sourcev1.GoGitImplementation, sourcev1.LibGit2Implementation}
150151
)
151152

153+
func mockTransportNotInitialized() bool {
154+
return false
155+
}
156+
152157
func TestGitRepositoryReconciler_Reconcile(t *testing.T) {
153158
g := NewWithT(t)
154159

@@ -504,10 +509,11 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
504509
}
505510

506511
r := &GitRepositoryReconciler{
507-
Client: builder.Build(),
508-
EventRecorder: record.NewFakeRecorder(32),
509-
Storage: testStorage,
510-
features: features.FeatureGates(),
512+
Client: builder.Build(),
513+
EventRecorder: record.NewFakeRecorder(32),
514+
Storage: testStorage,
515+
features: features.FeatureGates(),
516+
Libgit2TransportInitialized: managed.Enabled,
511517
}
512518

513519
for _, i := range testGitImplementations {
@@ -544,6 +550,40 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
544550
}
545551
}
546552

553+
func TestGitRepositoryReconciler_reconcileSource_libgit2TransportUninitialized(t *testing.T) {
554+
g := NewWithT(t)
555+
556+
r := &GitRepositoryReconciler{
557+
Client: fakeclient.NewClientBuilder().WithScheme(runtime.NewScheme()).Build(),
558+
EventRecorder: record.NewFakeRecorder(32),
559+
Storage: testStorage,
560+
features: features.FeatureGates(),
561+
Libgit2TransportInitialized: mockTransportNotInitialized,
562+
}
563+
564+
obj := &sourcev1.GitRepository{
565+
ObjectMeta: metav1.ObjectMeta{
566+
GenerateName: "libgit2-transport",
567+
},
568+
Spec: sourcev1.GitRepositorySpec{
569+
Interval: metav1.Duration{Duration: interval},
570+
Timeout: &metav1.Duration{Duration: timeout},
571+
Reference: &sourcev1.GitRepositoryRef{
572+
Branch: git.DefaultBranch,
573+
},
574+
GitImplementation: sourcev1.LibGit2Implementation,
575+
},
576+
}
577+
578+
tmpDir := t.TempDir()
579+
var commit git.Commit
580+
var includes artifactSet
581+
_, err := r.reconcileSource(ctx, obj, &commit, &includes, tmpDir)
582+
g.Expect(err).To(HaveOccurred())
583+
g.Expect(err).To(BeAssignableToTypeOf(&serror.Stalling{}))
584+
g.Expect(err.Error()).To(Equal("libgit2 managed transport not initialized"))
585+
}
586+
547587
func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T) {
548588
g := NewWithT(t)
549589

@@ -702,10 +742,11 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T)
702742
}
703743

704744
r := &GitRepositoryReconciler{
705-
Client: fakeclient.NewClientBuilder().WithScheme(runtime.NewScheme()).Build(),
706-
EventRecorder: record.NewFakeRecorder(32),
707-
Storage: testStorage,
708-
features: features.FeatureGates(),
745+
Client: fakeclient.NewClientBuilder().WithScheme(runtime.NewScheme()).Build(),
746+
EventRecorder: record.NewFakeRecorder(32),
747+
Storage: testStorage,
748+
features: features.FeatureGates(),
749+
Libgit2TransportInitialized: managed.Enabled,
709750
}
710751

711752
for _, tt := range tests {
@@ -1563,10 +1604,11 @@ func TestGitRepositoryReconciler_ConditionsUpdate(t *testing.T) {
15631604
builder := fakeclient.NewClientBuilder().WithScheme(testEnv.GetScheme()).WithObjects(obj)
15641605

15651606
r := &GitRepositoryReconciler{
1566-
Client: builder.Build(),
1567-
EventRecorder: record.NewFakeRecorder(32),
1568-
Storage: testStorage,
1569-
features: features.FeatureGates(),
1607+
Client: builder.Build(),
1608+
EventRecorder: record.NewFakeRecorder(32),
1609+
Storage: testStorage,
1610+
features: features.FeatureGates(),
1611+
Libgit2TransportInitialized: managed.Enabled,
15701612
}
15711613

15721614
key := client.ObjectKeyFromObject(obj)

controllers/suite_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import (
3737
ctrl "sigs.k8s.io/controller-runtime"
3838

3939
"github.com/fluxcd/pkg/runtime/controller"
40-
feathelper "github.com/fluxcd/pkg/runtime/features"
4140
"github.com/fluxcd/pkg/runtime/testenv"
4241
"github.com/fluxcd/pkg/testserver"
4342
"github.com/phayes/freeport"
@@ -206,16 +205,17 @@ func TestMain(m *testing.M) {
206205
panic(fmt.Sprintf("Failed to create a test registry server: %v", err))
207206
}
208207

209-
fg := feathelper.FeatureGates{}
210-
fg.SupportedFeatures(features.FeatureGates())
211-
managed.InitManagedTransport()
208+
if err = managed.InitManagedTransport(); err != nil {
209+
panic(fmt.Sprintf("Failed to initialize libgit2 managed transport: %v", err))
210+
}
212211

213212
if err := (&GitRepositoryReconciler{
214-
Client: testEnv,
215-
EventRecorder: record.NewFakeRecorder(32),
216-
Metrics: testMetricsH,
217-
Storage: testStorage,
218-
features: features.FeatureGates(),
213+
Client: testEnv,
214+
EventRecorder: record.NewFakeRecorder(32),
215+
Metrics: testMetricsH,
216+
Storage: testStorage,
217+
features: features.FeatureGates(),
218+
Libgit2TransportInitialized: managed.Enabled,
219219
}).SetupWithManager(testEnv); err != nil {
220220
panic(fmt.Sprintf("Failed to start GitRepositoryReconciler: %v", err))
221221
}

docs/spec/v1beta2/gitrepositories.md

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -405,18 +405,6 @@ Some Git providers like Azure DevOps _require_ the `libgit2` implementation, as
405405
their Git servers provide only support for the
406406
[v2 protocol](https://git-scm.com/docs/protocol-v2).
407407

408-
#### Managed transport for `libgit2` Git implementation
409-
410-
The `libgit2` Git implementation supports a new managed transport for
411-
improved reliability, adding timeout enforcement for Git network operations.
412-
413-
This feature is enabled by default. It can be disabled by starting the
414-
controller with the argument `--feature-gates=GitManagedTransport=false`.
415-
416-
By disabling this feature the management of the transport is passed on to
417-
`libgit2`, which may result in blocking Git operations leading the controllers
418-
to hang indefinitely.
419-
420408
#### Optimized Git clones
421409

422410
Optimized Git clones decreases resource utilization for GitRepository
@@ -432,9 +420,6 @@ usual.
432420

433421
This feature is enabled by default. It can be disabled by starting the
434422
controller with the argument `--feature-gates=OptimizedGitClones=false`.
435-
Please note that this feature is only active when managed transport for
436-
`libgit2` is active. Disabling managed transport for `libgit2` automatically
437-
disables this feature.
438423

439424
NB: GitRepository objects configured for SemVer or Commit clones are
440425
not affected by this functionality.

internal/features/features.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,12 @@ const (
3030
// the last revision is still the same at the target repository,
3131
// and if that is so, skips the reconciliation.
3232
OptimizedGitClones = "OptimizedGitClones"
33-
34-
// GitManagedTransport implements a managed transport for GitRepository
35-
// objects that use the libgit2 implementation.
36-
//
37-
// When enabled, improves the reliability of libgit2 reconciliations,
38-
// by enforcing timeouts and ensuring libgit2 cannot hijack the process
39-
// and hang it indefinitely.
40-
GitManagedTransport = "GitManagedTransport"
4133
)
4234

4335
var features = map[string]bool{
4436
// OptimizedGitClones
4537
// opt-out from v0.25
4638
OptimizedGitClones: true,
47-
48-
// GitManagedTransport
49-
// opt-in from v0.22 (via environment variable)
50-
// opt-out from v0.25
51-
GitManagedTransport: true,
5239
}
5340

5441
// DefaultFeatureGates contains a list of all supported feature gates and

main.go

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,18 @@ func main() {
204204
}
205205
storage := mustInitStorage(storagePath, storageAdvAddr, artifactRetentionTTL, artifactRetentionRecords, setupLog)
206206

207+
if err = managed.InitManagedTransport(); err != nil {
208+
// Log the error, but don't exit so as to not block reconcilers that are healthy.
209+
setupLog.Error(err, "unable to initialize libgit2 managed transport")
210+
}
211+
207212
if err = (&controllers.GitRepositoryReconciler{
208-
Client: mgr.GetClient(),
209-
EventRecorder: eventRecorder,
210-
Metrics: metricsH,
211-
Storage: storage,
212-
ControllerName: controllerName,
213+
Client: mgr.GetClient(),
214+
EventRecorder: eventRecorder,
215+
Metrics: metricsH,
216+
Storage: storage,
217+
ControllerName: controllerName,
218+
Libgit2TransportInitialized: managed.Enabled,
213219
}).SetupWithManagerAndOptions(mgr, controllers.GitRepositoryReconcilerOptions{
214220
MaxConcurrentReconciles: concurrent,
215221
DependencyRequeueInterval: requeueDependency,
@@ -310,17 +316,6 @@ func main() {
310316
startFileServer(storage.BasePath, storageAddr, setupLog)
311317
}()
312318

313-
if enabled, _ := features.Enabled(features.GitManagedTransport); enabled {
314-
managed.InitManagedTransport()
315-
} else {
316-
if optimize, _ := feathelper.Enabled(features.OptimizedGitClones); optimize {
317-
features.Disable(features.OptimizedGitClones)
318-
setupLog.Info(
319-
"disabling optimized git clones; git clones can only be optimized when using managed transport",
320-
)
321-
}
322-
}
323-
324319
setupLog.Info("starting manager")
325320
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
326321
setupLog.Error(err, "problem running manager")

0 commit comments

Comments
 (0)