Repository: openshift/assisted-service (language: python)

Issue:
MGMT-17369: Add multi-arch release images to as well when setting "only_latest=true" in ".../openshift-versions"
Add multi-arch release images to as well when setting `only_latest=true` in `.../openshift-versions`
<!--
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

You can refer to [Kubernetes community documentation] on writing good commit messages, which provides good tips and ideas.

Some PRs address specific issues. Please, refer to the [CONTRIBUTING] documentation for more
information on how to link a PR to an existing issue.

It's recommended to take a few extra minutes to provide more information about
how this code was tested. Here are some questions that may be worth answering:

- Should this PR be tested by the reviewer?
- Is this PR relying on CI for an e2e test run?
- Should this PR be tested in a specific environment?
- Any logs, screenshots, etc that can help with the review process?

-->

## List all the issues related to this PR

- [ ] New Feature <!-- new functionality -->
- [ ] Enhancement <!-- refactor, code changes, improvement, that won't add new features -->
- [x] Bug fix
- [ ] Tests
- [ ] Documentation
- [ ] CI/CD <!-- Notice that changes for Dockerfiles/Jenkinsfiles aren't tested in CI due to a known bug. -->

## What environments does this code impact?

- [ ] Automation (CI, tools, etc)
- [x] Cloud
- [ ] Operator Managed Deployments
- [ ] None

## How was this code tested?

<!-- Please, select one or more if needed: -->

- [x] assisted-test-infra environment
- [ ] dev-scripts environment
- [ ] Reviewer's test appreciated
- [x] Waiting for CI to do a full test run
- [ ] Manual (Elaborate on how it was tested)
- [ ] No tests needed

## Checklist

- [x] Title and description added to both, commit and PR.
- [x] Relevant issues have been associated (see [CONTRIBUTING] guide)
- [x] This change does not require a documentation update (docstring, `docs`, README, etc)
- [ ] Does this change include unit-tests (note that code changes require unit-tests)

## Reviewers Checklist

- Are the title and description (in both PR and commit) meaningful and clear?
- Is there a bug required (and linked) for this change?
- Should this PR be backported?

[Kubernetes community documentation]: https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#commit-message-guidelines
[CONTRIBUTING]: https://github.com/openshift/assisted-service/blob/master/CONTRIBUTING.md



Discussion / hints:

