Skip to content

Commit d2d6049

Browse files
committed
fix(package-server): get icons from default channel
Get icons from the default channel for icon subresource requests. Fixes an issue which caused package-server to erroneously return icons from the first channel declared.
1 parent 66c4a9d commit d2d6049

File tree

3 files changed

+85
-22
lines changed

3 files changed

+85
-22
lines changed

pkg/package-server/storage/subresources.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,29 @@ func (s *LogoStorage) Connect(ctx context.Context, name string, options runtime.
5151
return
5252
}
5353
imgBytes, mimeType, etag := func() ([]byte, string, string) {
54-
if len(pkg.Status.Channels) == 0 || len(pkg.Status.Channels[0].CurrentCSVDesc.Icon) == 0 {
55-
return []byte(defaultIcon), "image/svg+xml", ""
56-
} else {
57-
data := pkg.Status.Channels[0].CurrentCSVDesc.Icon[0].Base64Data
58-
mimeType := pkg.Status.Channels[0].CurrentCSVDesc.Icon[0].Mediatype
59-
etag := `"` + strings.Join([]string{name, pkg.Status.Channels[0].Name, pkg.Status.Channels[0].CurrentCSV}, ".") + `"`
54+
for _, pkgChannel := range pkg.Status.Channels {
55+
if pkgChannel.Name != pkg.Status.DefaultChannel {
56+
continue
57+
}
58+
59+
desc := pkgChannel.CurrentCSVDesc
60+
if len(desc.Icon) == 0 {
61+
break
62+
}
63+
64+
// The first icon is call we care about
65+
icon := desc.Icon[0]
66+
data := icon.Base64Data
67+
mimeType := icon.Mediatype
68+
etag := `"` + strings.Join([]string{name, pkgChannel.Name, pkgChannel.CurrentCSV}, ".") + `"`
6069

6170
reader := base64.NewDecoder(base64.StdEncoding, strings.NewReader(data))
6271
imgBytes, _ := ioutil.ReadAll(reader)
6372

6473
return imgBytes, mimeType, etag
6574
}
75+
76+
return []byte(defaultIcon), "image/svg+xml", ""
6677
}()
6778

6879
w.Header().Set("Content-Type", mimeType)

pkg/package-server/storage/subresources_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,15 @@ func testPackage() *operators.PackageManifest {
104104
Icon: []operators.Icon{{Mediatype: "image/png", Base64Data: iconData}},
105105
},
106106
},
107+
{
108+
Name: "alpha",
109+
CurrentCSV: "csv-b",
110+
CurrentCSVDesc: operators.CSVDescription{
111+
Icon: []operators.Icon{{Mediatype: "image/png", Base64Data: "different-icon"}},
112+
},
113+
},
107114
},
115+
DefaultChannel: "stable",
108116
},
109117
}
110118
}

test/e2e/packagemanifest_e2e_test.go

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package e2e
22

