Skip to content

Commit 54e96e9

Browse files
committed
Updates garbage collection for orphaned ReleasePayloads to use coordinated deletion via remove__ prefixed tags in quay.io
1 parent a57aa87 commit 54e96e9

4 files changed

Lines changed: 120 additions & 4 deletions

File tree

cmd/release-controller/sync.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,8 +490,14 @@ func (c *Controller) syncReady(release *releasecontroller.Release) error {
490490
mirror, err := releasecontroller.GetMirror(release, releaseTag.Name, c.releaseLister)
491491
if err != nil {
492492
klog.Errorf("Failed to identify `from` mirror for creation of release mirror job: %v", err)
493-
} else if _, err := c.ensureReleaseMirrorJob(release, releaseTag.Name, mirror); err != nil {
494-
klog.Errorf("Failed to create release mirror job: %v", err)
493+
} else {
494+
if _, err := c.ensureReleaseMirrorJob(release, releaseTag.Name, mirror); err != nil {
495+
klog.Errorf("Failed to create release mirror job: %v", err)
496+
}
497+
// For CI payloads, also create rc_payload__ tag for pruner to preserve component images
498+
if _, err := c.ensureRCPayloadTagJob(release, releaseTag.Name, mirror); err != nil {
499+
klog.Errorf("Failed to create rc_payload__ tag job: %v", err)
500+
}
495501
}
496502

497503
if err := c.ensureReleaseUpgradeJobs(release, releaseTag); err != nil {

cmd/release-controller/sync_gc.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,27 @@ func (c *Controller) garbageCollectSync() error {
122122
}
123123
}
124124

125-
// all releasepayloads created for releases that no longer exist should be deleted
125+
// all releasepayloads created for releases that no longer exist should be garbage collected
126126
for _, payload := range payloads {
127127
if active.Has(payload.Name) {
128128
continue
129129
}
130+
131+
// Get the release config from the ImageStream to check if alternate repository is configured
132+
imageStream, err := c.releaseLister.ImageStreams(payload.Spec.PayloadCoordinates.Namespace).Get(payload.Spec.PayloadCoordinates.ImagestreamName)
133+
if err == nil {
134+
release, ok, err := releasecontroller.ReleaseDefinition(imageStream, c.parsedReleaseConfigCache, c.eventRecorder, *c.releaseLister)
135+
if err == nil && ok && len(release.Config.AlternateImageRepository) > 0 && len(release.Config.AlternateImageRepositorySecretName) > 0 {
136+
_, err := c.ensureRemoveTagJob(payload, release)
137+
if err != nil {
138+
klog.V(2).Infof("Failed to create remove tag job for releasepayload %s/%s: %v, proceeding with direct deletion", payload.Namespace, payload.Name, err)
139+
} else {
140+
klog.V(2).Infof("Created remove tag job for orphaned releasepayload %s/%s, pruner will handle quay.io tag deletion", payload.Namespace, payload.Name)
141+
}
142+
}
143+
}
144+
145+
// Delete the ReleasePayload
130146
klog.V(2).Infof("Removing orphaned releasepayload %s/%s", payload.Namespace, payload.Name)
131147
if err := c.releasePayloadClient.ReleasePayloads(payload.Namespace).Delete(context.TODO(), payload.Name, metav1.DeleteOptions{}); err != nil && !errors.IsNotFound(err) {
132148
utilruntime.HandleError(fmt.Errorf("can't delete orphaned releasepayload %s/%s: %v", payload.Namespace, payload.Name, err))

cmd/release-controller/sync_release.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"context"
55
"fmt"
66
"strconv"
7+
"strings"
78
"time"
89

10+
"github.com/openshift/release-controller/pkg/apis/release/v1alpha1"
911
releasecontroller "github.com/openshift/release-controller/pkg/release-controller"
1012

1113
batchv1 "k8s.io/api/batch/v1"
@@ -417,3 +419,95 @@ func (c *Controller) ensureReleaseMirrorJob(release *releasecontroller.Release,
417419
func releaseMirrorJobName(tagName string) string {
418420
return fmt.Sprintf("%s-alternate-mirror", tagName)
419421
}
422+
423+
// ensureRCPayloadTagJob creates a job to mirror the release to rc_payload__{version} in quay.io for CI payloads
424+
// This is required for the pruner to preserve component images referenced by CI payloads
425+
func (c *Controller) ensureRCPayloadTagJob(release *releasecontroller.Release, name string, mirror *imagev1.ImageStream) (*batchv1.Job, error) {
426+
if len(release.Config.AlternateImageRepository) == 0 || len(release.Config.AlternateImageRepositorySecretName) == 0 {
427+
return nil, fmt.Errorf("alternate repository or secret not configured")
428+
}
429+
430+
// Only create rc_payload__ tags for CI payloads (tags containing .ci-)
431+
// Nightly payloads reference ART images that are permanently stored
432+
if !strings.Contains(name, ".ci-") {
433+
return nil, nil
434+
}
435+
436+
jobName := fmt.Sprintf("%s-rc-payload-tag", name)
437+
return c.ensureJob(jobName, nil, func() (*batchv1.Job, error) {
438+
fromImage := fmt.Sprintf("%s:%s", release.Target.Status.PublicDockerImageRepository, name)
439+
rcPayloadTag := fmt.Sprintf("rc_payload__%s", name)
440+
toImage := fmt.Sprintf("%s:%s", release.Config.AlternateImageRepository, rcPayloadTag)
441+
442+
cliImage := fmt.Sprintf("%s:cli", mirror.Status.DockerImageRepository)
443+
if len(release.Config.OverrideCLIImage) > 0 {
444+
cliImage = release.Config.OverrideCLIImage
445+
}
446+
447+
job, prefix := newReleaseJobBase(jobName, cliImage, release.Config.AlternateImageRepositorySecretName)
448+
449+
manifestListMode := "false"
450+
if c.manifestListMode && !release.Config.DisableManifestListMode {
451+
manifestListMode = "true"
452+
}
453+
454+
job.Spec.Template.Spec.Containers[0].Command = []string{
455+
"/bin/bash", "-c",
456+
prefix + `
457+
oc image mirror --keep-manifest-list=$1 $2 $3
458+
`,
459+
"",
460+
manifestListMode, fromImage, toImage,
461+
}
462+
463+
job.Annotations[releasecontroller.ReleaseAnnotationSource] = mirror.Annotations[releasecontroller.ReleaseAnnotationSource]
464+
job.Annotations[releasecontroller.ReleaseAnnotationTarget] = mirror.Annotations[releasecontroller.ReleaseAnnotationTarget]
465+
job.Annotations[releasecontroller.ReleaseAnnotationGeneration] = strconv.FormatInt(release.Target.Generation, 10)
466+
job.Annotations[releasecontroller.ReleaseAnnotationReleaseTag] = mirror.Annotations[releasecontroller.ReleaseAnnotationReleaseTag]
467+
468+
klog.V(2).Infof("Creating rc_payload__ tag job %s/%s to mirror %s to %s", c.jobNamespace, job.Name, fromImage, toImage)
469+
return job, nil
470+
})
471+
}
472+
473+
// ensureRemoveTagJob creates a job to copy the release tag to remove__rc_payload__{version} in quay.io
474+
func (c *Controller) ensureRemoveTagJob(payload *v1alpha1.ReleasePayload, release *releasecontroller.Release) (*batchv1.Job, error) {
475+
if len(release.Config.AlternateImageRepository) == 0 || len(release.Config.AlternateImageRepositorySecretName) == 0 {
476+
return nil, fmt.Errorf("alternate repository or secret not configured")
477+
}
478+
479+
jobName := fmt.Sprintf("%s-remove-tag", payload.Name)
480+
return c.ensureJob(jobName, nil, func() (*batchv1.Job, error) {
481+
// Get cli image from mirror or config
482+
cliImage := "registry.ci.openshift.org/ocp/4.21:cli"
483+
if mirror, err := c.releaseLister.ImageStreams(release.Target.Namespace).Get(release.Target.Name); err == nil {
484+
cliImage = fmt.Sprintf("%s:cli", mirror.Status.DockerImageRepository)
485+
}
486+
if len(release.Config.OverrideCLIImage) > 0 {
487+
cliImage = release.Config.OverrideCLIImage
488+
}
489+
490+
job, prefix := newReleaseJobBase(jobName, cliImage, release.Config.AlternateImageRepositorySecretName)
491+
492+
// Mirror from the actual release tag (which exists in quay.io) to the removal request tag
493+
// The pruner only cares about the tag name, not the content
494+
removeTag := fmt.Sprintf("remove__rc_payload__%s", payload.Name)
495+
fromImage := fmt.Sprintf("%s:%s", release.Config.AlternateImageRepository, payload.Name)
496+
toImage := fmt.Sprintf("%s:%s", release.Config.AlternateImageRepository, removeTag)
497+
498+
job.Spec.Template.Spec.Containers[0].Command = []string{
499+
"/bin/bash", "-c",
500+
prefix + `
501+
oc image mirror --keep-manifest-list=true $1 $2
502+
`,
503+
"",
504+
fromImage, toImage,
505+
}
506+
507+
job.Annotations[releasecontroller.ReleaseAnnotationReleaseTag] = payload.Name
508+
job.Annotations[releasecontroller.ReleaseAnnotationTarget] = fmt.Sprintf("%s/%s", payload.Spec.PayloadCoordinates.Namespace, payload.Spec.PayloadCoordinates.ImagestreamName)
509+
510+
klog.V(2).Infof("Creating remove tag job %s/%s to copy %s to %s", c.jobNamespace, job.Name, fromImage, toImage)
511+
return job, nil
512+
})
513+
}

pkg/release-controller/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ type ReleaseConfig struct {
152152
// AlternateImageRepository is the full path to an external Image Repository where we
153153
// will mirror Accepted releases to.
154154
// For example:
155-
// "alternateImageRepository": "quay.io/openshift-release-dev/dev-release"
155+
// "alternateImageRepository": "quay.io/openshift/ci"
156156
AlternateImageRepository string `json:"alternateImageRepository"`
157157

158158
// AlternateImageRepositorySecret is the name of the secret containing credentials to the

0 commit comments

Comments
 (0)