Merge pull request #1790 from fluxcd/rfc-0010-oci
[RFC-0010] Introduce object-level workload identity for OCIRepository
This commit is contained in:
commit
e2538552af
|
@ -19,6 +19,12 @@ rules:
|
|||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- serviceaccounts/token
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- source.toolkit.fluxcd.io
|
||||
resources:
|
||||
|
|
8
go.mod
8
go.mod
|
@ -24,15 +24,15 @@ require (
|
|||
github.com/fluxcd/cli-utils v0.36.0-flux.13
|
||||
github.com/fluxcd/pkg/apis/event v0.17.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.11.0
|
||||
github.com/fluxcd/pkg/auth v0.11.0
|
||||
github.com/fluxcd/pkg/auth v0.12.0
|
||||
github.com/fluxcd/pkg/cache v0.9.0
|
||||
github.com/fluxcd/pkg/git v0.28.0
|
||||
github.com/fluxcd/pkg/git/gogit v0.30.0
|
||||
github.com/fluxcd/pkg/git v0.29.0
|
||||
github.com/fluxcd/pkg/git/gogit v0.31.0
|
||||
github.com/fluxcd/pkg/gittestserver v0.17.0
|
||||
github.com/fluxcd/pkg/helmtestserver v0.24.0
|
||||
github.com/fluxcd/pkg/lockedfile v0.6.0
|
||||
github.com/fluxcd/pkg/masktoken v0.7.0
|
||||
github.com/fluxcd/pkg/oci v0.47.0
|
||||
github.com/fluxcd/pkg/oci v0.48.0
|
||||
github.com/fluxcd/pkg/runtime v0.59.0
|
||||
github.com/fluxcd/pkg/sourceignore v0.12.0
|
||||
github.com/fluxcd/pkg/ssh v0.18.0
|
||||
|
|
16
go.sum
16
go.sum
|
@ -374,14 +374,14 @@ github.com/fluxcd/pkg/apis/event v0.17.0 h1:foEINE++pCJlWVhWjYDXfkVmGKu8mQ4BDBlb
|
|||
github.com/fluxcd/pkg/apis/event v0.17.0/go.mod h1:0fLhLFiHlRTDKPDXdRnv+tS7mCMIQ0fJxnEfmvGM/5A=
|
||||
github.com/fluxcd/pkg/apis/meta v1.11.0 h1:h8q95k6ZEK1HCfsLkt8Np3i6ktb6ZzcWJ6hg++oc9w0=
|
||||
github.com/fluxcd/pkg/apis/meta v1.11.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI=
|
||||
github.com/fluxcd/pkg/auth v0.11.0 h1:1BC6fQ71lCLFKz7juGlvWq9ysR2HVl5JPOWoxy4RMWE=
|
||||
github.com/fluxcd/pkg/auth v0.11.0/go.mod h1:BJVrbanLH0AoUBzOH7u016D21Zl3dvEd0AnAWVOo5Vs=
|
||||
github.com/fluxcd/pkg/auth v0.12.0 h1:35o0ziYMLZVgJwNvJBGsv/wd903B2fMagcrnm1ptUjc=
|
||||
github.com/fluxcd/pkg/auth v0.12.0/go.mod h1:gQD2VT5OhIR1E8ZTEsTaho3bDQZidr9P10smH/awcew=
|
||||
github.com/fluxcd/pkg/cache v0.9.0 h1:EGKfOLMG3fOwWnH/4Axl5xd425mxoQbZzlZoLfd8PDk=
|
||||
github.com/fluxcd/pkg/cache v0.9.0/go.mod h1:jMwabjWfsC5lW8hE7NM3wtGNwSJ38Javx6EKbEi7INU=
|
||||
github.com/fluxcd/pkg/git v0.28.0 h1:by7XTOvj4ZUPH1alYMJtDCVryhHue+UfjhrnPuJt5vA=
|
||||
github.com/fluxcd/pkg/git v0.28.0/go.mod h1:VPv6O3mYnYvn79LOdWAFCl4fE8o651cxW/p/yxBoq2g=
|
||||
github.com/fluxcd/pkg/git/gogit v0.30.0 h1:tdKRT4EDV8Cc2tBX+bg4H4gdcND7M4OEl6DQy1jSJmo=
|
||||
github.com/fluxcd/pkg/git/gogit v0.30.0/go.mod h1:UCm/fOBuvX43BNz7Rc61Sukp2gBG/qxlOASaBkwMFvc=
|
||||
github.com/fluxcd/pkg/git v0.29.0 h1:MHQ4F53e6Xt8a/POkd/fiChgysnd/XqiuK7vOWXAXLk=
|
||||
github.com/fluxcd/pkg/git v0.29.0/go.mod h1:Ygn+LfrK6Ok+85uiq6s3NWG5LcHS4KY7mzES2JDJsGY=
|
||||
github.com/fluxcd/pkg/git/gogit v0.31.0 h1:A56cmtgJBkWAj+gXSOdhPMQVTx0VF91S0PUaqpMXN4g=
|
||||
github.com/fluxcd/pkg/git/gogit v0.31.0/go.mod h1:ya8z22xTvAAdW12HycxKYv4S+G+lqu5Kx/LyO/jWz8Y=
|
||||
github.com/fluxcd/pkg/gittestserver v0.17.0 h1:JlBvWZQTDOI+np5Z+084m3DkeAH1hMusEybyRUDF63k=
|
||||
github.com/fluxcd/pkg/gittestserver v0.17.0/go.mod h1:E/40EmLoXcMqd6gLuLDC9F6KJxqHVGbBBeMNKk5XdxU=
|
||||
github.com/fluxcd/pkg/helmtestserver v0.24.0 h1:9sSfRG17GnDIup4sI8V+fdvKROtunU4JyIo34uvXq3Q=
|
||||
|
@ -390,8 +390,8 @@ github.com/fluxcd/pkg/lockedfile v0.6.0 h1:64RRMiPv3ZK9Y4sjI8c78kZAdfEo+Sjr2iP8a
|
|||
github.com/fluxcd/pkg/lockedfile v0.6.0/go.mod h1:gpdUVm7+05NIT1ZvzuNnHfnT81OhZtIySlxxkZ68pXk=
|
||||
github.com/fluxcd/pkg/masktoken v0.7.0 h1:pitmyOg2pUVdW+nn2Lk/xqm2TaA08uxvOC0ns3sz6bM=
|
||||
github.com/fluxcd/pkg/masktoken v0.7.0/go.mod h1:Lc1uoDjO1GY6+YdkK+ZqqBIBWquyV58nlSJ5S1N1IYU=
|
||||
github.com/fluxcd/pkg/oci v0.47.0 h1:eQ7syqy91Xcfd7Sgf64v5n+dfRAju/OBiXuOhZsgQAg=
|
||||
github.com/fluxcd/pkg/oci v0.47.0/go.mod h1:XBnI8+T6YFnIW4uEFojg7iIgHjKH7LXMpZARXJ9qmZk=
|
||||
github.com/fluxcd/pkg/oci v0.48.0 h1:iSK4JDM0nx9plSlOGx2aI4td6aQdV/awrfXK/bzI35I=
|
||||
github.com/fluxcd/pkg/oci v0.48.0/go.mod h1:rnUC8EOpzQp4rugpmopYFMnG3+CR1wqEV3356gHUtSY=
|
||||
github.com/fluxcd/pkg/runtime v0.59.0 h1:3OrFkMJB39NcQ2vhhoxqls59sQVSn8U+thhyLbsQoA4=
|
||||
github.com/fluxcd/pkg/runtime v0.59.0/go.mod h1:MFbfyNyyoYRgPxpdwC9/dCOkzo7Yxhu/cQ9NKyhvqc0=
|
||||
github.com/fluxcd/pkg/sourceignore v0.12.0 h1:jCIe6d50rQ3wdXPF0+PhhqN0XrTRIq3upMomPelI8Mw=
|
||||
|
|
|
@ -132,19 +132,17 @@ type GitRepositoryReconciler struct {
|
|||
|
||||
Storage *Storage
|
||||
ControllerName string
|
||||
TokenCache *cache.TokenCache
|
||||
|
||||
requeueDependency time.Duration
|
||||
features map[string]bool
|
||||
|
||||
patchOptions []patch.Option
|
||||
|
||||
tokenCache *cache.TokenCache
|
||||
}
|
||||
|
||||
type GitRepositoryReconcilerOptions struct {
|
||||
DependencyRequeueInterval time.Duration
|
||||
RateLimiter workqueue.TypedRateLimiter[reconcile.Request]
|
||||
TokenCache *cache.TokenCache
|
||||
}
|
||||
|
||||
// gitRepositoryReconcileFunc is the function type for all the
|
||||
|
@ -164,8 +162,6 @@ func (r *GitRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, o
|
|||
r.features = features.FeatureGates()
|
||||
}
|
||||
|
||||
r.tokenCache = opts.TokenCache
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&sourcev1.GitRepository{}, builder.WithPredicates(
|
||||
predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}),
|
||||
|
@ -689,14 +685,14 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
|
|||
|
||||
var authOpts []auth.Option
|
||||
|
||||
if r.tokenCache != nil {
|
||||
if r.TokenCache != nil {
|
||||
involvedObject := cache.InvolvedObject{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
Name: obj.GetName(),
|
||||
Namespace: obj.GetNamespace(),
|
||||
Operation: cache.OperationReconcile,
|
||||
}
|
||||
authOpts = append(authOpts, auth.WithCache(*r.tokenCache, involvedObject))
|
||||
authOpts = append(authOpts, auth.WithCache(*r.TokenCache, involvedObject))
|
||||
}
|
||||
|
||||
if proxyURL != nil {
|
||||
|
@ -726,7 +722,7 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
|
|||
GitHubOpts: []github.OptFunc{
|
||||
github.WithAppData(authData),
|
||||
github.WithProxyURL(proxyURL),
|
||||
github.WithCache(r.tokenCache, sourcev1.GitRepositoryKind,
|
||||
github.WithCache(r.TokenCache, sourcev1.GitRepositoryKind,
|
||||
obj.GetName(), obj.GetNamespace(), cache.OperationReconcile),
|
||||
},
|
||||
}
|
||||
|
@ -1150,7 +1146,7 @@ func (r *GitRepositoryReconciler) reconcileDelete(ctx context.Context, obj *sour
|
|||
controllerutil.RemoveFinalizer(obj, sourcev1.SourceFinalizer)
|
||||
|
||||
// Cleanup caches.
|
||||
r.tokenCache.DeleteEventsForObject(sourcev1.GitRepositoryKind,
|
||||
r.TokenCache.DeleteEventsForObject(sourcev1.GitRepositoryKind,
|
||||
obj.GetName(), obj.GetNamespace(), cache.OperationReconcile)
|
||||
|
||||
// Stop reconciliation as the object is being deleted
|
||||
|
|
|
@ -70,7 +70,6 @@ import (
|
|||
"github.com/fluxcd/source-controller/internal/helm/chart"
|
||||
"github.com/fluxcd/source-controller/internal/helm/getter"
|
||||
"github.com/fluxcd/source-controller/internal/helm/repository"
|
||||
"github.com/fluxcd/source-controller/internal/oci"
|
||||
soci "github.com/fluxcd/source-controller/internal/oci"
|
||||
scosign "github.com/fluxcd/source-controller/internal/oci/cosign"
|
||||
"github.com/fluxcd/source-controller/internal/oci/notation"
|
||||
|
@ -1255,7 +1254,7 @@ func observeChartBuild(ctx context.Context, sp *patch.SerialPatcher, pOpts []pat
|
|||
if build.Complete() {
|
||||
conditions.Delete(obj, sourcev1.FetchFailedCondition)
|
||||
conditions.Delete(obj, sourcev1.BuildFailedCondition)
|
||||
if build.VerifiedResult == oci.VerificationResultSuccess {
|
||||
if build.VerifiedResult == soci.VerificationResultSuccess {
|
||||
conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, meta.SucceededReason, "verified signature of version %s", build.Version)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ import (
|
|||
|
||||
eventv1 "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/fluxcd/pkg/auth"
|
||||
"github.com/fluxcd/pkg/cache"
|
||||
"github.com/fluxcd/pkg/oci"
|
||||
"github.com/fluxcd/pkg/runtime/conditions"
|
||||
helper "github.com/fluxcd/pkg/runtime/controller"
|
||||
|
@ -141,6 +143,7 @@ type OCIRepositoryReconciler struct {
|
|||
|
||||
Storage *Storage
|
||||
ControllerName string
|
||||
TokenCache *cache.TokenCache
|
||||
requeueDependency time.Duration
|
||||
|
||||
patchOptions []patch.Option
|
||||
|
@ -175,6 +178,7 @@ func (r *OCIRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, o
|
|||
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=ocirepositories/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=ocirepositories/finalizers,verbs=get;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
|
||||
// +kubebuilder:rbac:groups="",resources=serviceaccounts/token,verbs=create
|
||||
|
||||
func (r *OCIRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
|
||||
start := time.Now()
|
||||
|
@ -328,7 +332,7 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Seria
|
|||
// If this fails, it records v1beta2.FetchFailedCondition=True on the object and returns early.
|
||||
func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher,
|
||||
obj *ociv1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) {
|
||||
var auth authn.Authenticator
|
||||
var authenticator authn.Authenticator
|
||||
|
||||
ctxTimeout, cancel := context.WithTimeout(ctx, obj.Spec.Timeout.Duration)
|
||||
defer cancel()
|
||||
|
@ -363,9 +367,29 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
|
|||
}
|
||||
|
||||
if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != ociv1.GenericOCIProvider && ok {
|
||||
var opts []auth.Option
|
||||
if obj.Spec.ServiceAccountName != "" {
|
||||
serviceAccount := client.ObjectKey{
|
||||
Name: obj.Spec.ServiceAccountName,
|
||||
Namespace: obj.GetNamespace(),
|
||||
}
|
||||
opts = append(opts, auth.WithServiceAccount(serviceAccount, r.Client))
|
||||
}
|
||||
if r.TokenCache != nil {
|
||||
involvedObject := cache.InvolvedObject{
|
||||
Kind: ociv1.OCIRepositoryKind,
|
||||
Name: obj.GetName(),
|
||||
Namespace: obj.GetNamespace(),
|
||||
Operation: cache.OperationReconcile,
|
||||
}
|
||||
opts = append(opts, auth.WithCache(*r.TokenCache, involvedObject))
|
||||
}
|
||||
if proxyURL != nil {
|
||||
opts = append(opts, auth.WithProxyURL(*proxyURL))
|
||||
}
|
||||
var authErr error
|
||||
auth, authErr = soci.OIDCAuth(ctxTimeout, obj.Spec.URL, obj.Spec.Provider, proxyURL)
|
||||
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
|
||||
authenticator, authErr = soci.OIDCAuth(ctxTimeout, obj.Spec.URL, obj.Spec.Provider, opts...)
|
||||
if authErr != nil {
|
||||
e := serror.NewGeneric(
|
||||
fmt.Errorf("failed to get credential from %s: %w", obj.Spec.Provider, authErr),
|
||||
sourcev1.AuthenticationFailedReason,
|
||||
|
@ -386,7 +410,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
|
|||
return sreconcile.ResultEmpty, e
|
||||
}
|
||||
|
||||
opts := makeRemoteOptions(ctx, transport, keychain, auth)
|
||||
opts := makeRemoteOptions(ctx, transport, keychain, authenticator)
|
||||
|
||||
// Determine which artifact revision to pull
|
||||
ref, err := r.getArtifactRef(obj, opts)
|
||||
|
@ -446,7 +470,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
|
|||
conditions.GetObservedGeneration(obj, sourcev1.SourceVerifiedCondition) != obj.Generation ||
|
||||
conditions.IsFalse(obj, sourcev1.SourceVerifiedCondition) {
|
||||
|
||||
result, err := r.verifySignature(ctx, obj, ref, keychain, auth, transport, opts...)
|
||||
result, err := r.verifySignature(ctx, obj, ref, keychain, authenticator, transport, opts...)
|
||||
if err != nil {
|
||||
provider := obj.Spec.Verify.Provider
|
||||
if obj.Spec.Verify.SecretRef == nil && obj.Spec.Verify.Provider == "cosign" {
|
||||
|
@ -1225,6 +1249,10 @@ func (r *OCIRepositoryReconciler) reconcileDelete(ctx context.Context, obj *ociv
|
|||
// Remove our finalizer from the list
|
||||
controllerutil.RemoveFinalizer(obj, sourcev1.SourceFinalizer)
|
||||
|
||||
// Cleanup caches.
|
||||
r.TokenCache.DeleteEventsForObject(ociv1.OCIRepositoryKind,
|
||||
obj.GetName(), obj.GetNamespace(), cache.OperationReconcile)
|
||||
|
||||
// Stop reconciliation as the object is being deleted
|
||||
return sreconcile.ResultEmpty, nil
|
||||
}
|
||||
|
|
|
@ -872,9 +872,9 @@ func TestOCIRepository_CertSecret(t *testing.T) {
|
|||
|
||||
tlsSecretClientCert := corev1.Secret{
|
||||
Data: map[string][]byte{
|
||||
oci.CACert: tlsCA,
|
||||
oci.ClientCert: clientPublicKey,
|
||||
oci.ClientKey: clientPrivateKey,
|
||||
"caFile": tlsCA,
|
||||
"certFile": clientPublicKey,
|
||||
"keyFile": clientPrivateKey,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -907,9 +907,9 @@ func TestOCIRepository_CertSecret(t *testing.T) {
|
|||
digest: pi.digest,
|
||||
certSecret: &corev1.Secret{
|
||||
Data: map[string][]byte{
|
||||
oci.CACert: tlsCA,
|
||||
oci.ClientCert: clientPublicKey,
|
||||
oci.ClientKey: []byte("invalid-key"),
|
||||
"caFile": tlsCA,
|
||||
"certFile": clientPublicKey,
|
||||
"keyFile": []byte("invalid-key"),
|
||||
},
|
||||
},
|
||||
expectreadyconition: false,
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/fluxcd/pkg/oci"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
helmgetter "helm.sh/helm/v3/pkg/getter"
|
||||
helmreg "helm.sh/helm/v3/pkg/registry"
|
||||
|
@ -137,8 +136,8 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepos
|
|||
}
|
||||
}
|
||||
} else if obj.Spec.Provider != sourcev1beta2.GenericOCIProvider && obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI && ociRepo {
|
||||
authenticator, authErr := soci.OIDCAuth(ctx, obj.Spec.URL, obj.Spec.Provider, nil)
|
||||
if authErr != nil && !errors.Is(authErr, oci.ErrUnconfiguredProvider) {
|
||||
authenticator, authErr := soci.OIDCAuth(ctx, obj.Spec.URL, obj.Spec.Provider)
|
||||
if authErr != nil {
|
||||
return nil, "", fmt.Errorf("failed to get credential from '%s': %w", obj.Spec.Provider, authErr)
|
||||
}
|
||||
if authenticator != nil {
|
||||
|
|
|
@ -18,13 +18,12 @@ package oci
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/pkg/oci/auth/login"
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
|
||||
"github.com/fluxcd/pkg/auth"
|
||||
authutils "github.com/fluxcd/pkg/auth/utils"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||
)
|
||||
|
@ -41,22 +40,7 @@ func (a Anonymous) Resolve(_ authn.Resource) (authn.Authenticator, error) {
|
|||
}
|
||||
|
||||
// OIDCAuth generates the OIDC credential authenticator based on the specified cloud provider.
|
||||
func OIDCAuth(ctx context.Context, url, provider string, proxyURL *url.URL) (authn.Authenticator, error) {
|
||||
func OIDCAuth(ctx context.Context, url, provider string, opts ...auth.Option) (authn.Authenticator, error) {
|
||||
u := strings.TrimPrefix(url, sourcev1.OCIRepositoryPrefix)
|
||||
ref, err := name.ParseReference(u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URL '%s': %w", u, err)
|
||||
}
|
||||
|
||||
opts := login.ProviderOptions{}
|
||||
switch provider {
|
||||
case sourcev1.AmazonOCIProvider:
|
||||
opts.AwsAutoLogin = true
|
||||
case sourcev1.AzureOCIProvider:
|
||||
opts.AzureAutoLogin = true
|
||||
case sourcev1.GoogleOCIProvider:
|
||||
opts.GcpAutoLogin = true
|
||||
}
|
||||
|
||||
return login.NewManager(login.WithProxyURL(proxyURL)).Login(ctx, u, ref, opts)
|
||||
return authutils.GetArtifactRegistryCredentials(ctx, provider, u, opts...)
|
||||
}
|
||||
|
|
3
main.go
3
main.go
|
@ -216,10 +216,10 @@ func main() {
|
|||
Metrics: metrics,
|
||||
Storage: storage,
|
||||
ControllerName: controllerName,
|
||||
TokenCache: tokenCache,
|
||||
}).SetupWithManagerAndOptions(mgr, controller.GitRepositoryReconcilerOptions{
|
||||
DependencyRequeueInterval: requeueDependency,
|
||||
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
|
||||
TokenCache: tokenCache,
|
||||
}); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", v1.GitRepositoryKind)
|
||||
os.Exit(1)
|
||||
|
@ -278,6 +278,7 @@ func main() {
|
|||
Storage: storage,
|
||||
EventRecorder: eventRecorder,
|
||||
ControllerName: controllerName,
|
||||
TokenCache: tokenCache,
|
||||
Metrics: metrics,
|
||||
}).SetupWithManagerAndOptions(mgr, controller.OCIRepositoryReconcilerOptions{
|
||||
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
|
||||
|
|
Loading…
Reference in New Issue