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
52 changes: 12 additions & 40 deletions pkg/api/promotion.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,43 +107,11 @@ func quayImageWithTime(timestamp string, tag ImageStreamTagReference) string {
return fmt.Sprintf("%s:%s_prune_%s_%s_%s", QuayOpenShiftCIRepo, timestamp, tag.Namespace, tag.Name, tag.Tag)
}

func ConsolidatedQuayPromotion(c *ReleaseBuildConfiguration) bool {
if c == nil {
return false
}
if c.ReleaseTagConfiguration != nil && ConsolidatedQuayPromotionVersion(c.ReleaseTagConfiguration.Name) {
return true
}
for _, target := range PromotionTargets(c.PromotionConfiguration) {
if ConsolidatedQuayPromotionVersion(target.Name) {
return true
}
}
return false
}

func ConsolidatedQuayPromotionVersion(name string) bool {
var major, minor int
if _, err := fmt.Sscanf(name, "%d.%d", &major, &minor); err != nil {
return false
}
return major == 4 && minor >= 11 && minor <= 22
}

func quayProxyStreamSuffix(tag ImageStreamTagReference) string {
if ConsolidatedQuayPromotionVersion(tag.Name) {
return ""
}
return "-quay"
}

// getQuayProxyTarget creates the quay-proxy target imagestream tag reference.
// Format: namespace/imagestream-name-quay:tag
// getQuayProxyTarget creates the quay-proxy app.ci imagestream tag reference.
// Format: namespace/imagestream-name:tag (e.g. ocp/4.22:ovn-kubernetes).
func getQuayProxyTarget(target string, tag ImageStreamTagReference) string {
suffix := quayProxyStreamSuffix(tag)
if tag.Name != "" {
proxyTarget := fmt.Sprintf("%s/%s%s:%s", tag.Namespace, tag.Name, suffix, tag.Tag)
return proxyTarget
return fmt.Sprintf("%s/%s:%s", tag.Namespace, tag.Name, tag.Tag)
}

// For tag-based promotion, parse the target string to extract component name
Expand All @@ -157,15 +125,19 @@ func getQuayProxyTarget(target string, tag ImageStreamTagReference) string {
tagStart := len(tagPart) - len(tagSuffix)
targetComponent := tagPart[first+1 : tagStart]
if targetComponent != "" {
proxyTarget := fmt.Sprintf("%s/%s%s:%s", targetNamespace, targetComponent, suffix, tag.Tag)
return proxyTarget
return fmt.Sprintf("%s/%s:%s", targetNamespace, targetComponent, tag.Tag)
}
}
if first > 0 && tag.Tag != "" {
targetNamespace := tagPart[:first]
remainder := tagPart[first+1:]
if componentPrefix := tag.Tag + "_"; strings.HasPrefix(remainder, componentPrefix) {
return fmt.Sprintf("%s/%s:%s", targetNamespace, tag.Tag, remainder[len(componentPrefix):])
}
}
}

// Fallback: use namespace and tag
proxyTarget := fmt.Sprintf("%s/%s%s:%s", tag.Namespace, tag.Tag, suffix, tag.Tag)
return proxyTarget
return fmt.Sprintf("%s/%s:%s", tag.Namespace, tag.Tag, tag.Tag)
}