Fix patch:
diff --git a/internal/versions/api.go b/internal/versions/api.go
index e470ee4dbd2..56fd02ce5c2 100644
--- a/internal/versions/api.go
+++ b/internal/versions/api.go
@@ -2,6 +2,7 @@ package versions
 
 import (
 	context "context"
+	"fmt"
 	"strings"
 
 	middleware "github.com/go-openapi/runtime/middleware"
@@ -13,6 +14,7 @@ import (
 	"github.com/openshift/assisted-service/restapi"
 	operations "github.com/openshift/assisted-service/restapi/operations/versions"
 	"github.com/pkg/errors"
+	"github.com/samber/lo"
 	"github.com/sirupsen/logrus"
 	"github.com/thoas/go-funk"
 )
@@ -78,7 +80,7 @@ func GetModelVersions(v Versions) models.Versions {
 // getLatestReleaseImageForMajorMinor returns the latest release image matching a given major.minor version,
 // or error if none of the release images match. The latest release image is considered the latest none beta release image,
 // or if all matching release images are beta then just the latest.
-func getLatestReleaseImageForMajorMinor(releaseImages models.ReleaseImages, majorMinorVersion string) (*models.ReleaseImage, error) {
+func getLatestReleaseImageForMajorMinor(releaseImages models.ReleaseImages, majorMinorVersion string, log logrus.FieldLogger) (*models.ReleaseImage, error) {
 	var latestReleaseImage *models.ReleaseImage
 	for _, releaseImage := range releaseImages {
 		// Typically, releaseImage.OpenshiftVersion follow the major.minor format, though exceptions exist with static release images.
@@ -112,10 +114,28 @@ func getLatestReleaseImageForMajorMinor(releaseImages models.ReleaseImages, majo
 		}
 	}
 
+	log.Debugf("Found latest release image version '%s' for majorMinorVersion '%s'", *latestReleaseImage.Version, majorMinorVersion)
+
 	return latestReleaseImage, nil
 }
 
-func filterReleaseImagesByOnlyLatest(releaseImages models.ReleaseImages, onlyLatest *bool) (models.ReleaseImages, error) {
+// getMultiArchReleaseImage retrieves multi arch release image matching a given x.y.z version.
+func getMultiArchReleaseImage(releaseImages models.ReleaseImages, version string, log logrus.FieldLogger) *models.ReleaseImage {
+	if !strings.HasSuffix(version, "-multi") {
+		version = fmt.Sprintf("%s-multi", version)
+	}
+
+	if releaseImage, ok := lo.Find(releaseImages, func(releaseImage *models.ReleaseImage) bool {
+		return swag.StringValue(releaseImage.Version) == version
+	}); ok {
+		log.Debugf("Found multi-arch release image for version '%s'", version)
+		return releaseImage
+	}
+
+	return nil
+}
+
+func filterReleaseImagesByOnlyLatest(releaseImages models.ReleaseImages, onlyLatest *bool, log logrus.FieldLogger) (models.ReleaseImages, error) {
 	if !swag.BoolValue(onlyLatest) {
 		return releaseImages, nil
 	}
@@ -134,11 +154,16 @@ func filterReleaseImagesByOnlyLatest(releaseImages models.ReleaseImages, onlyLat
 
 	filteredReleaseImages := models.ReleaseImages{}
 	for majorMinorVersion := range releaseImagesMajorMinorVersionsSet {
-		latestReleaseImageForMajorMinor, err := getLatestReleaseImageForMajorMinor(releaseImages, majorMinorVersion)
+		latestReleaseImageForMajorMinor, err := getLatestReleaseImageForMajorMinor(releaseImages, majorMinorVersion, log)
 		if err != nil {
 			return nil, errors.Wrapf(err, "error occurred while trying to get the latest release image for version: %s", majorMinorVersion)
 		}
 		filteredReleaseImages = append(filteredReleaseImages, latestReleaseImageForMajorMinor)
+		// Add the matching multi-arch release image if exists as well
+		matchingMultiArchReleaseImage := getMultiArchReleaseImage(releaseImages, *latestReleaseImageForMajorMinor.Version, log)
+		if matchingMultiArchReleaseImage != nil {
+			filteredReleaseImages = append(filteredReleaseImages, matchingMultiArchReleaseImage)
+		}
 	}
 
 	return filteredReleaseImages, nil
@@ -206,7 +231,7 @@ func (h *apiHandler) V2ListSupportedOpenshiftVersions(ctx context.Context, param
 
 	releaseImages = filterIgnoredVersions(h.log, releaseImages, handler.ignoredOpenshiftVersions)
 	releaseImagesByVersionPattern := filterReleaseImagesByVersion(releaseImages, params.Version)
-	releaseImagesByOnlyLatest, err := filterReleaseImagesByOnlyLatest(releaseImages, params.OnlyLatest)
+	releaseImagesByOnlyLatest, err := filterReleaseImagesByOnlyLatest(releaseImages, params.OnlyLatest, h.log)
 	if err != nil {
 		return common.GenerateErrorResponder(err)
 	}


Test patch:
diff --git a/internal/versions/api_test.go b/internal/versions/api_test.go
index c96035b5598..31b8a38a66e 100644
--- a/internal/versions/api_test.go
+++ b/internal/versions/api_test.go
@@ -490,6 +490,14 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 				Version:          swag.String("4.11.2"),
 				SupportLevel:     models.ReleaseImageSupportLevelProduction,
 			},
+			{
+				CPUArchitecture:  swag.String(common.MultiCPUArchitecture),
+				CPUArchitectures: []string{common.X86CPUArchitecture, common.ARM64CPUArchitecture},
+				OpenshiftVersion: swag.String("4.11-multi"),
+				URL:              swag.String("quay.io/openshift-release-dev/ocp-release:4.11.2-multi"),
+				Version:          swag.String("4.11.2-multi"),
+				SupportLevel:     models.ReleaseImageSupportLevelProduction,
+			},
 			{
 				CPUArchitecture:  swag.String(common.X86CPUArchitecture),
 				CPUArchitectures: []string{common.X86CPUArchitecture},
@@ -522,6 +530,14 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 				Version:          swag.String("4.13.2"),
 				SupportLevel:     models.OpenshiftVersionSupportLevelBeta,
 			},
+			{
+				CPUArchitecture:  swag.String(common.MultiCPUArchitecture),
+				CPUArchitectures: []string{common.X86CPUArchitecture, common.ARM64CPUArchitecture},
+				OpenshiftVersion: swag.String("4.13-multi"),
+				URL:              swag.String("quay.io/openshift-release-dev/ocp-release:4.13.2-multi"),
+				Version:          swag.String("4.13.2-multi"),
+				SupportLevel:     models.OpenshiftVersionSupportLevelBeta,
+			},
 		}
 
 		osImages := osImageList{
@@ -531,6 +547,12 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 				URL:              swag.String("https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rhcos/4.11/4.11.48/rhcos-4.11.48-x86_64-live.x86_64.iso"),
 				Version:          swag.String("411.86.202308081056-0"),
 			},
+			{
+				OpenshiftVersion: swag.String("4.11"),
+				CPUArchitecture:  swag.String(common.ARM64CPUArchitecture),
+				URL:              swag.String("https://mirror.openshift.com/pub/openshift-v4/aarch64/dependencies/rhcos/4.11/4.11.48/rhcos-4.11.48-aarch64-live.aarch64.iso"),
+				Version:          swag.String("411.86.202308081056-0"),
+			},
 			{
 				OpenshiftVersion: swag.String("4.12"),
 				CPUArchitecture:  swag.String(common.X86CPUArchitecture),
@@ -543,6 +565,12 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 				URL:              swag.String("https://mirror.openshift.com/pub/openshift-v4/x86_64/dependencies/rhcos/4.13/4.13.48/rhcos-4.13.48-x86_64-live.x86_64.iso"),
 				Version:          swag.String("413.86.202308081056-0"),
 			},
+			{
+				OpenshiftVersion: swag.String("4.13"),
+				CPUArchitecture:  swag.String(common.ARM64CPUArchitecture),
+				URL:              swag.String("https://mirror.openshift.com/pub/openshift-v4/aarch64/dependencies/rhcos/4.13/4.13.48/rhcos-4.13.48-aarch64-live.aarch64.iso"),
+				Version:          swag.String("411.86.202308081056-0"),
+			},
 		}
 
 		var handler restapi.VersionsAPI
@@ -570,6 +598,12 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 					SupportLevel:     swag.String(models.ReleaseImageSupportLevelProduction),
 					Default:          false,
 				},
+				"4.11.2-multi": {
+					DisplayName:      swag.String("4.11.2-multi"),
+					CPUArchitectures: []string{common.X86CPUArchitecture, common.ARM64CPUArchitecture},
+					SupportLevel:     swag.String(models.ReleaseImageSupportLevelProduction),
+					Default:          false,
+				},
 				"4.12.1": {
 					DisplayName:      swag.String("4.12.1"),
 					CPUArchitectures: []string{common.X86CPUArchitecture},
@@ -594,6 +628,12 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 					SupportLevel:     swag.String(models.OpenshiftVersionSupportLevelBeta),
 					Default:          false,
 				},
+				"4.13.2-multi": {
+					DisplayName:      swag.String("4.13.2-multi"),
+					CPUArchitectures: []string{common.X86CPUArchitecture, common.ARM64CPUArchitecture},
+					SupportLevel:     swag.String(models.OpenshiftVersionSupportLevelBeta),
+					Default:          false,
+				},
 			}
 
 			reply := handler.V2ListSupportedOpenshiftVersions(
@@ -612,6 +652,12 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 					SupportLevel:     swag.String(models.ReleaseImageSupportLevelProduction),
 					Default:          false,
 				},
+				"4.11.2-multi": {
+					DisplayName:      swag.String("4.11.2-multi"),
+					CPUArchitectures: []string{common.X86CPUArchitecture, common.ARM64CPUArchitecture},
+					SupportLevel:     swag.String(models.ReleaseImageSupportLevelProduction),
+					Default:          false,
+				},
 				"4.12.1": {
 					DisplayName:      swag.String("4.12.1"),
 					CPUArchitectures: []string{common.X86CPUArchitecture},
@@ -624,6 +670,12 @@ var _ = Describe("V2ListSupportedOpenshiftVersions", func() {
 					SupportLevel:     swag.String(models.OpenshiftVersionSupportLevelBeta),
 					Default:          false,
 				},
+				"4.13.2-multi": {
+					DisplayName:      swag.String("4.13.2-multi"),
+					CPUArchitectures: []string{common.X86CPUArchitecture, common.ARM64CPUArchitecture},
+					SupportLevel:     swag.String(models.OpenshiftVersionSupportLevelBeta),
+					Default:          false,
+				},
 			}
 
 			reply := handler.V2ListSupportedOpenshiftVersions(