From f70e35b05b67deedd8cf2c4e7ba0021c5825bce6 Mon Sep 17 00:00:00 2001 From: Bryce Palmer Date: Thu, 14 Sep 2023 15:42:20 -0400 Subject: [PATCH] use catalogd HTTP server instead of CatalogMetadata API Signed-off-by: Bryce Palmer --- internal/catalogmetadata/client/client.go | 92 ++++++++--- .../catalogmetadata/client/client_test.go | 150 +++++------------- internal/catalogmetadata/unmarshal.go | 14 +- internal/catalogmetadata/unmarshal_test.go | 57 +++---- .../entitysources/catalogdsource.go | 82 +++++++--- 5 files changed, 197 insertions(+), 198 deletions(-) diff --git a/internal/catalogmetadata/client/client.go b/internal/catalogmetadata/client/client.go index b472d14ff..662053009 100644 --- a/internal/catalogmetadata/client/client.go +++ b/internal/catalogmetadata/client/client.go @@ -3,6 +3,7 @@ package client import ( "context" "fmt" + "net/http" "sigs.k8s.io/controller-runtime/pkg/client" @@ -12,8 +13,31 @@ import ( "github.com/operator-framework/operator-controller/internal/catalogmetadata" ) -func NewClient(cl client.Client) *Client { - return &Client{cl: cl} +// TODO: When a catalogd release containing https://github.com/operator-framework/catalogd/pull/168 +// is made this can be removed in favor of parsing `Catalog.Status` for the +// appropriate URL for fetching catalog contents. +const catalogdOnClusterBaseURL = "http://catalogd-catalogserver.catalogd-system.svc" +const catalogdOnClusterURLTemplate = "%s/catalogs/%s/all.json" + +type Opt func(c *Client) + +func WithBaseURL(baseURL string) Opt { + return func(c *Client) { + c.baseURL = baseURL + } +} + +func NewClient(cl client.Client, opts ...Opt) *Client { + cli := &Client{ + cl: cl, + baseURL: catalogdOnClusterBaseURL, + } + + for _, opt := range opts { + opt(cli) + } + + return cli } // Client is reading catalog metadata @@ -21,6 +45,14 @@ type Client struct { // Note that eventually we will be reading from catalogd http API // instead of kube API server. We will need to swap this implementation. cl client.Client + + // baseURL is the base URL used by the client when making a request + // to the catalogd HTTP server. When using NewClient() this defaults + // to http://catalogd-catalogserver.catalogd-system.svc + // TODO: When a catalogd release containing https://github.com/operator-framework/catalogd/pull/168 + // is made this can be removed in favor of parsing `Catalog.Status` for the + // appropriate URL for fetching catalog contents. + baseURL string } func (c *Client) Bundles(ctx context.Context) ([]*catalogmetadata.Bundle, error) { @@ -31,14 +63,47 @@ func (c *Client) Bundles(ctx context.Context) ([]*catalogmetadata.Bundle, error) return nil, err } for _, catalog := range catalogList.Items { - channels, err := fetchCatalogMetadata[catalogmetadata.Channel](ctx, c.cl, catalog.Name, declcfg.SchemaChannel) + channels := []*catalogmetadata.Channel{} + bundles := []*catalogmetadata.Bundle{} + + // TODO: When a catalogd release containing https://github.com/operator-framework/catalogd/pull/168 + // is made this should be updated in favor of parsing `Catalog.Status` for the + // appropriate URL for fetching catalog contents. + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf(catalogdOnClusterURLTemplate, c.baseURL, catalog.Name), nil) if err != nil { - return nil, err + return nil, fmt.Errorf("error forming request: %s", err) } - bundles, err := fetchCatalogMetadata[catalogmetadata.Bundle](ctx, c.cl, catalog.Name, declcfg.SchemaBundle) + resp, err := http.DefaultClient.Do(req) if err != nil { - return nil, err + return nil, fmt.Errorf("error performing request: %s", err) + } + defer resp.Body.Close() + + err = declcfg.WalkMetasReader(resp.Body, func(meta *declcfg.Meta, err error) error { + if err != nil { + return err + } + + switch meta.Schema { + case declcfg.SchemaChannel: + content, err := catalogmetadata.Unmarshal[catalogmetadata.Channel](meta) + if err != nil { + return fmt.Errorf("error unmarshalling catalog metadata: %s", err) + } + channels = append(channels, content) + case declcfg.SchemaBundle: + content, err := catalogmetadata.Unmarshal[catalogmetadata.Bundle](meta) + if err != nil { + return fmt.Errorf("error unmarshalling catalog metadata: %s", err) + } + bundles = append(bundles, content) + } + + return nil + }) + if err != nil { + return nil, fmt.Errorf("error processing response: %s", err) } bundles, err = populateExtraFields(catalog.Name, channels, bundles) @@ -52,21 +117,6 @@ func (c *Client) Bundles(ctx context.Context) ([]*catalogmetadata.Bundle, error) return allBundles, nil } -func fetchCatalogMetadata[T catalogmetadata.Schemas](ctx context.Context, cl client.Client, catalogName, schema string) ([]*T, error) { - var cmList catalogd.CatalogMetadataList - err := cl.List(ctx, &cmList, client.MatchingLabels{"catalog": catalogName, "schema": schema}) - if err != nil { - return nil, err - } - - content, err := catalogmetadata.Unmarshal[T](cmList.Items) - if err != nil { - return nil, fmt.Errorf("error unmarshalling catalog metadata: %s", err) - } - - return content, nil -} - func populateExtraFields(catalogName string, channels []*catalogmetadata.Channel, bundles []*catalogmetadata.Bundle) ([]*catalogmetadata.Bundle, error) { bundlesMap := map[string]*catalogmetadata.Bundle{} for i := range bundles { diff --git a/internal/catalogmetadata/client/client_test.go b/internal/catalogmetadata/client/client_test.go index 4b28dadd9..9d9a3e4c0 100644 --- a/internal/catalogmetadata/client/client_test.go +++ b/internal/catalogmetadata/client/client_test.go @@ -3,6 +3,10 @@ package client_test import ( "context" "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -33,7 +37,7 @@ func TestClient(t *testing.T) { t.Run("Bundles", func(t *testing.T) { for _, tt := range []struct { name string - fakeCatalog func() ([]client.Object, []*catalogmetadata.Bundle) + fakeCatalog func() ([]client.Object, []*catalogmetadata.Bundle, map[string][]byte) wantErr string }{ { @@ -42,16 +46,10 @@ func TestClient(t *testing.T) { }, { name: "channel has a ref to a missing bundle", - fakeCatalog: func() ([]client.Object, []*catalogmetadata.Bundle) { - objs, _ := defaultFakeCatalog() + fakeCatalog: func() ([]client.Object, []*catalogmetadata.Bundle, map[string][]byte) { + objs, _, catalogContentMap := defaultFakeCatalog() - objs = append(objs, &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-1-fake1-channel-with-missing-bundle", - Labels: map[string]string{"schema": declcfg.SchemaChannel, "catalog": "catalog-1"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(`{ + catalogContentMap["catalog-1"] = append(catalogContentMap["catalog-1"], []byte(`{ "schema": "olm.channel", "name": "channel-with-missing-bundle", "package": "fake1", @@ -60,59 +58,51 @@ func TestClient(t *testing.T) { "name": "fake1.v9.9.9" } ] - }`), - }, - }) + }`)...) - return objs, nil + return objs, nil, catalogContentMap }, wantErr: `bundle "fake1.v9.9.9" not found in catalog "catalog-1" (package "fake1", channel "channel-with-missing-bundle")`, }, { name: "invalid bundle", - fakeCatalog: func() ([]client.Object, []*catalogmetadata.Bundle) { - objs, _ := defaultFakeCatalog() + fakeCatalog: func() ([]client.Object, []*catalogmetadata.Bundle, map[string][]byte) { + objs, _, catalogContentMap := defaultFakeCatalog() - objs = append(objs, &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-1-broken-bundle", - Labels: map[string]string{"schema": declcfg.SchemaBundle, "catalog": "catalog-1"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(`{"name":123123123}`), - }, - }) + catalogContentMap["catalog-1"] = append(catalogContentMap["catalog-1"], []byte(`{"schema": "olm.bundle", "name":123123123}`)...) - return objs, nil + return objs, nil, catalogContentMap }, - wantErr: "error unmarshalling catalog metadata: json: cannot unmarshal number into Go struct field Bundle.name of type string", + wantErr: "error processing response: expected value for key \"name\" to be a string, got %!t(float64=1.23123123e+08): 1.23123123e+08", }, { name: "invalid channel", - fakeCatalog: func() ([]client.Object, []*catalogmetadata.Bundle) { - objs, _ := defaultFakeCatalog() + fakeCatalog: func() ([]client.Object, []*catalogmetadata.Bundle, map[string][]byte) { + objs, _, catalogContentMap := defaultFakeCatalog() - objs = append(objs, &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-1-fake1-broken-channel", - Labels: map[string]string{"schema": declcfg.SchemaChannel, "catalog": "catalog-1"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(`{"name":123123123}`), - }, - }) + catalogContentMap["catalog-1"] = append(catalogContentMap["catalog-1"], []byte(`{"schema": "olm.channel", "name":123123123}`)...) - return objs, nil + return objs, nil, catalogContentMap }, - wantErr: "error unmarshalling catalog metadata: json: cannot unmarshal number into Go struct field Channel.name of type string", + wantErr: "error processing response: expected value for key \"name\" to be a string, got %!t(float64=1.23123123e+08): 1.23123123e+08", }, } { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() - objs, expectedBundles := tt.fakeCatalog() + objs, expectedBundles, catalogContentMap := tt.fakeCatalog() + + mux := http.NewServeMux() + for k, v := range catalogContentMap { + content := v + mux.HandleFunc(fmt.Sprintf("/catalogs/%s/all.json", k), func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(content) + }) + } + srv := httptest.NewServer(mux) fakeCatalogClient := catalogClient.NewClient( fake.NewClientBuilder().WithScheme(scheme).WithObjects(objs...).Build(), + catalogClient.WithBaseURL(srv.URL), ) bundles, err := fakeCatalogClient.Bundles(ctx) @@ -127,9 +117,9 @@ func TestClient(t *testing.T) { }) } -func defaultFakeCatalog() ([]client.Object, []*catalogmetadata.Bundle) { +func defaultFakeCatalog() ([]client.Object, []*catalogmetadata.Bundle, map[string][]byte) { package1 := `{ - "schema": "olm.bundle", + "schema": "olm.package", "name": "fake1" }` @@ -179,69 +169,6 @@ func defaultFakeCatalog() ([]client.Object, []*catalogmetadata.Bundle) { Name: "catalog-2", }, }, - &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-1-fake1", - Labels: map[string]string{"schema": declcfg.SchemaPackage, "catalog": "catalog-1"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(package1), - }, - }, - &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-1-fake1-channel-stable", - Labels: map[string]string{"schema": declcfg.SchemaChannel, "catalog": "catalog-1"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(stableChannel), - }, - }, - &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-1-fake1-channel-beta", - Labels: map[string]string{"schema": declcfg.SchemaChannel, "catalog": "catalog-1"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(betaChannel), - }, - }, - &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-1-fake1-bundle-1", - Labels: map[string]string{"schema": declcfg.SchemaBundle, "catalog": "catalog-1"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(bundle1), - }, - }, - &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-2-fake1", - Labels: map[string]string{"schema": declcfg.SchemaPackage, "catalog": "catalog-2"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(package1), - }, - }, - &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-2-fake1-channel-stable", - Labels: map[string]string{"schema": declcfg.SchemaChannel, "catalog": "catalog-2"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(stableChannel), - }, - }, - &catalogd.CatalogMetadata{ - ObjectMeta: metav1.ObjectMeta{ - Name: "catalog-2-fake1-bundle-1", - Labels: map[string]string{"schema": declcfg.SchemaBundle, "catalog": "catalog-2"}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(bundle1), - }, - }, } expectedBundles := []*catalogmetadata.Bundle{ @@ -263,7 +190,7 @@ func defaultFakeCatalog() ([]client.Object, []*catalogmetadata.Bundle) { { Channel: declcfg.Channel{ Schema: declcfg.SchemaChannel, - Name: "beta", + Name: "stable", Package: "fake1", Entries: []declcfg.ChannelEntry{ { @@ -275,7 +202,7 @@ func defaultFakeCatalog() ([]client.Object, []*catalogmetadata.Bundle) { { Channel: declcfg.Channel{ Schema: declcfg.SchemaChannel, - Name: "stable", + Name: "beta", Package: "fake1", Entries: []declcfg.ChannelEntry{ { @@ -317,5 +244,10 @@ func defaultFakeCatalog() ([]client.Object, []*catalogmetadata.Bundle) { }, } - return objs, expectedBundles + catalogContents := map[string][]byte{ + "catalog-1": []byte(strings.Join([]string{package1, bundle1, stableChannel, betaChannel}, "\n")), + "catalog-2": []byte(strings.Join([]string{package1, bundle1, stableChannel}, "\n")), + } + + return objs, expectedBundles, catalogContents } diff --git a/internal/catalogmetadata/unmarshal.go b/internal/catalogmetadata/unmarshal.go index 4bb85b20b..cb76bede5 100644 --- a/internal/catalogmetadata/unmarshal.go +++ b/internal/catalogmetadata/unmarshal.go @@ -3,18 +3,16 @@ package catalogmetadata import ( "encoding/json" - catalogd "github.com/operator-framework/catalogd/api/core/v1alpha1" + "github.com/operator-framework/operator-registry/alpha/declcfg" ) -func Unmarshal[T Schemas](cm []catalogd.CatalogMetadata) ([]*T, error) { - contents := make([]*T, 0, len(cm)) - for _, cm := range cm { - var content T - if err := json.Unmarshal(cm.Spec.Content, &content); err != nil { +func Unmarshal[T Schemas](meta *declcfg.Meta) (*T, error) { + var content T + if meta != nil { + if err := json.Unmarshal(meta.Blob, &content); err != nil { return nil, err } - contents = append(contents, &content) } - return contents, nil + return &content, nil } diff --git a/internal/catalogmetadata/unmarshal_test.go b/internal/catalogmetadata/unmarshal_test.go index 8ca44acab..d7d72e9c1 100644 --- a/internal/catalogmetadata/unmarshal_test.go +++ b/internal/catalogmetadata/unmarshal_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "testing" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -26,8 +25,6 @@ func init() { } func TestFetchByScheme(t *testing.T) { - fakeCatalogName := "fake-catalog" - validBundle := `{ "schema": "olm.bundle", "name": "fake1.v1.0.0", @@ -43,35 +40,25 @@ func TestFetchByScheme(t *testing.T) { for _, tt := range []struct { name string - objs []catalogd.CatalogMetadata - wantData []*catalogmetadata.Bundle + obj *declcfg.Meta + wantData *catalogmetadata.Bundle wantErr string }{ { name: "valid objects", - objs: []catalogd.CatalogMetadata{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "obj-1", - Labels: map[string]string{"schema": declcfg.SchemaBundle, "catalog": fakeCatalogName}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(validBundle), - }, - }, + obj: &declcfg.Meta{ + Blob: json.RawMessage(validBundle), }, - wantData: []*catalogmetadata.Bundle{ - { - Bundle: declcfg.Bundle{ - Schema: declcfg.SchemaBundle, - Name: "fake1.v1.0.0", - Package: "fake1", - Image: "fake-image", - Properties: []property.Property{ - { - Type: property.TypePackage, - Value: json.RawMessage(`{"packageName":"fake1","version":"1.0.0"}`), - }, + wantData: &catalogmetadata.Bundle{ + Bundle: declcfg.Bundle{ + Schema: declcfg.SchemaBundle, + Name: "fake1.v1.0.0", + Package: "fake1", + Image: "fake-image", + Properties: []property.Property{ + { + Type: property.TypePackage, + Value: json.RawMessage(`{"packageName":"fake1","version":"1.0.0"}`), }, }, }, @@ -79,26 +66,18 @@ func TestFetchByScheme(t *testing.T) { }, { name: "invalid objects", - objs: []catalogd.CatalogMetadata{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "obj-1", - Labels: map[string]string{"schema": declcfg.SchemaBundle, "catalog": fakeCatalogName}, - }, - Spec: catalogd.CatalogMetadataSpec{ - Content: json.RawMessage(`{"name":123123123}`), - }, - }, + obj: &declcfg.Meta{ + Blob: json.RawMessage(`{"name":123123123}`), }, wantErr: "json: cannot unmarshal number into Go struct field Bundle.name of type string", }, { name: "not found", - wantData: []*catalogmetadata.Bundle{}, + wantData: &catalogmetadata.Bundle{}, }, } { t.Run(tt.name, func(t *testing.T) { - data, err := catalogmetadata.Unmarshal[catalogmetadata.Bundle](tt.objs) + data, err := catalogmetadata.Unmarshal[catalogmetadata.Bundle](tt.obj) assert.Equal(t, tt.wantData, data) if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) diff --git a/internal/resolution/entitysources/catalogdsource.go b/internal/resolution/entitysources/catalogdsource.go index 106f893f8..cf2b4f569 100644 --- a/internal/resolution/entitysources/catalogdsource.go +++ b/internal/resolution/entitysources/catalogdsource.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" catalogd "github.com/operator-framework/catalogd/api/core/v1alpha1" "github.com/operator-framework/deppy/pkg/deppy" @@ -15,15 +16,35 @@ import ( "github.com/operator-framework/operator-controller/internal/resolution/entities" ) +const catalogdOnClusterBaseURL = "http://catalogd-catalogserver.catalogd-system.svc" + // CatalogdEntitySource is a source for(/collection of) deppy defined input.Entity, built from content // made accessible on-cluster by https://github.com/operator-framework/catalogd. // It is an implementation of deppy defined input.EntitySource type CatalogdEntitySource struct { - client client.Client + client client.Client + baseURL string } -func NewCatalogdEntitySource(client client.Client) *CatalogdEntitySource { - return &CatalogdEntitySource{client: client} +type CatalogdEntitySourceOpt func(es *CatalogdEntitySource) + +func WithBaseURL(baseURL string) CatalogdEntitySourceOpt { + return func(es *CatalogdEntitySource) { + es.baseURL = baseURL + } +} + +func NewCatalogdEntitySource(client client.Client, opts ...CatalogdEntitySourceOpt) *CatalogdEntitySource { + ces := &CatalogdEntitySource{ + client: client, + baseURL: catalogdOnClusterBaseURL, + } + + for _, opt := range opts { + opt(ces) + } + + return ces } func (es *CatalogdEntitySource) Get(_ context.Context, _ deppy.Identifier) (*input.Entity, error) { @@ -32,7 +53,7 @@ func (es *CatalogdEntitySource) Get(_ context.Context, _ deppy.Identifier) (*inp func (es *CatalogdEntitySource) Filter(ctx context.Context, filter input.Predicate) (input.EntityList, error) { resultSet := input.EntityList{} - entities, err := getEntities(ctx, es.client) + entities, err := getEntities(ctx, es.client, es.baseURL) if err != nil { return nil, err } @@ -45,7 +66,7 @@ func (es *CatalogdEntitySource) Filter(ctx context.Context, filter input.Predica } func (es *CatalogdEntitySource) GroupBy(ctx context.Context, fn input.GroupByFunction) (input.EntityListMap, error) { - entities, err := getEntities(ctx, es.client) + entities, err := getEntities(ctx, es.client, es.baseURL) if err != nil { return nil, err } @@ -60,7 +81,7 @@ func (es *CatalogdEntitySource) GroupBy(ctx context.Context, fn input.GroupByFun } func (es *CatalogdEntitySource) Iterate(ctx context.Context, fn input.IteratorFunction) error { - entities, err := getEntities(ctx, es.client) + entities, err := getEntities(ctx, es.client, es.baseURL) if err != nil { return err } @@ -72,7 +93,7 @@ func (es *CatalogdEntitySource) Iterate(ctx context.Context, fn input.IteratorFu return nil } -func getEntities(ctx context.Context, cl client.Client) (input.EntityList, error) { +func getEntities(ctx context.Context, cl client.Client, baseURL string) (input.EntityList, error) { allEntitiesList := input.EntityList{} var catalogList catalogd.CatalogList @@ -80,7 +101,7 @@ func getEntities(ctx context.Context, cl client.Client) (input.EntityList, error return nil, err } for _, catalog := range catalogList.Items { - channels, bundles, err := fetchCatalogMetadata(ctx, cl, catalog.Name) + channels, bundles, err := fetchCatalogMetadata(ctx, baseURL, catalog.Name) if err != nil { return nil, err } @@ -152,12 +173,12 @@ func MetadataToEntities(catalogName string, channels []declcfg.Channel, bundles return entityList, nil } -func fetchCatalogMetadata(ctx context.Context, cl client.Client, catalogName string) ([]declcfg.Channel, []declcfg.Bundle, error) { - channels, err := fetchCatalogMetadataByScheme[declcfg.Channel](ctx, cl, declcfg.SchemaChannel, catalogName) +func fetchCatalogMetadata(ctx context.Context, baseURL, catalogName string) ([]declcfg.Channel, []declcfg.Bundle, error) { + channels, err := fetchCatalogMetadataByScheme[declcfg.Channel](ctx, baseURL, declcfg.SchemaChannel, catalogName) if err != nil { return nil, nil, err } - bundles, err := fetchCatalogMetadataByScheme[declcfg.Bundle](ctx, cl, declcfg.SchemaBundle, catalogName) + bundles, err := fetchCatalogMetadataByScheme[declcfg.Bundle](ctx, baseURL, declcfg.SchemaBundle, catalogName) if err != nil { return nil, nil, err } @@ -169,21 +190,40 @@ type declcfgSchema interface { declcfg.Package | declcfg.Bundle | declcfg.Channel } +const catalogdOnClusterURLTemplate = "%s/catalogs/%s/all.json" + // TODO: Cleanup once https://github.com/golang/go/issues/45380 implemented // We should be able to get rid of the schema arg and switch based on the type passed to this generic -func fetchCatalogMetadataByScheme[T declcfgSchema](ctx context.Context, cl client.Client, schema, catalogName string) ([]T, error) { - cmList := catalogd.CatalogMetadataList{} - if err := cl.List(ctx, &cmList, client.MatchingLabels{"schema": schema, "catalog": catalogName}); err != nil { - return nil, err +func fetchCatalogMetadataByScheme[T declcfgSchema](ctx context.Context, baseURL, schema, catalogName string) ([]T, error) { + contents := []T{} + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf(catalogdOnClusterURLTemplate, baseURL, catalogName), nil) + if err != nil { + return nil, fmt.Errorf("error forming request: %s", err) } - contents := []T{} - for _, cm := range cmList.Items { - var content T - if err := json.Unmarshal(cm.Spec.Content, &content); err != nil { - return nil, err + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, fmt.Errorf("error performing request: %s", err) + } + defer resp.Body.Close() + + err = declcfg.WalkMetasReader(resp.Body, func(meta *declcfg.Meta, err error) error { + if err != nil { + return err + } + + if meta.Schema == schema { + var content T + if err := json.Unmarshal(meta.Blob, &content); err != nil { + return fmt.Errorf("error unmarshalling content: %s", err) + } + contents = append(contents, content) } - contents = append(contents, content) + + return nil + }) + if err != nil { + return nil, fmt.Errorf("error processing response: %s", err) } return contents, nil