Skip to content

Commit

Permalink
Implement Managed Transport for libgit2
Browse files Browse the repository at this point in the history
libgit2 network operations are blocking and do not provide timeout nor context capabilities,
leading for several reports by users of the controllers hanging indefinitely.

By using managed transport, golang primitives such as http.Transport and net.Dial can be used
to ensure timeouts are enforced.

Co-Authored-by: Sunny <darkowlzz@protonmail.com>
Signed-off-by: Paulo Gomes <paulo.gomes@weave.works>
  • Loading branch information
Paulo Gomes and darkowlzz committed Mar 11, 2022
1 parent 02c8fba commit dec736e
Show file tree
Hide file tree
Showing 8 changed files with 753 additions and 1 deletion.
30 changes: 29 additions & 1 deletion controllers/gitrepository_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
"github.com/fluxcd/source-controller/internal/reconcile/summarize"
"github.com/fluxcd/source-controller/internal/util"
"github.com/fluxcd/source-controller/pkg/git"
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
"github.com/fluxcd/source-controller/pkg/git/strategy"
"github.com/fluxcd/source-controller/pkg/sourceignore"
)
Expand Down Expand Up @@ -363,10 +364,37 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context,
return sreconcile.ResultEmpty, e
}

repositoryURL := obj.Spec.URL
// managed GIT transport only affects the libgit2 implementation
if managed.Enabled() && obj.Spec.GitImplementation == sourcev1.LibGit2Implementation {
// At present only HTTP connections have the ability to define remote options.
// Although this can be easily extended by ensuring that the fake URL below uses the
// target ssh scheme, and the libgit2/managed/ssh.go pulls that information accordingly.
//
// This is due to the fact the key libgit2 remote callbacks do not take place for HTTP
// whilst most still work for SSH.
if strings.HasPrefix(repositoryURL, "http") {
// Due to the lack of the callback feature, a fake target URL is created to allow
// for the smart sub transport be able to pick the options specific for this
// GitRepository object.
// The URL should use unique information that do not collide in a multi tenant
// deployment.
repositoryURL = fmt.Sprintf("http://%s/%s/%d", obj.Name, obj.UID, obj.Generation)
managed.AddTransportOptions(repositoryURL,
managed.TransportOptions{
TargetUrl: obj.Spec.URL,
CABundle: authOpts.CAFile,
})

// We remove the options from memory, to avoid accumulating unused options over time.
defer managed.RemoveTransportOptions(repositoryURL)
}
}

// Checkout HEAD of reference in object
gitCtx, cancel := context.WithTimeout(ctx, obj.Spec.Timeout.Duration)
defer cancel()
c, err := checkoutStrategy.Checkout(gitCtx, dir, obj.Spec.URL, authOpts)
c, err := checkoutStrategy.Checkout(gitCtx, dir, repositoryURL, authOpts)
if err != nil {
e := &serror.Event{
Err: fmt.Errorf("failed to checkout and determine revision: %w", err),
Expand Down
5 changes: 5 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/source-controller/controllers"
"github.com/fluxcd/source-controller/internal/helm"
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
// +kubebuilder:scaffold:imports
)

Expand Down Expand Up @@ -226,6 +227,10 @@ func main() {
startFileServer(storage.BasePath, storageAddr, setupLog)
}()

if managed.Enabled() {
managed.InitManagedTransport()
}

setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
Expand Down
18 changes: 18 additions & 0 deletions pkg/git/libgit2/managed/flag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package managed

import (
"os"
"strings"
)

// Enabled defines whether the use of Managed Transport should be enabled.
// This is only affects git operations that uses libgit2 implementation.
//
// True is returned when the environment variable `EXPERIMENTAL_GIT_TRANSPORT`
// is detected with the value of `true` or `1`.
func Enabled() bool {
if v, ok := os.LookupEnv("EXPERIMENTAL_GIT_TRANSPORT"); ok {
return strings.ToLower(v) == "true" || v == "1"
}
return false
}
Loading

0 comments on commit dec736e

Please sign in to comment.