diff --git a/pkg/api/promotion.go b/pkg/api/promotion.go index 455b4d1cca5..1aaf1dce7fb 100644 --- a/pkg/api/promotion.go +++ b/pkg/api/promotion.go @@ -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 @@ -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) { diff --git a/pkg/api/promotion_test.go b/pkg/api/promotion_test.go index b3daa6d09d8..8c229e6fee1 100644 --- a/pkg/api/promotion_test.go +++ b/pkg/api/promotion_test.go @@ -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{ @@ -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", }, }, { @@ -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", }, }, { @@ -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", }, }, { diff --git a/pkg/defaults/defaults.go b/pkg/defaults/defaults.go index 9a8a5594a95..c95ef070970 100644 --- a/pkg/defaults/defaults.go +++ b/pkg/defaults/defaults.go @@ -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 diff --git a/pkg/defaults/defaults_test.go b/pkg/defaults/defaults_test.go index 6f03f119698..7b8b7c4a811 100644 --- a/pkg/defaults/defaults_test.go +++ b/pkg/defaults/defaults_test.go @@ -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", }}, @@ -1717,11 +1717,11 @@ 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", }}, @@ -1729,13 +1729,13 @@ func TestFromConfig(t *testing.T) { }, 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", }}, @@ -1743,7 +1743,7 @@ func TestFromConfig(t *testing.T) { }, promote: true, expectedSteps: []string{"[output-images]", "[images]"}, - expectedPost: []string{"[promotion]", "[promotion-quay]"}, + expectedPost: []string{"[promotion-quay]"}, }, { name: "duplicate input images", config: api.ReleaseBuildConfiguration{ diff --git a/pkg/steps/input_image_tag_test.go b/pkg/steps/input_image_tag_test.go index a306ec43f21..56bcc0f8faf 100644 --- a/pkg/steps/input_image_tag_test.go +++ b/pkg/steps/input_image_tag_test.go @@ -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}, @@ -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{} @@ -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}, } diff --git a/pkg/steps/release/create_release.go b/pkg/steps/release/create_release.go index ef537ac93d1..cee7a233529 100644 --- a/pkg/steps/release/create_release.go +++ b/pkg/steps/release/create_release.go @@ -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) diff --git a/pkg/steps/release/create_release_test.go b/pkg/steps/release/create_release_test.go index fc7a9fd435c..1436e4bce7a 100644 --- a/pkg/steps/release/create_release_test.go +++ b/pkg/steps/release/create_release_test.go @@ -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) } diff --git a/pkg/steps/release/promote.go b/pkg/steps/release/promote.go index 5c6508e5f29..fe3f3d66e76 100644 --- a/pkg/steps/release/promote.go +++ b/pkg/steps/release/promote.go @@ -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 @@ -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, "/") @@ -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 @@ -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 @@ -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) @@ -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)) { diff --git a/pkg/steps/release/promote_test.go b/pkg/steps/release/promote_test.go index eb1514e6edc..e8e21a7f47f 100644 --- a/pkg/steps/release/promote_test.go +++ b/pkg/steps/release/promote_test.go @@ -724,6 +724,7 @@ func TestGetPromotionPod(t *testing.T) { var testCases = []struct { name string stepName string + registry string imageMirror map[string]string nodeArchitectures []string namespace string @@ -733,6 +734,7 @@ func TestGetPromotionPod(t *testing.T) { { name: "basic case", stepName: "promotion", + registry: "registry.ci.openshift.org", nodeArchitectures: []string{"amd64"}, imageMirror: map[string]string{ "registry.ci.openshift.org/ci/applyconfig:latest": "docker-registry.default.svc:5000/ci-op-y2n8rsh3/pipeline@sha256:afd71aa3cbbf7d2e00cd8696747b2abf164700147723c657919c20b13d13ec62", @@ -742,7 +744,8 @@ func TestGetPromotionPod(t *testing.T) { }, { name: "promotion-quay", - stepName: "promotion-quay", + stepName: api.PromotionQuayStepName, + registry: api.QuayOpenShiftCIRepo, nodeArchitectures: []string{"amd64"}, imageMirror: map[string]string{ "quay.io/openshift/ci:20240603235401_prune_ci_a_latest": "quay.io/openshift/ci:ci_a_latest", @@ -756,7 +759,8 @@ func TestGetPromotionPod(t *testing.T) { }, { name: "promotion-quay-multiple-tags", - stepName: "promotion-quay", + stepName: api.PromotionQuayStepName, + registry: api.QuayOpenShiftCIRepo, nodeArchitectures: []string{"amd64"}, imageMirror: map[string]string{ "quay.io/openshift/ci:20240603235401_prune_ovn-kubernetes": "quay.io/openshift/ci:ocp_4.21_ovn-kubernetes", @@ -773,7 +777,8 @@ func TestGetPromotionPod(t *testing.T) { }, { name: "promotion-quay-4.12", - stepName: "promotion-quay", + stepName: api.PromotionQuayStepName, + registry: api.QuayOpenShiftCIRepo, nodeArchitectures: []string{"amd64"}, imageMirror: map[string]string{ "quay.io/openshift/ci:20240603235401_prune_ovn-kubernetes": "quay.io/openshift/ci:ocp_4.12_ovn-kubernetes", @@ -787,7 +792,8 @@ func TestGetPromotionPod(t *testing.T) { }, { name: "promotion-quay-non-release-namespace", - stepName: "promotion-quay", + stepName: api.PromotionQuayStepName, + registry: api.QuayOpenShiftCIRepo, nodeArchitectures: []string{"amd64"}, imageMirror: map[string]string{ "quay.io/openshift/ci:ocp_4.21_ovn-kubernetes": "registry.build02.ci.openshift.org/ci-op-y2n8rsh3/pipeline@sha256:aaa", @@ -800,6 +806,7 @@ func TestGetPromotionPod(t *testing.T) { { name: "basic case - arm64 only", stepName: "promotion", + registry: "registry.ci.openshift.org", nodeArchitectures: []string{"arm64"}, imageMirror: map[string]string{ "registry.ci.openshift.org/ci/applyconfig:latest": "docker-registry.default.svc:5000/ci-op-y2n8rsh3/pipeline@sha256:afd71aa3cbbf7d2e00cd8696747b2abf164700147723c657919c20b13d13ec62", @@ -810,6 +817,7 @@ func TestGetPromotionPod(t *testing.T) { { name: "basic case - multi architecture", stepName: "promotion", + registry: "registry.ci.openshift.org", nodeArchitectures: []string{"amd64", "arm64"}, imageMirror: map[string]string{ "registry.ci.openshift.org/ci/applyconfig:latest": "docker-registry.default.svc:5000/ci-op-y2n8rsh3/pipeline@sha256:afd71aa3cbbf7d2e00cd8696747b2abf164700147723c657919c20b13d13ec62", @@ -821,7 +829,7 @@ func TestGetPromotionPod(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - testhelper.CompareWithFixture(t, getPromotionPod(testCase.imageMirror, "20240603235401", testCase.namespace, testCase.stepName, "stable:cli", testCase.nodeArchitectures)) + testhelper.CompareWithFixture(t, getPromotionPod(testCase.imageMirror, "20240603235401", testCase.namespace, testCase.stepName, testCase.registry, "stable:cli", testCase.nodeArchitectures)) }) } } @@ -1137,8 +1145,8 @@ func TestGetResolveAndTagRetryShell(t *testing.T) { "for r in {1..5}", "oc image info --registry-config=" + regcfg + " --filter-by-os=linux/amd64 " + quayIOTag, "oc tag --source=docker --loglevel=2 --reference-policy='source' --import-mode='PreserveOriginal' --reference quay-proxy.ci.openshift.org/openshift/ci@${_digest} " + isTag, - "promotion-quay: digest-tag failed for " + isTag, - "promotion-quay: retrying digest-tag for " + isTag, + "promotion: digest-tag failed for " + isTag, + "promotion: retrying digest-tag for " + isTag, `[ "${r}" -eq 5 ]`, "exit 1", "$(($RANDOM % 120))", @@ -1187,21 +1195,28 @@ func TestQuayProxyTagFromISKey(t *testing.T) { wantOK: false, }, { - name: "consolidated ocp stream", + name: "ocp stream", isTagKey: "ocp/4.13:secondary-scheduler-operator", wantTag: "quay-proxy.ci.openshift.org/openshift/ci:ocp_4.13_secondary-scheduler-operator", wantOK: true, }, { - name: "consolidated 4.21 stream", + name: "ocp 4.21 stream", isTagKey: "ocp/4.21:ovn-kubernetes", wantTag: "quay-proxy.ci.openshift.org/openshift/ci:ocp_4.21_ovn-kubernetes", wantOK: true, }, { - name: "non-consolidated stream without -quay", + name: "ocp 4.23 stream", isTagKey: "ocp/4.23:ovn-kubernetes", - wantOK: false, + wantTag: "quay-proxy.ci.openshift.org/openshift/ci:ocp_4.23_ovn-kubernetes", + wantOK: true, + }, + { + name: "ocp 5.0 stream", + isTagKey: "ocp/5.0:ansible", + wantTag: "quay-proxy.ci.openshift.org/openshift/ci:ocp_5.0_ansible", + wantOK: true, }, } for _, tt := range tests { @@ -1274,6 +1289,7 @@ func TestGetPromotionPodFallbackImageDoesNotPinArm64Node(t *testing.T) { "20240603235401", "ci-op-test", "promotion", + "registry.ci.openshift.org", api.QCIAPPCIDomain+"/openshift/ci:ocp_4.22_cli", []string{"arm64"}, ) diff --git a/pkg/steps/release/snapshot.go b/pkg/steps/release/snapshot.go index d95f6371ba7..6bf6350ee70 100644 --- a/pkg/steps/release/snapshot.go +++ b/pkg/steps/release/snapshot.go @@ -141,7 +141,7 @@ func snapshotImportSource(sourceNamespace, sourceName, tag string, source *image } return nil, false } - if api.ConsolidatedQuayPromotionVersion(sourceName) { + if api.RefersToOfficialImage(sourceNamespace, api.WithoutOKD) { return utils.OfficialImageTagFrom(source, base), true } if source != nil { diff --git a/pkg/steps/release/snapshot_test.go b/pkg/steps/release/snapshot_test.go index 7635a5e4d46..10b4e1412ca 100644 --- a/pkg/steps/release/snapshot_test.go +++ b/pkg/steps/release/snapshot_test.go @@ -24,7 +24,7 @@ func TestSnapshotImportSource(t *testing.T) { wantFrom *coreapi.ObjectReference }{ { - name: "consolidated spec first", + name: "ocp spec first", stream: "4.18", tag: base.Tag, source: &imagev1.ImageStream{ @@ -46,14 +46,14 @@ func TestSnapshotImportSource(t *testing.T) { wantFrom: &coreapi.ObjectReference{Kind: "DockerImage", Name: api.QuayImageReference(base)}, }, { - name: "consolidated missing source imagestream", + name: "ocp missing source imagestream", stream: "4.22", tag: base.Tag, wantOK: true, wantFrom: &coreapi.ObjectReference{Kind: "DockerImage", Name: api.QuayImageReference(api.ImageStreamTagReference{Namespace: "ocp", Name: "4.22", Tag: base.Tag})}, }, { - name: "non-consolidated spec docker", + name: "ocp spec docker 4.23", stream: "4.23", tag: "cli", source: &imagev1.ImageStream{ diff --git a/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_4.12.yaml b/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_4.12.yaml index 877b909f8a6..416410c5529 100644 --- a/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_4.12.yaml +++ b/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_4.12.yaml @@ -24,11 +24,11 @@ spec: if [ -n "${_digest}" ] && oc tag --source=docker --loglevel=2 --reference-policy='source' --import-mode='PreserveOriginal' --reference quay-proxy.ci.openshift.org/openshift/ci@${_digest} ocp/4.12:ovn-kubernetes; then break fi - echo "promotion-quay: digest-tag failed for ocp/4.12:ovn-kubernetes attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 + echo "promotion: digest-tag failed for ocp/4.12:ovn-kubernetes attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 if [ "${r}" -eq 5 ]; then exit 1 fi - echo "promotion-quay: retrying digest-tag for ocp/4.12:ovn-kubernetes (attempt $((r+1))/5 after randomized backoff)" >&2 + echo "promotion: retrying digest-tag for ocp/4.12:ovn-kubernetes (attempt $((r+1))/5 after randomized backoff)" >&2 backoff=$(($RANDOM % 120))s sleep "${backoff}" done @@ -38,11 +38,11 @@ spec: if [ -n "${_digest}" ] && oc tag --source=docker --loglevel=2 --reference-policy='source' --import-mode='PreserveOriginal' --reference quay-proxy.ci.openshift.org/openshift/ci@${_digest} ocp/4.12:ovn-kubernetes-base; then break fi - echo "promotion-quay: digest-tag failed for ocp/4.12:ovn-kubernetes-base attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 + echo "promotion: digest-tag failed for ocp/4.12:ovn-kubernetes-base attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 if [ "${r}" -eq 5 ]; then exit 1 fi - echo "promotion-quay: retrying digest-tag for ocp/4.12:ovn-kubernetes-base (attempt $((r+1))/5 after randomized backoff)" >&2 + echo "promotion: retrying digest-tag for ocp/4.12:ovn-kubernetes-base (attempt $((r+1))/5 after randomized backoff)" >&2 backoff=$(($RANDOM % 120))s sleep "${backoff}" done diff --git a/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_multiple_tags.yaml b/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_multiple_tags.yaml index 93b51a90a55..31f09c2ef3b 100644 --- a/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_multiple_tags.yaml +++ b/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_multiple_tags.yaml @@ -24,11 +24,11 @@ spec: if [ -n "${_digest}" ] && oc tag --source=docker --loglevel=2 --reference-policy='source' --import-mode='PreserveOriginal' --reference quay-proxy.ci.openshift.org/openshift/ci@${_digest} ocp/4.21:ovn-kubernetes; then break fi - echo "promotion-quay: digest-tag failed for ocp/4.21:ovn-kubernetes attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 + echo "promotion: digest-tag failed for ocp/4.21:ovn-kubernetes attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 if [ "${r}" -eq 5 ]; then exit 1 fi - echo "promotion-quay: retrying digest-tag for ocp/4.21:ovn-kubernetes (attempt $((r+1))/5 after randomized backoff)" >&2 + echo "promotion: retrying digest-tag for ocp/4.21:ovn-kubernetes (attempt $((r+1))/5 after randomized backoff)" >&2 backoff=$(($RANDOM % 120))s sleep "${backoff}" done @@ -38,11 +38,11 @@ spec: if [ -n "${_digest}" ] && oc tag --source=docker --loglevel=2 --reference-policy='source' --import-mode='PreserveOriginal' --reference quay-proxy.ci.openshift.org/openshift/ci@${_digest} ocp/4.21:ovn-kubernetes-base; then break fi - echo "promotion-quay: digest-tag failed for ocp/4.21:ovn-kubernetes-base attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 + echo "promotion: digest-tag failed for ocp/4.21:ovn-kubernetes-base attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 if [ "${r}" -eq 5 ]; then exit 1 fi - echo "promotion-quay: retrying digest-tag for ocp/4.21:ovn-kubernetes-base (attempt $((r+1))/5 after randomized backoff)" >&2 + echo "promotion: retrying digest-tag for ocp/4.21:ovn-kubernetes-base (attempt $((r+1))/5 after randomized backoff)" >&2 backoff=$(($RANDOM % 120))s sleep "${backoff}" done @@ -52,11 +52,11 @@ spec: if [ -n "${_digest}" ] && oc tag --source=docker --loglevel=2 --reference-policy='source' --import-mode='PreserveOriginal' --reference quay-proxy.ci.openshift.org/openshift/ci@${_digest} ocp/4.21:ovn-kubernetes-microshift; then break fi - echo "promotion-quay: digest-tag failed for ocp/4.21:ovn-kubernetes-microshift attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 + echo "promotion: digest-tag failed for ocp/4.21:ovn-kubernetes-microshift attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 if [ "${r}" -eq 5 ]; then exit 1 fi - echo "promotion-quay: retrying digest-tag for ocp/4.21:ovn-kubernetes-microshift (attempt $((r+1))/5 after randomized backoff)" >&2 + echo "promotion: retrying digest-tag for ocp/4.21:ovn-kubernetes-microshift (attempt $((r+1))/5 after randomized backoff)" >&2 backoff=$(($RANDOM % 120))s sleep "${backoff}" done diff --git a/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_non_release_namespace.yaml b/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_non_release_namespace.yaml index 0e6945e4792..09aa4f532ca 100644 --- a/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_non_release_namespace.yaml +++ b/pkg/steps/release/testdata/zz_fixture_TestGetPromotionPod_promotion_quay_non_release_namespace.yaml @@ -23,11 +23,11 @@ spec: if [ -n "${_digest}" ] && oc tag --source=docker --loglevel=2 --reference-policy='source' --import-mode='PreserveOriginal' --reference quay-proxy.ci.openshift.org/openshift/ci@${_digest} ocp/4.21:ovn-kubernetes; then break fi - echo "promotion-quay: digest-tag failed for ocp/4.21:ovn-kubernetes attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 + echo "promotion: digest-tag failed for ocp/4.21:ovn-kubernetes attempt ${r}/5 (QCI digest may have moved after mirror)" >&2 if [ "${r}" -eq 5 ]; then exit 1 fi - echo "promotion-quay: retrying digest-tag for ocp/4.21:ovn-kubernetes (attempt $((r+1))/5 after randomized backoff)" >&2 + echo "promotion: retrying digest-tag for ocp/4.21:ovn-kubernetes (attempt $((r+1))/5 after randomized backoff)" >&2 backoff=$(($RANDOM % 120))s sleep "${backoff}" done diff --git a/pkg/steps/utils/image.go b/pkg/steps/utils/image.go index 2533a48fef6..e23fc10b5ab 100644 --- a/pkg/steps/utils/image.go +++ b/pkg/steps/utils/image.go @@ -83,23 +83,25 @@ func OfficialImageTagFrom(source *imagev1.ImageStream, base api.ImageStreamTagRe return &coreapi.ObjectReference{Kind: "DockerImage", Name: api.QuayImageReference(base)} } -// ResolveOfficialInputFrom resolves consolidated ocp inputs: stable in job ns, then spec/status/quay on source IS. -// When ok is false, callers use QuayImageReference with Source policy (e.g. 4.23, 5.0). +// ResolveOfficialInputFrom resolves official ocp inputs: stable in job ns, then spec/status/quay on source IS. +// When ok is false, callers use QuayImageReference with Source policy. func ResolveOfficialInputFrom(ctx context.Context, client ctrlruntimeclient.Client, jobNamespace string, base api.ImageStreamTagReference) (*coreapi.ObjectReference, bool, error) { - if !api.ConsolidatedQuayPromotionVersion(base.Name) || !api.RefersToOfficialImage(base.Namespace, api.WithoutOKD) { + if !api.RefersToOfficialImage(base.Namespace, api.WithoutOKD) { return nil, false, nil } - stable := &imagev1.ImageStream{} - if err := client.Get(ctx, ctrlruntimeclient.ObjectKey{Namespace: jobNamespace, Name: api.StableImageStream}, stable); err == nil { - if _, exists, _ := util.ResolvePullSpec(stable, base.Tag, true); exists { - return &coreapi.ObjectReference{ - Kind: "ImageStreamTag", - Namespace: jobNamespace, - Name: fmt.Sprintf("%s:%s", api.StableImageStream, base.Tag), - }, true, nil + if base.Name == api.StableImageStream || api.IsReleaseStream(base.Name) { + stable := &imagev1.ImageStream{} + if err := client.Get(ctx, ctrlruntimeclient.ObjectKey{Namespace: jobNamespace, Name: api.StableImageStream}, stable); err == nil { + if _, exists, _ := util.ResolvePullSpec(stable, base.Tag, true); exists { + return &coreapi.ObjectReference{ + Kind: "ImageStreamTag", + Namespace: jobNamespace, + Name: fmt.Sprintf("%s:%s", api.StableImageStream, base.Tag), + }, true, nil + } + } else if !kerrors.IsNotFound(err) { + return nil, false, fmt.Errorf("get stable imagestream in %s: %w", jobNamespace, err) } - } else if !kerrors.IsNotFound(err) { - return nil, false, fmt.Errorf("get stable imagestream in %s: %w", jobNamespace, err) } source := &imagev1.ImageStream{} if err := client.Get(ctx, ctrlruntimeclient.ObjectKey{Namespace: base.Namespace, Name: base.Name}, source); err != nil && !kerrors.IsNotFound(err) { diff --git a/pkg/steps/utils/image_test.go b/pkg/steps/utils/image_test.go index 030b49b1b44..2878b0d57e8 100644 --- a/pkg/steps/utils/image_test.go +++ b/pkg/steps/utils/image_test.go @@ -39,7 +39,8 @@ func TestResolveOfficialInputFrom(t *testing.T) { wantOK bool wantFrom *coreapi.ObjectReference }{ - {name: "non-consolidated", base: api.ImageStreamTagReference{Namespace: "ocp", Name: "5.0", Tag: "cli"}, wantOK: false}, + {name: "official ocp 5.0", base: api.ImageStreamTagReference{Namespace: "ocp", Name: "5.0", Tag: "cli"}, wantOK: true, wantFrom: &coreapi.ObjectReference{Kind: "DockerImage", Name: api.QuayImageReference(api.ImageStreamTagReference{Namespace: "ocp", Name: "5.0", Tag: "cli"})}}, + {name: "non-official namespace", base: api.ImageStreamTagReference{Namespace: "ci", Name: "5.0", Tag: "cli"}, wantOK: false}, { name: "spec docker", base: base, @@ -86,8 +87,8 @@ func TestResolveOfficialInputFrom(t *testing.T) { wantFrom: &coreapi.ObjectReference{Kind: "DockerImage", Name: api.QuayImageReference(api.ImageStreamTagReference{Namespace: "ocp", Name: "4.16", Tag: "base-rhel9"})}, }, { - name: "stable first", - base: api.ImageStreamTagReference{Namespace: "ocp", Name: "4.22", Tag: "cli"}, + name: "stable stream in job namespace", + base: api.ImageStreamTagReference{Namespace: "ocp", Name: api.StableImageStream, Tag: "cli"}, objects: []runtime.Object{&imagev1.ImageStream{ ObjectMeta: metav1.ObjectMeta{Namespace: "job-ns", Name: api.StableImageStream}, Spec: imagev1.ImageStreamSpec{Tags: []imagev1.TagReference{{Name: "cli"}}}, @@ -99,6 +100,20 @@ func TestResolveOfficialInputFrom(t *testing.T) { wantOK: true, wantFrom: &coreapi.ObjectReference{Kind: "ImageStreamTag", Name: "stable:cli", Namespace: "job-ns"}, }, + { + name: "versioned ocp stream not redirected to job stable", + base: api.ImageStreamTagReference{Namespace: "ocp", Name: "5.0", Tag: "cli"}, + objects: []runtime.Object{&imagev1.ImageStream{ + ObjectMeta: metav1.ObjectMeta{Namespace: "job-ns", Name: api.StableImageStream}, + Spec: imagev1.ImageStreamSpec{Tags: []imagev1.TagReference{{Name: "cli"}}}, + Status: imagev1.ImageStreamStatus{ + PublicDockerImageRepository: "registry/job-ns/stable", + Tags: []imagev1.NamedTagEventList{{Tag: "cli", Items: []imagev1.TagEvent{{Image: "sha256:1111"}}}}, + }, + }}, + wantOK: true, + wantFrom: &coreapi.ObjectReference{Kind: "DockerImage", Name: api.QuayImageReference(api.ImageStreamTagReference{Namespace: "ocp", Name: "5.0", Tag: "cli"})}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {