Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion cmd/release-controller/sync_gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,29 @@ func (c *Controller) garbageCollectSync() error {
}
}

// all releasepayloads created for releases that no longer exist should be deleted
// all releasepayloads created for releases that no longer exist should be garbage collected
// Use coordinated deletion via remove__ prefixed tags in quay.io, allowing the pruner to handle tag deletion
for _, payload := range payloads {
if active.Has(payload.Name) {
continue
}

// Get the release config from the ImageStream to check if alternate repository is configured
imageStream, err := c.releaseLister.ImageStreams(payload.Spec.PayloadCoordinates.Namespace).Get(payload.Spec.PayloadCoordinates.ImagestreamName)
if err == nil {
release, ok, err := releasecontroller.ReleaseDefinition(imageStream, c.parsedReleaseConfigCache, c.eventRecorder, *c.releaseLister)
if err == nil && ok && len(release.Config.AlternateImageRepository) > 0 && len(release.Config.AlternateImageRepositorySecretName) > 0 {
// Create a job to copy rc_payload__{version} to remove__rc_payload__{version}
_, err := c.ensureRemoveTagJob(payload, release)
if err != nil {
klog.V(2).Infof("Failed to create remove tag job for releasepayload %s/%s: %v, proceeding with direct deletion", payload.Namespace, payload.Name, err)
} else {
klog.V(2).Infof("Created remove tag job for orphaned releasepayload %s/%s, pruner will handle quay.io tag deletion", payload.Namespace, payload.Name)
}
}
}

// Delete the ReleasePayload
klog.V(2).Infof("Removing orphaned releasepayload %s/%s", payload.Namespace, payload.Name)
if err := c.releasePayloadClient.ReleasePayloads(payload.Namespace).Delete(context.TODO(), payload.Name, metav1.DeleteOptions{}); err != nil && !errors.IsNotFound(err) {
utilruntime.HandleError(fmt.Errorf("can't delete orphaned releasepayload %s/%s: %v", payload.Namespace, payload.Name, err))
Expand Down
42 changes: 42 additions & 0 deletions cmd/release-controller/sync_release.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strconv"
"time"

"github.com/openshift/release-controller/pkg/apis/release/v1alpha1"
releasecontroller "github.com/openshift/release-controller/pkg/release-controller"

batchv1 "k8s.io/api/batch/v1"
Expand Down Expand Up @@ -417,3 +418,44 @@ func (c *Controller) ensureReleaseMirrorJob(release *releasecontroller.Release,
func releaseMirrorJobName(tagName string) string {
return fmt.Sprintf("%s-alternate-mirror", tagName)
}

// ensureRemoveTagJob creates a job to copy rc_payload__{version} to remove__rc_payload__{version} in quay.io
func (c *Controller) ensureRemoveTagJob(payload *v1alpha1.ReleasePayload, release *releasecontroller.Release) (*batchv1.Job, error) {
if len(release.Config.AlternateImageRepository) == 0 || len(release.Config.AlternateImageRepositorySecretName) == 0 {
return nil, fmt.Errorf("alternate repository or secret not configured")
}

jobName := fmt.Sprintf("%s-remove-tag", payload.Name)
return c.ensureJob(jobName, nil, func() (*batchv1.Job, error) {
// Get cli image from mirror or config
cliImage := "registry.ci.openshift.org/ocp/4.16:cli"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Don't like this being hard-coded
  2. If it must be hard-coded, then it should, at least, point to a more modern version (like: 4.21)

if mirror, err := c.releaseLister.ImageStreams(release.Target.Namespace).Get(release.Target.Name); err == nil {
cliImage = fmt.Sprintf("%s:cli", mirror.Status.DockerImageRepository)
}
if len(release.Config.OverrideCLIImage) > 0 {
cliImage = release.Config.OverrideCLIImage
}

job, prefix := newReleaseJobBase(jobName, cliImage, release.Config.AlternateImageRepositorySecretName)

rcPayloadTag := fmt.Sprintf("rc_payload__%s", payload.Name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently do not create release tags named anything like: rc_payload__{version}, so this logic does not make any sense to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will be using similar here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused...
Based on this logic, the calculated "fromImage" will be something of the form: rc_payload__4.22.0-0.nightly-2025-12-17-101159
Which will be passed into oc mirror <FROM> <TO>, correct?
What I'm questioning is why you think the "FROM" image even exists with that naming convention?
AFAIK, the release-controller doesn't have any logic to create such a named release.

removeTag := fmt.Sprintf("remove__rc_payload__%s", payload.Name)
fromImage := fmt.Sprintf("%s:%s", release.Config.AlternateImageRepository, rcPayloadTag)
toImage := fmt.Sprintf("%s:%s", release.Config.AlternateImageRepository, removeTag)

job.Spec.Template.Spec.Containers[0].Command = []string{
"/bin/bash", "-c",
prefix + `
oc image mirror --keep-manifest-list=true $1 $2
`,
"",
fromImage, toImage,
}

job.Annotations[releasecontroller.ReleaseAnnotationReleaseTag] = payload.Name
job.Annotations[releasecontroller.ReleaseAnnotationTarget] = fmt.Sprintf("%s/%s", payload.Spec.PayloadCoordinates.Namespace, payload.Spec.PayloadCoordinates.ImagestreamName)

klog.V(2).Infof("Creating remove tag job %s/%s to copy %s to %s", c.jobNamespace, job.Name, fromImage, toImage)
return job, nil
})
}
2 changes: 1 addition & 1 deletion pkg/release-controller/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ type ReleaseConfig struct {
// AlternateImageRepository is the full path to an external Image Repository where we
// will mirror Accepted releases to.
// For example:
// "alternateImageRepository": "quay.io/openshift-release-dev/dev-release"
// "alternateImageRepository": "quay.io/openshift/ci"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is literally just a comment reference. If/when this goes live, you'll need to update all the respective references, like here: https://github.com/openshift/release/blob/6e2ede7d8f765e123cb1c0cfaf33f80a92a2b9e5/core-services/release-controller/_releases/release-ocp-4.21-ci.json#L10-L11

AlternateImageRepository string `json:"alternateImageRepository"`

// AlternateImageRepositorySecret is the name of the secret containing credentials to the
Expand Down