Skip to content

Commit 1e51a0e

Browse files
Merge pull request #490 from wking/current-channels-by-digest
Bug 1879976: pkg/cvo: Compare Cincinnati data by digest when merging metadata
2 parents b2392e9 + 9bae4d6 commit 1e51a0e

File tree

4 files changed

+126
-6
lines changed

4 files changed

+126
-6
lines changed

pkg/cvo/availableupdates.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func calculateAvailableUpdatesStatus(ctx context.Context, clusterID string, prox
215215
}
216216
}
217217

218-
cvoCurrent, err = convertRetreivedUpdateToRelease(current)
218+
cvoCurrent, err = convertRetrievedUpdateToRelease(current)
219219
if err != nil {
220220
return cvoCurrent, nil, configv1.ClusterOperatorStatusCondition{
221221
Type: configv1.RetrievedUpdates, Status: configv1.ConditionFalse, Reason: "ResponseInvalid",
@@ -225,7 +225,7 @@ func calculateAvailableUpdatesStatus(ctx context.Context, clusterID string, prox
225225

226226
var cvoUpdates []configv1.Release
227227
for _, update := range updates {
228-
cvoUpdate, err := convertRetreivedUpdateToRelease(update)
228+
cvoUpdate, err := convertRetrievedUpdateToRelease(update)
229229
if err != nil {
230230
return cvoCurrent, nil, configv1.ClusterOperatorStatusCondition{
231231
Type: configv1.RetrievedUpdates, Status: configv1.ConditionFalse, Reason: "ResponseInvalid",
@@ -243,7 +243,7 @@ func calculateAvailableUpdatesStatus(ctx context.Context, clusterID string, prox
243243
}
244244
}
245245

246-
func convertRetreivedUpdateToRelease(update cincinnati.Update) (configv1.Release, error) {
246+
func convertRetrievedUpdateToRelease(update cincinnati.Update) (configv1.Release, error) {
247247
cvoUpdate := configv1.Release{
248248
Version: update.Version.String(),
249249
Image: update.Image,

pkg/cvo/cvo.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -614,11 +614,11 @@ func (optr *Operator) mergeReleaseMetadata(release configv1.Release) configv1.Re
614614
availableUpdates := optr.getAvailableUpdates()
615615
if availableUpdates != nil {
616616
var update *configv1.Release
617-
if merged.Image == availableUpdates.Current.Image {
617+
if equalDigest(merged.Image, availableUpdates.Current.Image) {
618618
update = &availableUpdates.Current
619619
} else {
620620
for _, u := range availableUpdates.Updates {
621-
if u.Image == merged.Image {
621+
if equalDigest(u.Image, merged.Image) {
622622
update = &u
623623
break
624624
}

pkg/cvo/sync_worker.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,11 +430,36 @@ func (w *SyncWorker) calculateNext(work *SyncWork) bool {
430430
}
431431

432432
// equalUpdate returns true if two updates are semantically equivalent.
433-
// It checks if the updates have have the same force and image values
433+
// It checks if the updates have have the same force and image values.
434+
//
435+
// We require complete pullspec equality, not just digest equality,
436+
// because we want to go through the usual update process even if it's
437+
// only the registry portion of the pullspec which has changed.
434438
func equalUpdate(a, b configv1.Update) bool {
435439
return a.Force == b.Force && a.Image == b.Image
436440
}
437441

442+
// equalDigest returns true if and only if the two pullspecs are
443+
// by-digest pullspecs and the digests are equal or the two pullspecs
444+
// are identical.
445+
func equalDigest(pullspecA string, pullspecB string) bool {
446+
if pullspecA == pullspecB {
447+
return true
448+
}
449+
digestA := splitDigest(pullspecA)
450+
return digestA != "" && digestA == splitDigest(pullspecB)
451+
}
452+
453+
// splitDigest returns the pullspec's digest, or an empty string if
454+
// the pullspec is not by-digest (e.g. it is by-tag, or implicit).
455+
func splitDigest(pullspec string) string {
456+
parts := strings.SplitN(pullspec, "@", 3)
457+
if len(parts) != 2 {
458+
return ""
459+
}
460+
return parts[1]
461+
}
462+
438463
// equalSyncWork returns true if a and b are equal.
439464
func equalSyncWork(a, b *SyncWork) bool {
440465
if a == b {

pkg/cvo/sync_worker_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,98 @@ func Test_runThrottledStatusNotifier(t *testing.T) {
189189
case <-time.After(100 * time.Millisecond):
190190
}
191191
}
192+
193+
func Test_equalDigest(t *testing.T) {
194+
for _, testCase := range []struct {
195+
name string
196+
pullspecA string
197+
pullspecB string
198+
expected bool
199+
}{
200+
{
201+
name: "both empty",
202+
pullspecA: "",
203+
pullspecB: "",
204+
expected: true,
205+
},
206+
{
207+
name: "A empty",
208+
pullspecA: "",
209+
pullspecB: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
210+
expected: false,
211+
},
212+
{
213+
name: "B empty",
214+
pullspecA: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
215+
pullspecB: "",
216+
expected: false,
217+
},
218+
{
219+
name: "A implicit tag",
220+
pullspecA: "example.com",
221+
pullspecB: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
222+
expected: false,
223+
},
224+
{
225+
name: "B implicit tag",
226+
pullspecA: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
227+
pullspecB: "example.com",
228+
expected: false,
229+
},
230+
{
231+
name: "A by tag",
232+
pullspecA: "example.com:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
233+
pullspecB: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
234+
expected: false,
235+
},
236+
{
237+
name: "B by tag",
238+
pullspecA: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
239+
pullspecB: "example.com:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
240+
expected: false,
241+
},
242+
{
243+
name: "identical by tag",
244+
pullspecA: "example.com:latest",
245+
pullspecB: "example.com:latest",
246+
expected: true,
247+
},
248+
{
249+
name: "different repositories, same tag",
250+
pullspecA: "a.example.com:latest",
251+
pullspecB: "b.example.com:latest",
252+
expected: false,
253+
},
254+
{
255+
name: "different repositories, same digest",
256+
pullspecA: "a.example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
257+
pullspecB: "b.example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
258+
expected: true,
259+
},
260+
{
261+
name: "same repository, different digests",
262+
pullspecA: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
263+
pullspecB: "example.com@sha256:01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b",
264+
expected: false,
265+
},
266+
{
267+
name: "A empty repository, same digest",
268+
pullspecA: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
269+
pullspecB: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
270+
expected: true,
271+
},
272+
{
273+
name: "B empty repository, same digest",
274+
pullspecA: "example.com@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
275+
pullspecB: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
276+
expected: true,
277+
},
278+
} {
279+
t.Run(testCase.name, func(t *testing.T) {
280+
actual := equalDigest(testCase.pullspecA, testCase.pullspecB)
281+
if actual != testCase.expected {
282+
t.Fatalf("got %t, not the expected %t", actual, testCase.expected)
283+
}
284+
})
285+
}
286+
}

0 commit comments

Comments
 (0)