diff --git a/pkg/controller/component/component_version.go b/pkg/controller/component/component_version.go index c6ccf9f8753..d34949655f9 100644 --- a/pkg/controller/component/component_version.go +++ b/pkg/controller/component/component_version.go @@ -176,13 +176,36 @@ func findMatchedImagesFromCompVersions(compVersions []*appsv1alpha1.ComponentVer } } } + + exactMatchedServiceVersion := func(releases map[string]appNameVersionImage) []string { + names := make([]string, 0) + for name, r := range releases { + if r.version == serviceVersion { + names = append(names, name) + } + } + return names + } + apps := make(map[string]appNameVersionImage) - for name, releases := range appsWithReleases { - names := maps.Keys(releases) - slices.Sort(names) + for appName, releases := range appsWithReleases { + releaseNames := maps.Keys(releases) + if names := exactMatchedServiceVersion(releases); len(names) > 0 { + releaseNames = names + } + slices.Sort(releaseNames) // use the latest release - apps[name] = releases[names[len(names)-1]] + apps[appName] = releases[releaseNames[len(releaseNames)-1]] } + + matched := appNameVersionImage{} + for name, app := range apps { + if len(matched.version) > 0 && app.version != matched.version { + return nil, fmt.Errorf("multiple service versions matched: %v, %v", matched, app) + } + matched = apps[name] + } + return apps, nil } diff --git a/pkg/controller/component/component_version_test.go b/pkg/controller/component/component_version_test.go index 27f760be3b9..52a29d2aaec 100644 --- a/pkg/controller/component/component_version_test.go +++ b/pkg/controller/component/component_version_test.go @@ -126,5 +126,90 @@ var _ = Describe("Component Version", func() { Expect(err).Should(Succeed()) Expect(compDefObj.Spec.Runtime.Containers[0].Image).Should(Equal(releases[2].Images[testapps.AppName])) }) + + It("exact matched service version", func() { + compDefObj := testapps.NewComponentDefinitionFactory(testapps.CompDefName("v1")). + SetRuntime(&corev1.Container{Name: testapps.AppName}). + GetObject() + + releases := []appsv1alpha1.ComponentVersionRelease{ + { + Name: testapps.ReleaseID("r0"), // v0.0.1-r0 + ServiceVersion: testapps.ServiceVersion(""), // 8.0.30 + Images: map[string]string{ + testapps.AppName: testapps.AppImage(testapps.AppName, testapps.ReleaseID("r0")), + }, + }, + { + Name: testapps.ReleaseID("r0-opt"), // // v0.0.1-r0-opt, has a newer release name + ServiceVersion: testapps.ServiceVersion("opt"), // 8.0.30-opt + Images: map[string]string{ + testapps.AppName: testapps.AppImage(testapps.AppName, testapps.ReleaseID("r0-opt")), + }, + }, + } + + compVersionObj := testapps.NewComponentVersionFactory(testapps.CompVersionName). + SetSpec(appsv1alpha1.ComponentVersionSpec{ + CompatibilityRules: []appsv1alpha1.ComponentVersionCompatibilityRule{ + { + CompDefs: []string{compDefObj.Name}, + Releases: []string{releases[0].Name, releases[1].Name}, + }, + }, + Releases: []appsv1alpha1.ComponentVersionRelease{releases[0], releases[1]}, + }). + GetObject() + + By("resolve images with service version 8.0.30") + err := resolveImagesWithCompVersions(compDefObj, []*appsv1alpha1.ComponentVersion{compVersionObj}, testapps.ServiceVersion("")) + Expect(err).Should(Succeed()) + Expect(compDefObj.Spec.Runtime.Containers[0].Image).Should(Equal(releases[0].Images[testapps.AppName])) + }) + + It("matched from different service versions", func() { + var ( + app1, app2 = "app1", "app2" + ) + + compDefObj := testapps.NewComponentDefinitionFactory(testapps.CompDefName("v1")). + SetRuntime(&corev1.Container{Name: app1}). + SetRuntime(&corev1.Container{Name: app2}). + GetObject() + + releases := []appsv1alpha1.ComponentVersionRelease{ + { + Name: testapps.ReleaseID("r0"), // v0.0.1-r0 + ServiceVersion: testapps.ServiceVersion(""), // 8.0.30 + Images: map[string]string{ + app1: testapps.AppImage(app1, testapps.ReleaseID("r0")), + }, + }, + { + Name: testapps.ReleaseID("r0-opt"), // // v0.0.1-r0-opt, has a newer release name + ServiceVersion: testapps.ServiceVersion("opt"), // 8.0.30-opt + Images: map[string]string{ + app1: testapps.AppImage(app1, testapps.ReleaseID("r0-opt")), + app2: testapps.AppImage(app2, testapps.ReleaseID("r0-opt")), + }, + }, + } + + compVersionObj := testapps.NewComponentVersionFactory(testapps.CompVersionName). + SetSpec(appsv1alpha1.ComponentVersionSpec{ + CompatibilityRules: []appsv1alpha1.ComponentVersionCompatibilityRule{ + { + CompDefs: []string{compDefObj.Name}, + Releases: []string{releases[0].Name, releases[1].Name}, + }, + }, + Releases: []appsv1alpha1.ComponentVersionRelease{releases[0], releases[1]}, + }). + GetObject() + + By("resolve images with service version 8.0.30") + err := resolveImagesWithCompVersions(compDefObj, []*appsv1alpha1.ComponentVersion{compVersionObj}, testapps.ServiceVersion("")) + Expect(err).ShouldNot(BeNil()) + }) }) })