func qciPullSpec(pipelineSource string) (string, bool) {
Expand Down
8 changes: 4 additions & 4 deletions pkg/api/promotion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func TestQuayCombinedMirrorFunc(t *testing.T) {
expected map[string]string
}{
{
name: "4.12 consolidated quay proxy target",
name: "4.12 quay proxy target",
source: "registry.build02.ci.openshift.org/ci-op-abc/pipeline@sha256:abc123",
target: "quay.io/openshift/ci:ocp_4.12_ovn-kubernetes",
tag: ImageStreamTagReference{
Expand Down Expand Up @@ -231,7 +231,7 @@ func TestQuayCombinedMirrorFunc(t *testing.T) {
expected: map[string]string{
"quay.io/openshift/ci:ocp__ovn-kubernetes": "registry.build02.ci.openshift.org/ci-op-abc/pipeline@sha256:def456",
"quay.io/openshift/ci:20241024103000_prune_ocp__ovn-kubernetes": "quay.io/openshift/ci:ocp__ovn-kubernetes",
"ocp/ovn-kubernetes-quay:ovn-kubernetes": "quay-proxy.ci.openshift.org/openshift/ci@sha256:def456",
"ocp/ovn-kubernetes:latest": "quay-proxy.ci.openshift.org/openshift/ci@sha256:def456",
},
},
{
Expand Down Expand Up @@ -277,7 +277,7 @@ func TestQuayCombinedMirrorFunc(t *testing.T) {
expected: map[string]string{
"quay.io/openshift/ci:ocp_release_payload_images": "registry.build02.ci.openshift.org/ci-op-abc/pipeline@sha256:abc123",
"quay.io/openshift/ci:20241024102030_prune_ocp_release_payload_images": "quay.io/openshift/ci:ocp_release_payload_images",
"ocp/release-quay:payload_images": "quay-proxy.ci.openshift.org/openshift/ci@sha256:abc123",
"ocp/release:payload_images": "quay-proxy.ci.openshift.org/openshift/ci@sha256:abc123",
},
},
{
Expand All @@ -293,7 +293,7 @@ func TestQuayCombinedMirrorFunc(t *testing.T) {
expected: map[string]string{
"quay.io/openshift/ci:ocp__ci_a_latest": "registry.build02.ci.openshift.org/ci-op-abc/pipeline@sha256:def456",
"quay.io/openshift/ci:20241024103000_prune_ocp__ci_a_latest": "quay.io/openshift/ci:ocp__ci_a_latest",
"ocp/ovn-kubernetes-quay:ci_a_latest": "quay-proxy.ci.openshift.org/openshift/ci@sha256:def456",
"ocp/ovn-kubernetes:ci_a_latest": "quay-proxy.ci.openshift.org/openshift/ci@sha256:def456",
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion pkg/defaults/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ func fromConfig(ctx context.Context, cfg *Config) ([]api.Step, []api.Step, error
return nil, nil, fmt.Errorf("cannot promote images, no promotion configuration defined")
}

if !api.ConsolidatedQuayPromotion(cfg.CIConfig) {
if !api.PromotesOfficialImages(cfg.CIConfig, api.WithoutOKD) {
promotionSteps = append(promotionSteps, releasesteps.PromotionStep(api.PromotionStepName, cfg.CIConfig, requiredNames, cfg.JobSpec, cfg.podClient, cfg.PushSecret, registryDomain(cfg.CIConfig.PromotionConfiguration), api.DefaultMirrorFunc, api.DefaultTargetNameFunc, cfg.NodeArchitectures))
}
// Used primarily (only?) by the ci-chat-bot
Expand Down
16 changes: 8 additions & 8 deletions pkg/defaults/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1703,11 +1703,11 @@ func TestFromConfig(t *testing.T) {
expectedSteps: []string{"[output-images]", "[images]"},
expectedPost: []string{"[promotion]", "[promotion-quay]"},
}, {
name: "promote 4.12 consolidated quay",
name: "promote 4.12 quay only",
config: api.ReleaseBuildConfiguration{
PromotionConfiguration: &api.PromotionConfiguration{
Targets: []api.PromotionTarget{{
Namespace: ns,
Namespace: "ocp",
Name: "4.12",
Tag: "tag",
}},
Expand All @@ -1717,33 +1717,33 @@ func TestFromConfig(t *testing.T) {
expectedSteps: []string{"[output-images]", "[images]"},
expectedPost: []string{"[promotion-quay]"},
}, {
name: "promote 4.23 legacy quay",
name: "promote 4.23 quay only",
config: api.ReleaseBuildConfiguration{
PromotionConfiguration: &api.PromotionConfiguration{
Targets: []api.PromotionTarget{{
Namespace: ns,
Namespace: "ocp",
Name: "4.23",
Tag: "tag",
}},
},
},
promote: true,
expectedSteps: []string{"[output-images]", "[images]"},
expectedPost: []string{"[promotion]", "[promotion-quay]"},
expectedPost: []string{"[promotion-quay]"},
}, {
name: "promote 5.0 legacy quay",
name: "promote 5.0 quay only",
config: api.ReleaseBuildConfiguration{
PromotionConfiguration: &api.PromotionConfiguration{
Targets: []api.PromotionTarget{{
Namespace: ns,
Namespace: "ocp",
Name: "5.0",
Tag: "tag",
}},
},
},
promote: true,
expectedSteps: []string{"[output-images]", "[images]"},
expectedPost: []string{"[promotion]", "[promotion-quay]"},
expectedPost: []string{"[promotion-quay]"},
}, {
name: "duplicate input images",
config: api.ReleaseBuildConfiguration{
Expand Down
6 changes: 3 additions & 3 deletions pkg/steps/input_image_tag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func TestInputImageTagStepOfficialSpec(t *testing.T) {
}
}

func TestInputImageTagStepLegacyStream(t *testing.T) {
func TestInputImageTagStepConsolidatedStream(t *testing.T) {
baseImage := api.ImageStreamTagReference{Namespace: "ocp", Name: "5.0", Tag: "cli"}
config := api.InputImageTagStepConfiguration{
InputImage: api.InputImage{To: "cli", BaseImage: baseImage},
Expand Down Expand Up @@ -241,7 +241,7 @@ func TestInputImageTagStepLegacyStream(t *testing.T) {
Tag: &imagev1.TagReference{
From: &corev1.ObjectReference{Kind: "DockerImage", Name: quayRef},
ImportPolicy: imagev1.TagImportPolicy{ImportMode: imagev1.ImportModePreserveOriginal},
ReferencePolicy: imagev1.TagReferencePolicy{Type: imagev1.SourceTagReferencePolicy},
ReferencePolicy: imagev1.TagReferencePolicy{Type: imagev1.LocalTagReferencePolicy},
},
}
got := &imagev1.ImageStreamTag{}
Expand All @@ -254,7 +254,7 @@ func TestInputImageTagStepLegacyStream(t *testing.T) {
}

func TestInputImageTagStepStableFirst(t *testing.T) {
baseImage := api.ImageStreamTagReference{Namespace: "ocp", Name: "4.22", Tag: "cli"}
baseImage := api.ImageStreamTagReference{Namespace: "ocp", Name: api.StableImageStream, Tag: "cli"}
config := api.InputImageTagStepConfiguration{
InputImage: api.InputImage{To: "ocp_4_22_cli", BaseImage: baseImage},
}
Expand Down
3 changes: 0 additions & 3 deletions pkg/steps/release/create_release.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,6 @@ func joinOcAdmReleaseNewCommand(config *api.ReleaseTagConfiguration, namespace,
}

func buildOcAdmReleaseNewCommand(config *api.ReleaseTagConfiguration, namespace, streamName, cvo, destination, version string) string {
if !api.ConsolidatedQuayPromotionVersion(config.Name) {
return joinOcAdmReleaseNewCommand(config, namespace, cvo, destination, version, "--from-image-stream", streamName)
}
filePathVar := "${_CI_RELEASE_IS_FILE}"
fromStream := joinOcAdmReleaseNewCommand(config, namespace, cvo, destination, version, "--from-image-stream", streamName)
fromFile := joinOcAdmReleaseNewCommand(config, namespace, cvo, destination, version, "--from-image-stream-file", filePathVar)
Expand Down
14 changes: 4 additions & 10 deletions pkg/steps/release/create_release_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,14 @@ func TestBuildOcAdmReleaseNewCommand(t *testing.T) {
})

t.Run("assemble_script", func(t *testing.T) {
srcPol := imagev1.SourceTagReferencePolicy
config := &api.ReleaseTagConfiguration{Name: "4.12", ReferencePolicy: &srcPol}
got := buildOcAdmReleaseNewCommand(config, "test-ns", "stable", "cvo-pullspec", "dest:tag", "0.0.1-ver")
want := `_CI_RELEASE_IS_FILE="/tmp/ci-operator-release-is-stable.yaml"
if oc get imagestream "stable" -n "test-ns" -o yaml > "${_CI_RELEASE_IS_FILE}" 2>/dev/null; then
oc adm release new --max-per-registry=32 -n test-ns --from-image-stream-file ${_CI_RELEASE_IS_FILE} --to-image-base cvo-pullspec --to-image dest:tag --name 0.0.1-ver --keep-manifest-list || oc adm release new --max-per-registry=32 -n test-ns --from-image-stream stable --to-image-base cvo-pullspec --to-image dest:tag --name 0.0.1-ver --keep-manifest-list
oc adm release new --max-per-registry=32 -n test-ns --from-image-stream-file ${_CI_RELEASE_IS_FILE} --to-image-base cvo-pullspec --to-image dest:tag --name 0.0.1-ver --reference-mode=source --keep-manifest-list || oc adm release new --max-per-registry=32 -n test-ns --from-image-stream stable --to-image-base cvo-pullspec --to-image dest:tag --name 0.0.1-ver --reference-mode=source --keep-manifest-list
else
oc adm release new --max-per-registry=32 -n test-ns --from-image-stream stable --to-image-base cvo-pullspec --to-image dest:tag --name 0.0.1-ver --keep-manifest-list
oc adm release new --max-per-registry=32 -n test-ns --from-image-stream stable --to-image-base cvo-pullspec --to-image dest:tag --name 0.0.1-ver --reference-mode=source --keep-manifest-list
fi`
if diff := cmp.Diff(want, got); diff != "" {
t.Fatalf("buildOcAdmReleaseNewCommand() mismatch (-want +got):\n%s", diff)
}
got = buildOcAdmReleaseNewCommand(&api.ReleaseTagConfiguration{Name: "4.23", ReferencePolicy: &srcPol}, "test-ns", "stable", "cvo-pullspec", "dest:tag", "0.0.1-ver")
want = "oc adm release new --max-per-registry=32 -n test-ns --from-image-stream stable --to-image-base cvo-pullspec --to-image dest:tag --name 0.0.1-ver --reference-mode=source --keep-manifest-list"
config := &api.ReleaseTagConfiguration{Name: "4.23", ReferencePolicy: &sourceTagReference}
got := buildOcAdmReleaseNewCommand(config, "test-ns", "stable", "cvo-pullspec", "dest:tag", "0.0.1-ver")
if diff := cmp.Diff(want, got); diff != "" {
t.Fatalf("buildOcAdmReleaseNewCommand() mismatch (-want +got):\n%s", diff)
}
Expand Down
18 changes: 9 additions & 9 deletions pkg/steps/release/promote.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (s *promotionStep) run(ctx context.Context) error {
return fmt.Errorf("resolve promotion cli image: %w", err)
}

if _, err := steps.RunPod(ctx, s.client, getPromotionPod(imageMirrorTarget, timeStr, s.jobSpec.Namespace(), s.name, cliImage, s.nodeArchitectures), false); err != nil {
if _, err := steps.RunPod(ctx, s.client, getPromotionPod(imageMirrorTarget, timeStr, s.jobSpec.Namespace(), s.name, s.registry, cliImage, s.nodeArchitectures), false); err != nil {
return fmt.Errorf("unable to run promotion pod: %w", err)
}
return nil
Expand Down Expand Up @@ -289,7 +289,7 @@ func getTagCommand(tagSpecs []string, loglevel int) string {
}

// quayProxyTagFromISKey derives the quay-proxy floating tag from an IS tag key.
// Handles "namespace/stream-quay:tag" (4.23+) and consolidated "ocp/4.13:tag" (4.11–4.22).
// Handles "ocp/4.13:cli" and legacy "namespace/stream-quay:tag" (ci templates).
// Example: "ocp/4.13:cli" → "quay-proxy.ci.openshift.org/openshift/ci:ocp_4.13_cli".
func quayProxyTagFromISKey(isTagKey string) (string, bool) {
slashIdx := strings.Index(isTagKey, "/")
Expand All @@ -311,7 +311,7 @@ func quayProxyTagFromISKey(isTagKey string) (string, bool) {
var streamName string
if strings.HasSuffix(streamPart, quayStreamSuffix) {
streamName = strings.TrimSuffix(streamPart, quayStreamSuffix)
} else if api.ConsolidatedQuayPromotionVersion(streamPart) {
} else if api.RefersToOfficialImage(namespace, api.WithOKD) {
streamName = streamPart
} else {
return "", false
Expand Down Expand Up @@ -363,11 +363,11 @@ func getResolveAndTagRetryShell(registryConfig, quayProxyTag, isTag string, logl
if [ -n "${_digest}" ] && oc tag --source=docker --loglevel=%d --reference-policy='source' --import-mode='PreserveOriginal' --reference %s@${_digest} %s; then
break
fi
echo "promotion-quay: digest-tag failed for %s attempt ${r}/%d (QCI digest may have moved after mirror)" >&2
echo "promotion: digest-tag failed for %s attempt ${r}/%d (QCI digest may have moved after mirror)" >&2
if [ "${r}" -eq %d ]; then
exit 1
fi
echo "promotion-quay: retrying digest-tag for %s (attempt $((r+1))/%d after randomized backoff)" >&2
echo "promotion: retrying digest-tag for %s (attempt $((r+1))/%d after randomized backoff)" >&2
backoff=$(($RANDOM %% %d))s
sleep "${backoff}"
done
Expand All @@ -383,7 +383,7 @@ const (
retryLoopWithBackoff = "backoff=$(($RANDOM % 120))s; echo Sleeping randomized $backoff before retry; sleep $backoff"
)

func getPromotionPod(imageMirrorTarget map[string]string, timeStr string, namespace string, name string, cliImage string, nodeArchitectures []string) *coreapi.Pod {
func getPromotionPod(imageMirrorTarget map[string]string, timeStr string, namespace string, name string, registry string, cliImage string, nodeArchitectures []string) *coreapi.Pod {
keys := make([]string, 0, len(imageMirrorTarget))
for k := range imageMirrorTarget {
keys = append(keys, k)
Expand All @@ -393,11 +393,11 @@ func getPromotionPod(imageMirrorTarget map[string]string, timeStr string, namesp
var images []string
var pruneImages []string
var tags []string
// resolveAndTagPairs holds [quayProxyTag, isTag] for official ocp IS targets (consolidated
// ocp/4.x:tag and legacy *-quay). Resolved post-mirror via oc image info + oc tag.
// resolveAndTagPairs holds [quayProxyTag, isTag] for official ocp IS targets.
// Resolved post-mirror via oc image info on quay.io + oc tag with quay-proxy@digest.
var resolveAndTagPairs [][2]string

isQuayStep := name == api.PromotionQuayStepName
isQuayStep := registry == api.QuayOpenShiftCIRepo

for _, k := range keys {
if strings.Contains(k, fmt.Sprintf("%s_prune_", timeStr)) {
Expand Down
Loading