33
import (
44
"context"
5+
"encoding/base64"
56
"encoding/json"
67

78
"github.com/blang/semver"
@@ -10,7 +11,9 @@ import (
1011
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
1112
"k8s.io/apimachinery/pkg/api/errors"
1213
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/client-go/rest"
1315

16+
opver "github.com/operator-framework/api/pkg/lib/version"
1417
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1518
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
1619
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
@@ -40,23 +43,29 @@ var _ = Describe("Package Manifest API lists available Operators from Catalog So
4043
Context("Given a CatalogSource created using the ConfigMap as catalog source type", func() {
4144

4245
var (
46+
catsrcName string
4347
packageName string
48+
packageAlpha string
49+
alphaChannel string
4450
packageStable string
45-
cleanupCatalogSource cleanupFunc
46-
csvJSON []byte
51+
stableChannel string
52+
csvAlpha v1alpha1.ClusterServiceVersion
4753
csv v1alpha1.ClusterServiceVersion
48-
catsrcName string
54+
cleanupCatalogSource cleanupFunc
4955
)
5056
BeforeEach(func() {
5157

5258
// create a simple catalogsource
5359
packageName = genName("nginx")
54-
stableChannel := "stable"
60+
alphaChannel = "alpha"
61+
packageAlpha = packageName + "-alpha"
62+
stableChannel = "stable"
5563
packageStable = packageName + "-stable"
5664
manifests := []registry.PackageManifest{
5765
{
5866
PackageName: packageName,
5967
Channels: []registry.PackageChannel{
68+
{Name: alphaChannel, CurrentCSVName: packageAlpha},
6069
{Name: stableChannel, CurrentCSVName: packageStable},
6170
},
6271
DefaultChannelName: stableChannel,
@@ -84,15 +93,28 @@ var _ = Describe("Package Manifest API lists available Operators from Catalog So
8493
}
8594
csv.Spec.Maturity = "foo"
8695
csv.Spec.NativeAPIs = []metav1.GroupVersionKind{{Group: "kubenative.io", Version: "v1", Kind: "Native"}}
96+
csv.Spec.Icon = []v1alpha1.Icon{
97+
{
98+
Data: "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",
99+
MediaType: "image/png",
100+
},
101+
}
87102

88-
var err error
89-
csvJSON, err = json.Marshal(csv)
90-
Expect(err).ToNot(HaveOccurred())
103+
csvAlpha = *csv.DeepCopy()
104+
csvAlpha.SetName(packageAlpha)
105+
csvAlpha.Spec.Version = opver.OperatorVersion{semver.MustParse("0.1.1")}
106+
csvAlpha.Spec.Replaces = csv.GetName()
107+
csvAlpha.Spec.Icon = []v1alpha1.Icon{
108+
{
109+
Data: base64.StdEncoding.EncodeToString([]byte(csvAlpha.GetName())),
110+
MediaType: "image/png",
111+
},
112+
}
91113

92-
_, cleanupCatalogSource = createInternalCatalogSource(c, crc, catsrcName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []v1alpha1.ClusterServiceVersion{csv})
114+
_, cleanupCatalogSource = createInternalCatalogSource(c, crc, catsrcName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []v1alpha1.ClusterServiceVersion{csv, csvAlpha})
93115

94116
// Verify catalog source was created
95-
_, err = fetchCatalogSourceOnStatus(crc, catsrcName, testNamespace, catalogSourceRegistryPodSynced)
117+
_, err := fetchCatalogSourceOnStatus(crc, catsrcName, testNamespace, catalogSourceRegistryPodSynced)
96118
Expect(err).ToNot(HaveOccurred())
97119
})
98120

@@ -103,12 +125,25 @@ var _ = Describe("Package Manifest API lists available Operators from Catalog So
103125
})
104126

105127
It("retrieves the PackageManifest by package name and validates its fields", func() {
128+
// Drop icons to account for pruning
129+
csvAlpha.Spec.Icon = nil
130+
csv.Spec.Icon = nil
131+
132+
csvAlphaJSON, err := json.Marshal(csvAlpha)
133+
Expect(err).ToNot(HaveOccurred())
134+
csvJSON, err := json.Marshal(csv)
135+
Expect(err).ToNot(HaveOccurred())
106136

107137
expectedStatus := packagev1.PackageManifestStatus{
108138
CatalogSource: catsrcName,
109139
CatalogSourceNamespace: testNamespace,
110140
PackageName: packageName,
111141
Channels: []packagev1.PackageChannel{
142+
{
143+
Name: alphaChannel,
144+
CurrentCSV: packageAlpha,
145+
CurrentCSVDesc: packagev1.CreateCSVDescription(&csvAlpha, string(csvAlphaJSON)),
146+
},
112147
{
113148
Name: stableChannel,
114149
CurrentCSV: packageStable,
@@ -123,17 +158,11 @@ var _ = Describe("Package Manifest API lists available Operators from Catalog So
123158
Expect(pm).ShouldNot(BeNil())
124159
Expect(pm.GetName()).Should(Equal(packageName))
125160
Expect(pm.Status).Should(Equal(expectedStatus))
126-
Expect(pm.Status.Channels[0].CurrentCSVDesc.MinKubeVersion).Should(Equal("0.0.0"))
127-
Expect(pm.Status.Channels[0].CurrentCSVDesc.RelatedImages[0]).Should(Equal(*dummyImage))
128-
Expect(pm.Status.Channels[0].CurrentCSVDesc.NativeAPIs).Should(Equal(csv.Spec.NativeAPIs))
129161
Expect(pm.GetLabels()["projected"]).Should(Equal("label"))
130162
Expect(pm.GetLabels()["operatorframework.io/arch.amd64"]).Should(Equal("supported"))
131163
Expect(pm.GetLabels()["operatorframework.io/os.linux"]).Should(Equal("supported"))
132-
Expect(pm.Status.Channels[0].CurrentCSVDesc.Keywords).Should(Equal([]string{"foo", "bar"}))
133-
Expect(pm.Status.Channels[0].CurrentCSVDesc.Maturity).Should(Equal("foo"))
134-
Expect(pm.Status.Channels[0].CurrentCSVDesc.Links).Should(Equal([]packagev1.AppLink{{Name: "foo", URL: "example.com"}}))
135-
Expect(pm.Status.Channels[0].CurrentCSVDesc.Maintainers).Should(Equal([]packagev1.Maintainer{{Name: "foo", Email: "[email protected]"}}))
136164
})
165+
137166
It("lists PackageManifest and ensures it has valid PackageManifest item", func() {
138167
// Get a PackageManifestList and ensure it has the correct items
139168
Eventually(func() (bool, error) {
@@ -142,6 +171,21 @@ var _ = Describe("Package Manifest API lists available Operators from Catalog So
142171
}).Should(BeTrue(), "required package name not found in the list")
143172
})
144173

174+
It("gets the icon from the default channel", func() {
175+
var res rest.Result
176+
Eventually(func() error {
177+
res = pmc.OperatorsV1().RESTClient().Get().Resource("packagemanifests").SubResource("icon").Namespace(testNamespace).Name(packageName).Do(context.Background())
178+
return res.Error()
179+
}).Should(Succeed(), "error getting icon")
180+
181+
data, err := res.Raw()
182+
Expect(err).ToNot(HaveOccurred())
183+
184+
// Match against icon from the default
185+
expected, err := base64.StdEncoding.DecodeString(csv.Spec.Icon[0].Data)
186+
Expect(err).ToNot(HaveOccurred())
187+
Expect(data).To(Equal(expected))
188+
})
145189
})
146190

147191
Context("Given a CatalogSource created using gRPC catalog source type", func() {

0 commit comments

Comments
 (0)