Merge branch 'main' into 5411-kubectl-cosmetics
This commit is contained in:
commit
c4ddb04b87
|
|
@ -28,6 +28,7 @@ import (
|
|||
const ImageRepositoryKind = "ImageRepository"
|
||||
|
||||
// Deprecated: Use ImageFinalizer.
|
||||
// TODO: Remove in v1.
|
||||
const ImageRepositoryFinalizer = ImageFinalizer
|
||||
|
||||
// ImageRepositorySpec defines the parameters for scanning an image
|
||||
|
|
@ -115,10 +116,26 @@ type ImageRepositorySpec struct {
|
|||
Insecure bool `json:"insecure,omitempty"`
|
||||
}
|
||||
|
||||
// ScanResult contains information about the last scan of the image repository.
|
||||
// TODO: Make all fields except for LatestTags required in v1.
|
||||
type ScanResult struct {
|
||||
TagCount int `json:"tagCount"`
|
||||
ScanTime metav1.Time `json:"scanTime,omitempty"`
|
||||
LatestTags []string `json:"latestTags,omitempty"`
|
||||
// Revision is a stable hash of the scanned tags.
|
||||
// +optional
|
||||
Revision string `json:"revision"`
|
||||
|
||||
// TagCount is the number of tags found in the last scan.
|
||||
// +required
|
||||
TagCount int `json:"tagCount"`
|
||||
|
||||
// ScanTime is the time when the last scan was performed.
|
||||
// +optional
|
||||
ScanTime metav1.Time `json:"scanTime"`
|
||||
|
||||
// LatestTags is a small sample of the tags found in the last scan.
|
||||
// It's the first 10 tags when sorting all the tags in descending
|
||||
// alphabetical order.
|
||||
// +optional
|
||||
LatestTags []string `json:"latestTags,omitempty"`
|
||||
}
|
||||
|
||||
// ImageRepositoryStatus defines the observed state of ImageRepository
|
||||
|
|
|
|||
|
|
@ -496,13 +496,23 @@ spec:
|
|||
description: LastScanResult contains the number of fetched tags.
|
||||
properties:
|
||||
latestTags:
|
||||
description: |-
|
||||
LatestTags is a small sample of the tags found in the last scan.
|
||||
It's the first 10 tags when sorting all the tags in descending
|
||||
alphabetical order.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
revision:
|
||||
description: Revision is a stable hash of the scanned tags.
|
||||
type: string
|
||||
scanTime:
|
||||
description: ScanTime is the time when the last scan was performed.
|
||||
format: date-time
|
||||
type: string
|
||||
tagCount:
|
||||
description: TagCount is the number of tags found in the last
|
||||
scan.
|
||||
type: integer
|
||||
required:
|
||||
- tagCount
|
||||
|
|
|
|||
|
|
@ -1098,6 +1098,8 @@ would select 0.</p>
|
|||
(<em>Appears on:</em>
|
||||
<a href="#image.toolkit.fluxcd.io/v1beta2.ImageRepositoryStatus">ImageRepositoryStatus</a>)
|
||||
</p>
|
||||
<p>ScanResult contains information about the last scan of the image repository.
|
||||
TODO: Make all fields except for LatestTags required in v1.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
|
|
@ -1110,12 +1112,25 @@ would select 0.</p>
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>revision</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Revision is a stable hash of the scanned tags.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>tagCount</code><br>
|
||||
<em>
|
||||
int
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>TagCount is the number of tags found in the last scan.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
@ -1128,6 +1143,8 @@ Kubernetes meta/v1.Time
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ScanTime is the time when the last scan was performed.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
@ -1138,6 +1155,10 @@ Kubernetes meta/v1.Time
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>LatestTags is a small sample of the tags found in the last scan.
|
||||
It’s the first 10 tags when sorting all the tags in descending
|
||||
alphabetical order.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -13,7 +13,7 @@ require (
|
|||
github.com/fluxcd/pkg/apis/acl v0.7.0
|
||||
github.com/fluxcd/pkg/apis/event v0.17.0
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0
|
||||
github.com/fluxcd/pkg/auth v0.17.0
|
||||
github.com/fluxcd/pkg/auth v0.18.0
|
||||
github.com/fluxcd/pkg/cache v0.9.0
|
||||
github.com/fluxcd/pkg/runtime v0.60.0
|
||||
github.com/fluxcd/pkg/version v0.7.0
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -163,8 +163,8 @@ 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.12.0 h1:XW15TKZieC2b7MN8VS85stqZJOx+/b8jATQ/xTUhVYg=
|
||||
github.com/fluxcd/pkg/apis/meta v1.12.0/go.mod h1:+son1Va60x2eiDcTwd7lcctbI6C+K3gM7R+ULmEq1SI=
|
||||
github.com/fluxcd/pkg/auth v0.17.0 h1:jgum55f5K7Db6yI2bi4WeKojTzQS9KxlHCC0CsFs5x8=
|
||||
github.com/fluxcd/pkg/auth v0.17.0/go.mod h1:4h6s8VBNuec3tWd4xIReLw8BYPOKaIegjNMEbA4ikTU=
|
||||
github.com/fluxcd/pkg/auth v0.18.0 h1:71pGdKe0PVKWQvM3hEuyd3FD9dEUHtMuKMbUeiMl4aA=
|
||||
github.com/fluxcd/pkg/auth v0.18.0/go.mod h1:4h6s8VBNuec3tWd4xIReLw8BYPOKaIegjNMEbA4ikTU=
|
||||
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/runtime v0.60.0 h1:d++EkV3FlycB+bzakB5NumwY4J8xts8i7lbvD6jBLeU=
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package controller
|
|||
|
||||
// DatabaseWriter implementations record the tags for an image repository.
|
||||
type DatabaseWriter interface {
|
||||
SetTags(repo string, tags []string) error
|
||||
SetTags(repo string, tags []string) (string, error)
|
||||
}
|
||||
|
||||
// DatabaseReader implementations get the stored set of tags for an image
|
||||
|
|
|
|||
|
|
@ -164,15 +164,18 @@ func (imageRepositoryPredicate) Update(e event.UpdateEvent) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// This is a temporary workaround to avoid reconciling ImagePolicy
|
||||
// when the ImageRepository is not ready. In the near future, we
|
||||
// will implement a digest for the scanned tags in the ImageRepository
|
||||
// and will only return true here if the digest has changed, which
|
||||
// covers not only skipping the reconciliation when the ImageRepository
|
||||
// is not ready, but also when the tags have not changed.
|
||||
repo := e.ObjectNew.(*imagev1.ImageRepository)
|
||||
return conditions.IsReady(repo) &&
|
||||
conditions.GetObservedGeneration(repo, meta.ReadyCondition) == repo.Generation
|
||||
newRepo := e.ObjectNew.(*imagev1.ImageRepository)
|
||||
if newRepo.Status.LastScanResult == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
oldRepo := e.ObjectOld.(*imagev1.ImageRepository)
|
||||
if oldRepo.Status.LastScanResult == nil ||
|
||||
oldRepo.Status.LastScanResult.Revision != newRepo.Status.LastScanResult.Revision {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *ImagePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, retErr error) {
|
||||
|
|
|
|||
|
|
@ -185,6 +185,147 @@ func TestImagePolicyReconciler_ignoresImageRepoNotReadyEvent(t *testing.T) {
|
|||
}).Should(BeTrue())
|
||||
}
|
||||
|
||||
func TestImagePolicyReconciler_imageRepoRevisionLifeCycle(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
namespaceName := "imagepolicy-" + randStringRunes(5)
|
||||
namespace := &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: namespaceName},
|
||||
}
|
||||
g.Expect(k8sClient.Create(ctx, namespace)).ToNot(HaveOccurred())
|
||||
t.Cleanup(func() {
|
||||
g.Expect(k8sClient.Delete(ctx, namespace)).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
imageRepo := &imagev1.ImageRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespaceName,
|
||||
Name: "repo",
|
||||
},
|
||||
Spec: imagev1.ImageRepositorySpec{
|
||||
Image: "ghcr.io/stefanprodan/podinfo",
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(ctx, imageRepo)).NotTo(HaveOccurred())
|
||||
t.Cleanup(func() {
|
||||
g.Expect(k8sClient.Delete(ctx, imageRepo)).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imageRepo), imageRepo)
|
||||
return err == nil && conditions.IsReady(imageRepo) &&
|
||||
imageRepo.Generation == conditions.GetObservedGeneration(imageRepo, meta.ReadyCondition)
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
imagePolicy := &imagev1.ImagePolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: namespaceName,
|
||||
Name: "test-imagepolicy",
|
||||
},
|
||||
Spec: imagev1.ImagePolicySpec{
|
||||
ImageRepositoryRef: meta.NamespacedObjectReference{
|
||||
Name: imageRepo.Name,
|
||||
},
|
||||
FilterTags: &imagev1.TagFilter{
|
||||
Pattern: `^6\.7\.\d+$`,
|
||||
},
|
||||
Policy: imagev1.ImagePolicyChoice{
|
||||
SemVer: &imagev1.SemVerPolicy{
|
||||
Range: "6.7.x",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
g.Expect(k8sClient.Create(ctx, imagePolicy)).NotTo(HaveOccurred())
|
||||
t.Cleanup(func() {
|
||||
g.Expect(k8sClient.Delete(ctx, imagePolicy)).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imagePolicy), imagePolicy)
|
||||
return err == nil && conditions.IsReady(imagePolicy) &&
|
||||
imagePolicy.Generation == conditions.GetObservedGeneration(imagePolicy, meta.ReadyCondition) &&
|
||||
imagePolicy.Status.LatestRef != nil &&
|
||||
imagePolicy.Status.LatestRef.Tag == "6.7.1"
|
||||
}, timeout).Should(BeTrue())
|
||||
expectedImagePolicyLastTransitionTime := conditions.GetLastTransitionTime(imagePolicy, meta.ReadyCondition).Time
|
||||
|
||||
// Now force a reconciliation by setting the annotation.
|
||||
var requestedAt string
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imageRepo), imageRepo)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
p := patch.NewSerialPatcher(imageRepo, k8sClient)
|
||||
requestedAt = time.Now().Format(time.RFC3339Nano)
|
||||
if imageRepo.Annotations == nil {
|
||||
imageRepo.Annotations = make(map[string]string)
|
||||
}
|
||||
imageRepo.Annotations["reconcile.fluxcd.io/requestedAt"] = requestedAt
|
||||
return p.Patch(ctx, imageRepo) == nil
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
// Wait for the ImageRepository to reconcile.
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imageRepo), imageRepo)
|
||||
return err == nil && conditions.IsReady(imageRepo) &&
|
||||
imageRepo.Status.LastHandledReconcileAt == requestedAt
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
// Check that the ImagePolicy is still ready and does not get updated.
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imagePolicy), imagePolicy)
|
||||
return err == nil && conditions.IsReady(imagePolicy) &&
|
||||
imagePolicy.Status.LatestRef != nil &&
|
||||
imagePolicy.Status.LatestRef.Tag == "6.7.1"
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
// Wait a bit and check that the ImagePolicy remains ready.
|
||||
time.Sleep(time.Second)
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imagePolicy), imagePolicy)
|
||||
return err == nil && conditions.IsReady(imagePolicy) &&
|
||||
imagePolicy.Status.LatestRef != nil &&
|
||||
imagePolicy.Status.LatestRef.Tag == "6.7.1"
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
// Check that the last transition time of the ImagePolicy Ready condition did not change since the beginning.
|
||||
lastTransitionTime := conditions.GetLastTransitionTime(imagePolicy, meta.ReadyCondition).Time
|
||||
g.Expect(lastTransitionTime).To(Equal(expectedImagePolicyLastTransitionTime))
|
||||
|
||||
// Now add an exclusion rule to force the checksum to change.
|
||||
firstChecksum := imageRepo.Status.LastScanResult.Revision
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imageRepo), imageRepo)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
p := patch.NewSerialPatcher(imageRepo, k8sClient)
|
||||
imageRepo.Spec.ExclusionList = []string{`^6\.7\.1$`}
|
||||
return p.Patch(ctx, imageRepo) == nil
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
// Wait for the ImageRepository to reconcile.
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imageRepo), imageRepo)
|
||||
return err == nil && conditions.IsReady(imageRepo) &&
|
||||
imageRepo.Generation == conditions.GetObservedGeneration(imageRepo, meta.ReadyCondition) &&
|
||||
imageRepo.Status.LastScanResult.Revision != firstChecksum
|
||||
}, timeout).Should(BeTrue())
|
||||
|
||||
// Check that the ImagePolicy receives the update and the latest tag changes.
|
||||
g.Eventually(func() bool {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(imagePolicy), imagePolicy)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return conditions.IsReady(imagePolicy) &&
|
||||
imagePolicy.Generation == conditions.GetObservedGeneration(imagePolicy, meta.ReadyCondition) &&
|
||||
imagePolicy.Status.LatestRef.Tag == "6.7.0"
|
||||
}, timeout).Should(BeTrue())
|
||||
}
|
||||
|
||||
func TestImagePolicyReconciler_invalidImage(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
|
|
@ -111,8 +112,7 @@ type ImageRepositoryReconciler struct {
|
|||
DatabaseWriter
|
||||
DatabaseReader
|
||||
}
|
||||
DeprecatedLoginOpts []auth.Provider
|
||||
AuthOptionsGetter *registry.AuthOptionsGetter
|
||||
AuthOptionsGetter *registry.AuthOptionsGetter
|
||||
|
||||
patchOptions []patch.Option
|
||||
}
|
||||
|
|
@ -191,7 +191,8 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
|
|||
obj *imagev1.ImageRepository, startTime time.Time) (result ctrl.Result, retErr error) {
|
||||
oldObj := obj.DeepCopy()
|
||||
|
||||
var foundTags int
|
||||
var tagsChecksum string
|
||||
var numFoundTags int
|
||||
// Store a message about current reconciliation and next scan.
|
||||
var nextScanMsg string
|
||||
// Set a default next scan time before processing the object.
|
||||
|
|
@ -206,7 +207,7 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
|
|||
return true
|
||||
}
|
||||
|
||||
readyMsg := fmt.Sprintf("successful scan: found %d tags", foundTags)
|
||||
readyMsg := fmt.Sprintf("successful scan: found %d tags with checksum %s", numFoundTags, tagsChecksum)
|
||||
rs := reconcile.NewResultFinalizer(isSuccess, readyMsg)
|
||||
retErr = rs.Finalize(obj, result, retErr)
|
||||
|
||||
|
|
@ -270,7 +271,7 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
|
|||
Namespace: obj.GetNamespace(),
|
||||
Operation: cache.OperationReconcile,
|
||||
}
|
||||
opts, err := r.AuthOptionsGetter.GetOptions(ctx, obj, involvedObject, r.DeprecatedLoginOpts...)
|
||||
opts, err := r.AuthOptionsGetter.GetOptions(ctx, obj, involvedObject)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("failed to configure authentication options: %w", err)
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, imagev1.AuthenticationFailedReason, "%s", e)
|
||||
|
|
@ -301,20 +302,18 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
|
|||
return
|
||||
}
|
||||
|
||||
tags, err := r.scan(ctx, obj, ref, opts)
|
||||
if err != nil {
|
||||
if err := r.scan(ctx, obj, ref, opts); err != nil {
|
||||
e := fmt.Errorf("scan failed: %w", err)
|
||||
conditions.MarkFalse(obj, meta.ReadyCondition, imagev1.ReadOperationFailedReason, "%s", e)
|
||||
result, retErr = ctrl.Result{}, e
|
||||
return
|
||||
}
|
||||
foundTags = tags
|
||||
|
||||
nextScanMsg = fmt.Sprintf("next scan in %s", when.String())
|
||||
// Check if new tags were found.
|
||||
if oldObj.Status.LastScanResult != nil &&
|
||||
oldObj.Status.LastScanResult.TagCount == foundTags {
|
||||
nextScanMsg = "no new tags found, " + nextScanMsg
|
||||
oldObj.Status.LastScanResult.Revision == obj.Status.LastScanResult.Revision {
|
||||
nextScanMsg = "tags did not change, " + nextScanMsg
|
||||
} else {
|
||||
// When new tags are found, this message will be suppressed by
|
||||
// another event based on the new Ready=true status value. This is
|
||||
|
|
@ -322,9 +321,10 @@ func (r *ImageRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Ser
|
|||
nextScanMsg = "successful scan, " + nextScanMsg
|
||||
}
|
||||
} else {
|
||||
foundTags = obj.Status.LastScanResult.TagCount
|
||||
nextScanMsg = fmt.Sprintf("no change in repository configuration since last scan, next scan in %s", when.String())
|
||||
}
|
||||
tagsChecksum = obj.Status.LastScanResult.Revision
|
||||
numFoundTags = obj.Status.LastScanResult.TagCount
|
||||
|
||||
// Set the observations on the status.
|
||||
obj.Status.CanonicalImageName = ref.Context().String()
|
||||
|
|
@ -410,7 +410,7 @@ func (r *ImageRepositoryReconciler) shouldScan(obj imagev1.ImageRepository, now
|
|||
|
||||
// scan performs repository scanning and writes the scanned result in the
|
||||
// internal database and populates the status of the ImageRepository.
|
||||
func (r *ImageRepositoryReconciler) scan(ctx context.Context, obj *imagev1.ImageRepository, ref name.Reference, options []remote.Option) (int, error) {
|
||||
func (r *ImageRepositoryReconciler) scan(ctx context.Context, obj *imagev1.ImageRepository, ref name.Reference, options []remote.Option) error {
|
||||
timeout := obj.GetTimeout()
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
|
@ -419,24 +419,30 @@ func (r *ImageRepositoryReconciler) scan(ctx context.Context, obj *imagev1.Image
|
|||
|
||||
tags, err := remote.List(ref.Context(), options...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return err
|
||||
}
|
||||
|
||||
filteredTags, err := filterOutTags(tags, obj.GetExclusionList())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return err
|
||||
}
|
||||
|
||||
latestTags := sortTagsAndGetLatestTags(filteredTags)
|
||||
if len(latestTags) == 0 {
|
||||
latestTags = nil // for omission in json serialization when empty
|
||||
}
|
||||
|
||||
canonicalName := ref.Context().String()
|
||||
if err := r.Database.SetTags(canonicalName, filteredTags); err != nil {
|
||||
return 0, fmt.Errorf("failed to set tags for %q: %w", canonicalName, err)
|
||||
checksum, err := r.Database.SetTags(canonicalName, filteredTags)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set tags for %q: %w", canonicalName, err)
|
||||
}
|
||||
|
||||
scanTime := metav1.Now()
|
||||
obj.Status.LastScanResult = &imagev1.ScanResult{
|
||||
Revision: checksum,
|
||||
TagCount: len(filteredTags),
|
||||
ScanTime: scanTime,
|
||||
LatestTags: getLatestTags(filteredTags),
|
||||
ScanTime: metav1.Now(),
|
||||
LatestTags: latestTags,
|
||||
}
|
||||
|
||||
// If the reconcile request annotation was set, consider it
|
||||
|
|
@ -446,7 +452,7 @@ func (r *ImageRepositoryReconciler) scan(ctx context.Context, obj *imagev1.Image
|
|||
obj.Status.SetLastHandledReconcileRequest(token)
|
||||
}
|
||||
|
||||
return len(filteredTags), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// reconcileDelete handles the deletion of the object.
|
||||
|
|
@ -508,19 +514,15 @@ func filterOutTags(tags []string, patterns []string) ([]string, error) {
|
|||
return filteredTags, nil
|
||||
}
|
||||
|
||||
// getLatestTags takes a slice of tags, sorts them in descending order of their
|
||||
// values and returns the 10 latest tags.
|
||||
func getLatestTags(tags []string) []string {
|
||||
var result []string
|
||||
sort.SliceStable(tags, func(i, j int) bool { return tags[i] > tags[j] })
|
||||
|
||||
if len(tags) >= latestTagsCount {
|
||||
latestTags := tags[0:latestTagsCount]
|
||||
result = append(result, latestTags...)
|
||||
} else {
|
||||
result = append(result, tags...)
|
||||
}
|
||||
return result
|
||||
// sortTagsAndGetLatestTags takes a slice of tags, sorts them in-place
|
||||
// in descending order of their values and returns the 10 latest tags.
|
||||
func sortTagsAndGetLatestTags(tags []string) []string {
|
||||
slices.SortStableFunc(tags, func(a, b string) int { return -strings.Compare(a, b) })
|
||||
latestTags := tags[:min(len(tags), latestTagsCount)]
|
||||
// We can't return a slice of the original slice here because the original
|
||||
// slice can be too large and we want to free up that memory. Our copy has
|
||||
// at most latestTagsCount elements, which is specifically a small number.
|
||||
return slices.Clone(latestTags)
|
||||
}
|
||||
|
||||
// isEqualSliceContent compares two string slices to check if they have the same
|
||||
|
|
|
|||
|
|
@ -22,8 +22,10 @@ import (
|
|||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/adler32"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -56,12 +58,12 @@ type mockDatabase struct {
|
|||
}
|
||||
|
||||
// SetTags implements the DatabaseWriter interface of the Database.
|
||||
func (db *mockDatabase) SetTags(repo string, tags []string) error {
|
||||
func (db *mockDatabase) SetTags(repo string, tags []string) (string, error) {
|
||||
if db.WriteError != nil {
|
||||
return db.WriteError
|
||||
return "", db.WriteError
|
||||
}
|
||||
db.TagData = append(db.TagData, tags...)
|
||||
return nil
|
||||
return fmt.Sprintf("%v", adler32.Checksum([]byte(strings.Join(tags, ",")))), nil
|
||||
}
|
||||
|
||||
// Tags implements the DatabaseReader interface of the Database.
|
||||
|
|
@ -277,66 +279,74 @@ func TestImageRepositoryReconciler_scan(t *testing.T) {
|
|||
proxyAddr, proxyPort := test.NewProxy(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tags []string
|
||||
exclusionList []string
|
||||
annotation string
|
||||
db *mockDatabase
|
||||
proxyURL *url.URL
|
||||
wantErr string
|
||||
wantTags []string
|
||||
wantLatestTags []string
|
||||
name string
|
||||
tags []string
|
||||
exclusionList []string
|
||||
annotation string
|
||||
db *mockDatabase
|
||||
proxyURL *url.URL
|
||||
wantErr string
|
||||
wantChecksum string
|
||||
wantTags []string
|
||||
}{
|
||||
{
|
||||
name: "no tags",
|
||||
wantErr: "404 Not Found",
|
||||
},
|
||||
{
|
||||
name: "simple tags",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"a", "b", "c", "d"},
|
||||
wantLatestTags: []string{"d", "c", "b", "a"},
|
||||
name: "simple tags",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"d", "c", "b", "a"},
|
||||
},
|
||||
{
|
||||
name: "simple tags with proxy",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
db: &mockDatabase{},
|
||||
proxyURL: &url.URL{Scheme: "http", Host: proxyAddr},
|
||||
wantTags: []string{"a", "b", "c", "d"},
|
||||
wantLatestTags: []string{"d", "c", "b", "a"},
|
||||
name: "tags are sorted for checksum - order 1",
|
||||
tags: []string{"c", "d", "a", "b"},
|
||||
db: &mockDatabase{},
|
||||
wantChecksum: "139002383",
|
||||
wantTags: []string{"d", "c", "b", "a"},
|
||||
},
|
||||
{
|
||||
name: "simple tags with incorrect proxy",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
db: &mockDatabase{},
|
||||
proxyURL: &url.URL{Scheme: "http", Host: fmt.Sprintf("localhost:%d", proxyPort+1)},
|
||||
wantErr: "connection refused",
|
||||
wantTags: []string{"a", "b", "c", "d"},
|
||||
wantLatestTags: []string{"d", "c", "b", "a"},
|
||||
name: "tags are sorted for checksum - order 2",
|
||||
tags: []string{"c", "b", "a", "d"},
|
||||
db: &mockDatabase{},
|
||||
wantChecksum: "139002383",
|
||||
wantTags: []string{"d", "c", "b", "a"},
|
||||
},
|
||||
{
|
||||
name: "simple tags, 10+",
|
||||
tags: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"},
|
||||
wantLatestTags: []string{"k", "j", "i", "h, g, f, e, d, c, b"},
|
||||
name: "simple tags with proxy",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
db: &mockDatabase{},
|
||||
proxyURL: &url.URL{Scheme: "http", Host: proxyAddr},
|
||||
wantTags: []string{"d", "c", "b", "a"},
|
||||
},
|
||||
{
|
||||
name: "with single exclusion pattern",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
exclusionList: []string{"c"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"a", "b", "d"},
|
||||
wantLatestTags: []string{"d", "b", "a"},
|
||||
name: "simple tags with incorrect proxy",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
db: &mockDatabase{},
|
||||
proxyURL: &url.URL{Scheme: "http", Host: fmt.Sprintf("localhost:%d", proxyPort+1)},
|
||||
wantErr: "connection refused",
|
||||
wantTags: []string{"d", "c", "b", "a"},
|
||||
},
|
||||
{
|
||||
name: "with multiple exclusion pattern",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
exclusionList: []string{"c", "a"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"b", "d"},
|
||||
wantLatestTags: []string{"d", "b"},
|
||||
name: "more than maximum amount of tags for latest tags",
|
||||
tags: []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"k", "j", "i", "h", "g", "f", "e", "d", "c", "b", "a"},
|
||||
},
|
||||
{
|
||||
name: "with single exclusion pattern",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
exclusionList: []string{"c"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"d", "b", "a"},
|
||||
},
|
||||
{
|
||||
name: "with multiple exclusion pattern",
|
||||
tags: []string{"a", "b", "c", "d"},
|
||||
exclusionList: []string{"c", "a"},
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"d", "b"},
|
||||
},
|
||||
{
|
||||
name: "bad exclusion pattern",
|
||||
|
|
@ -351,12 +361,11 @@ func TestImageRepositoryReconciler_scan(t *testing.T) {
|
|||
wantErr: "failed to set tags",
|
||||
},
|
||||
{
|
||||
name: "with reconcile annotation",
|
||||
tags: []string{"a", "b"},
|
||||
annotation: "foo",
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"a", "b"},
|
||||
wantLatestTags: []string{"b", "a"},
|
||||
name: "with reconcile annotation",
|
||||
tags: []string{"a", "b"},
|
||||
annotation: "foo",
|
||||
db: &mockDatabase{},
|
||||
wantTags: []string{"b", "a"},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -393,7 +402,7 @@ func TestImageRepositoryReconciler_scan(t *testing.T) {
|
|||
opts = append(opts, remote.WithTransport(tr))
|
||||
}
|
||||
|
||||
tagCount, err := r.scan(context.TODO(), repo, ref, opts)
|
||||
err = r.scan(context.TODO(), repo, ref, opts)
|
||||
if tt.wantErr != "" {
|
||||
g.Expect(err).To(HaveOccurred())
|
||||
g.Expect(err.Error()).To(ContainSubstring(tt.wantErr))
|
||||
|
|
@ -401,10 +410,14 @@ func TestImageRepositoryReconciler_scan(t *testing.T) {
|
|||
g.Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
if err == nil {
|
||||
g.Expect(tagCount).To(Equal(len(tt.wantTags)))
|
||||
g.Expect(r.Database.Tags(imgRepo)).To(Equal(tt.wantTags))
|
||||
if tt.wantChecksum != "" {
|
||||
g.Expect(repo.Status.LastScanResult.Revision).To(Equal(tt.wantChecksum))
|
||||
}
|
||||
g.Expect(repo.Status.LastScanResult.TagCount).To(Equal(len(tt.wantTags)))
|
||||
g.Expect(repo.Status.LastScanResult.ScanTime).ToNot(BeZero())
|
||||
g.Expect(len(repo.Status.LastScanResult.LatestTags)).To(BeNumerically("<=", latestTagsCount))
|
||||
g.Expect(repo.Status.LastScanResult.LatestTags).To(Equal(tt.wantTags[:min(len(tt.wantTags), latestTagsCount)]))
|
||||
if tt.annotation != "" {
|
||||
g.Expect(repo.Status.LastHandledReconcileAt).To(Equal(tt.annotation))
|
||||
}
|
||||
|
|
@ -413,7 +426,7 @@ func TestImageRepositoryReconciler_scan(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetLatestTags(t *testing.T) {
|
||||
func TestSortTagsAndGetLatestTags(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tags []string
|
||||
|
|
@ -464,7 +477,7 @@ func TestGetLatestTags(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := NewWithT(t)
|
||||
|
||||
g.Expect(getLatestTags(tt.tags)).To(Equal(tt.wantLatestTags))
|
||||
g.Expect(sortTagsAndGetLatestTags(tt.tags)).To(Equal(tt.wantLatestTags))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package database
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/adler32"
|
||||
|
||||
"github.com/dgraph-io/badger/v3"
|
||||
)
|
||||
|
|
@ -54,15 +55,19 @@ func (a *BadgerDatabase) Tags(repo string) ([]string, error) {
|
|||
// the repo.
|
||||
//
|
||||
// It overwrites existing tag sets for the provided repo.
|
||||
func (a *BadgerDatabase) SetTags(repo string, tags []string) error {
|
||||
func (a *BadgerDatabase) SetTags(repo string, tags []string) (string, error) {
|
||||
b, err := marshal(tags)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
return a.db.Update(func(txn *badger.Txn) error {
|
||||
err = a.db.Update(func(txn *badger.Txn) error {
|
||||
e := badger.NewEntry(keyForRepo(tagsPrefix, repo), b)
|
||||
return txn.SetEntry(e)
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%v", adler32.Checksum(b)), nil
|
||||
}
|
||||
|
||||
func keyForRepo(prefix, repo string) []byte {
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ func TestBadgerGarbageCollectorDoesStop(t *testing.T) {
|
|||
time.Sleep(time.Second)
|
||||
|
||||
tags := []string{"latest", "v0.0.1", "v0.0.2"}
|
||||
fatalIfError(t, db.SetTags(testRepo, tags))
|
||||
_, err := db.Tags(testRepo)
|
||||
_, err := db.SetTags(testRepo, tags)
|
||||
fatalIfError(t, err)
|
||||
_, err = db.Tags(testRepo)
|
||||
fatalIfError(t, err)
|
||||
t.Log("wrote tags successfully")
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
|
@ -40,7 +41,7 @@ func TestSetTags(t *testing.T) {
|
|||
db := createBadgerDatabase(t)
|
||||
tags := []string{"latest", "v0.0.1", "v0.0.2"}
|
||||
|
||||
fatalIfError(t, db.SetTags(testRepo, tags))
|
||||
fatalIfError(t, setTags(t, db, testRepo, tags, "1943865137"))
|
||||
|
||||
loaded, err := db.Tags(testRepo)
|
||||
fatalIfError(t, err)
|
||||
|
|
@ -53,9 +54,9 @@ func TestSetTagsOverwrites(t *testing.T) {
|
|||
db := createBadgerDatabase(t)
|
||||
tags1 := []string{"latest", "v0.0.1", "v0.0.2"}
|
||||
tags2 := []string{"latest", "v0.0.1", "v0.0.2", "v0.0.3"}
|
||||
fatalIfError(t, db.SetTags(testRepo, tags1))
|
||||
fatalIfError(t, setTags(t, db, testRepo, tags1, "1943865137"))
|
||||
|
||||
fatalIfError(t, db.SetTags(testRepo, tags2))
|
||||
fatalIfError(t, setTags(t, db, testRepo, tags2, "3168012550"))
|
||||
|
||||
loaded, err := db.Tags(testRepo)
|
||||
fatalIfError(t, err)
|
||||
|
|
@ -67,10 +68,10 @@ func TestSetTagsOverwrites(t *testing.T) {
|
|||
func TestGetOnlyFetchesForRepo(t *testing.T) {
|
||||
db := createBadgerDatabase(t)
|
||||
tags1 := []string{"latest", "v0.0.1", "v0.0.2"}
|
||||
fatalIfError(t, db.SetTags(testRepo, tags1))
|
||||
fatalIfError(t, setTags(t, db, testRepo, tags1, "1943865137"))
|
||||
testRepo2 := "another/repo"
|
||||
tags2 := []string{"v0.0.3", "v0.0.4"}
|
||||
fatalIfError(t, db.SetTags(testRepo2, tags2))
|
||||
fatalIfError(t, setTags(t, db, testRepo2, tags2, "728958008"))
|
||||
|
||||
loaded, err := db.Tags(testRepo)
|
||||
fatalIfError(t, err)
|
||||
|
|
@ -96,6 +97,18 @@ func createBadgerDatabase(t *testing.T) *BadgerDatabase {
|
|||
return NewBadgerDatabase(db)
|
||||
}
|
||||
|
||||
func setTags(t *testing.T, db *BadgerDatabase, repo string, tags []string, expectedChecksum string) error {
|
||||
t.Helper()
|
||||
checksum, err := db.SetTags(repo, tags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if checksum != expectedChecksum {
|
||||
return fmt.Errorf("SetTags returned unexpected checksum: got %s, want %s", checksum, expectedChecksum)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fatalIfError(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/pkg/auth"
|
||||
"github.com/fluxcd/pkg/auth/aws"
|
||||
"github.com/fluxcd/pkg/auth/azure"
|
||||
"github.com/fluxcd/pkg/auth/gcp"
|
||||
authutils "github.com/fluxcd/pkg/auth/utils"
|
||||
"github.com/fluxcd/pkg/cache"
|
||||
|
||||
|
|
@ -57,7 +54,7 @@ type AuthOptionsGetter struct {
|
|||
}
|
||||
|
||||
func (r *AuthOptionsGetter) GetOptions(ctx context.Context, repo *imagev1.ImageRepository,
|
||||
involvedObject *cache.InvolvedObject, deprecatedLoginOpts ...auth.Provider) ([]remote.Option, error) {
|
||||
involvedObject *cache.InvolvedObject) ([]remote.Option, error) {
|
||||
timeout := repo.GetTimeout()
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
|
@ -98,36 +95,23 @@ func (r *AuthOptionsGetter) GetOptions(ctx context.Context, repo *imagev1.ImageR
|
|||
return nil, err
|
||||
}
|
||||
authenticator, authErr = secret.AuthFromSecret(authSecret, ref)
|
||||
} else {
|
||||
} else if provider := repo.GetProvider(); provider != "generic" {
|
||||
// Build login provider options and use it to attempt registry login.
|
||||
var opts []auth.Option
|
||||
if proxyURL != nil {
|
||||
opts = append(opts, auth.WithProxyURL(*proxyURL))
|
||||
}
|
||||
switch provider := repo.GetProvider(); provider {
|
||||
case aws.ProviderName, azure.ProviderName, gcp.ProviderName:
|
||||
// Support new features (service account and cache) only for non-deprecated code paths.
|
||||
if repo.Spec.ServiceAccountName != "" {
|
||||
serviceAccount := client.ObjectKey{
|
||||
Name: repo.Spec.ServiceAccountName,
|
||||
Namespace: repo.GetNamespace(),
|
||||
}
|
||||
opts = append(opts, auth.WithServiceAccount(serviceAccount, r.Client))
|
||||
}
|
||||
if r.TokenCache != nil {
|
||||
opts = append(opts, auth.WithCache(*r.TokenCache, *involvedObject))
|
||||
}
|
||||
authenticator, authErr = authutils.GetArtifactRegistryCredentials(ctx, provider, repo.Spec.Image, opts...)
|
||||
default:
|
||||
// Handle deprecated auto-login controller flags.
|
||||
for _, provider := range deprecatedLoginOpts {
|
||||
if _, err := provider.ParseArtifactRepository(repo.Spec.Image); err == nil {
|
||||
authenticator, authErr = authutils.GetArtifactRegistryCredentials(ctx,
|
||||
provider.GetName(), repo.Spec.Image, opts...)
|
||||
break
|
||||
}
|
||||
if repo.Spec.ServiceAccountName != "" {
|
||||
serviceAccount := client.ObjectKey{
|
||||
Name: repo.Spec.ServiceAccountName,
|
||||
Namespace: repo.GetNamespace(),
|
||||
}
|
||||
opts = append(opts, auth.WithServiceAccount(serviceAccount, r.Client))
|
||||
}
|
||||
if r.TokenCache != nil {
|
||||
opts = append(opts, auth.WithCache(*r.TokenCache, *involvedObject))
|
||||
}
|
||||
authenticator, authErr = authutils.GetArtifactRegistryCredentials(ctx, provider, repo.Spec.Image, opts...)
|
||||
}
|
||||
if authErr != nil {
|
||||
return nil, authErr
|
||||
|
|
|
|||
|
|
@ -260,6 +260,14 @@ func TestNewAuthOptionsGetter_GetOptions(t *testing.T) {
|
|||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "unsupported provider",
|
||||
imageRepoSpec: imagev1.ImageRepositorySpec{
|
||||
Image: testImg,
|
||||
Provider: "unsupported-provider",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
44
main.go
44
main.go
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
|
@ -38,9 +37,6 @@ import (
|
|||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
|
||||
"github.com/fluxcd/pkg/auth"
|
||||
"github.com/fluxcd/pkg/auth/aws"
|
||||
"github.com/fluxcd/pkg/auth/azure"
|
||||
"github.com/fluxcd/pkg/auth/gcp"
|
||||
pkgcache "github.com/fluxcd/pkg/cache"
|
||||
"github.com/fluxcd/pkg/runtime/acl"
|
||||
"github.com/fluxcd/pkg/runtime/client"
|
||||
|
|
@ -96,9 +92,6 @@ func main() {
|
|||
storageValueLogFileSize int64
|
||||
gcInterval uint16 // max value is 65535 minutes (~ 45 days) which is well under the maximum time.Duration
|
||||
concurrent int
|
||||
awsAutoLogin bool
|
||||
gcpAutoLogin bool
|
||||
azureAutoLogin bool
|
||||
aclOptions acl.Options
|
||||
rateLimiterOptions helper.RateLimiterOptions
|
||||
featureGates feathelper.FeatureGates
|
||||
|
|
@ -113,11 +106,6 @@ func main() {
|
|||
flag.Uint16Var(&gcInterval, "gc-interval", 10, "The number of minutes to wait between garbage collections. 0 disables the garbage collector.")
|
||||
flag.IntVar(&concurrent, "concurrent", 4, "The number of concurrent resource reconciles.")
|
||||
|
||||
// NOTE: Deprecated flags.
|
||||
flag.BoolVar(&awsAutoLogin, "aws-autologin-for-ecr", false, "(AWS) Attempt to get credentials for images in Elastic Container Registry, when no secret is referenced")
|
||||
flag.BoolVar(&gcpAutoLogin, "gcp-autologin-for-gcr", false, "(GCP) Attempt to get credentials for images in Google Container Registry, when no secret is referenced")
|
||||
flag.BoolVar(&azureAutoLogin, "azure-autologin-for-acr", false, "(Azure) Attempt to get credentials for images in Azure Container Registry, when no secret is referenced")
|
||||
|
||||
clientOptions.BindFlags(flag.CommandLine)
|
||||
logOptions.BindFlags(flag.CommandLine)
|
||||
leaderElectionOptions.BindFlags(flag.CommandLine)
|
||||
|
|
@ -131,12 +119,6 @@ func main() {
|
|||
|
||||
logger.SetLogger(logger.NewLogger(logOptions))
|
||||
|
||||
if awsAutoLogin || gcpAutoLogin || azureAutoLogin {
|
||||
setupLog.Error(errors.New("use of deprecated flags"),
|
||||
"autologin flags have been deprecated. These flags will be removed in a future release."+
|
||||
" Please update the respective ImageRepository objects with .spec.provider field.")
|
||||
}
|
||||
|
||||
if err := featureGates.WithLogger(setupLog).SupportedFeatures(features.FeatureGates()); err != nil {
|
||||
setupLog.Error(err, "unable to load feature gates")
|
||||
os.Exit(1)
|
||||
|
|
@ -265,31 +247,19 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
var deprecatedLoginOpts []auth.Provider
|
||||
if awsAutoLogin {
|
||||
deprecatedLoginOpts = append(deprecatedLoginOpts, aws.Provider{})
|
||||
}
|
||||
if azureAutoLogin {
|
||||
deprecatedLoginOpts = append(deprecatedLoginOpts, azure.Provider{})
|
||||
}
|
||||
if gcpAutoLogin {
|
||||
deprecatedLoginOpts = append(deprecatedLoginOpts, gcp.Provider{})
|
||||
}
|
||||
|
||||
authOptionsGetter := ®istry.AuthOptionsGetter{
|
||||
Client: mgr.GetClient(),
|
||||
TokenCache: tokenCache,
|
||||
}
|
||||
|
||||
if err := (&controller.ImageRepositoryReconciler{
|
||||
Client: mgr.GetClient(),
|
||||
EventRecorder: eventRecorder,
|
||||
Metrics: metricsH,
|
||||
Database: db,
|
||||
ControllerName: controllerName,
|
||||
TokenCache: tokenCache,
|
||||
AuthOptionsGetter: authOptionsGetter,
|
||||
DeprecatedLoginOpts: deprecatedLoginOpts,
|
||||
Client: mgr.GetClient(),
|
||||
EventRecorder: eventRecorder,
|
||||
Metrics: metricsH,
|
||||
Database: db,
|
||||
ControllerName: controllerName,
|
||||
TokenCache: tokenCache,
|
||||
AuthOptionsGetter: authOptionsGetter,
|
||||
}).SetupWithManager(mgr, controller.ImageRepositoryReconcilerOptions{
|
||||
RateLimiter: helper.GetRateLimiter(rateLimiterOptions),
|
||||
}); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue