Skip to content

Commit 12c2ca9

Browse files
committed
initial commit for graphql refactoring and handler
Signed-off-by: Joe Lanford <[email protected]>
1 parent 0491775 commit 12c2ca9

File tree

22 files changed

+1490
-397
lines changed

22 files changed

+1490
-397
lines changed

cmd/catalogd/main.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"errors"
2323
"flag"
2424
"fmt"
25+
"net/http"
2526
"net/url"
2627
"os"
2728
"path/filepath"
@@ -54,6 +55,7 @@ import (
5455
corecontrollers "github.com/operator-framework/operator-controller/internal/catalogd/controllers/core"
5556
"github.com/operator-framework/operator-controller/internal/catalogd/features"
5657
"github.com/operator-framework/operator-controller/internal/catalogd/garbagecollection"
58+
"github.com/operator-framework/operator-controller/internal/catalogd/handlers"
5759
catalogdmetrics "github.com/operator-framework/operator-controller/internal/catalogd/metrics"
5860
"github.com/operator-framework/operator-controller/internal/catalogd/serverutil"
5961
"github.com/operator-framework/operator-controller/internal/catalogd/storage"
@@ -341,10 +343,24 @@ func run(ctx context.Context) error {
341343
return err
342344
}
343345

346+
indexer := storage.NewIndexer()
347+
handlersMap := map[string]http.Handler{
348+
"/all": handlers.V1AllHandler(indexer),
349+
}
350+
351+
if features.CatalogdFeatureGate.Enabled(features.APIV1MetasHandler) {
352+
handlersMap["/metas"] = handlers.V1MetasHandler(indexer)
353+
}
354+
355+
if features.CatalogdFeatureGate.Enabled(features.APIV1GraphQLHandler) {
356+
handlersMap["/graphql"] = handlers.V1GraphQLHandler()
357+
}
358+
344359
localStorage = &storage.LocalDirV1{
345-
RootDir: storeDir,
346-
RootURL: baseStorageURL,
347-
EnableMetasHandler: features.CatalogdFeatureGate.Enabled(features.APIV1MetasHandler),
360+
Indexer: indexer,
361+
Handlers: handlersMap,
362+
RootDir: storeDir,
363+
RootURL: baseStorageURL,
348364
}
349365

350366
// Config for the catalogd web server

config/components/base/experimental/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ components:
1212
- ../../features/single-own-namespace
1313
- ../../features/preflight-permissions
1414
- ../../features/apiv1-metas-handler
15+
- ../../features/apiv1-graphql-handler
1516
- ../../features/helm-chart
1617
# This one is downstream only, so we shant use it
1718
# - ../../features/webhook-provider-openshift-serviceca
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# kustomization file for catalogd APIv1 metas handler
2+
# DO NOT ADD A NAMESPACE HERE
3+
apiVersion: kustomize.config.k8s.io/v1alpha1
4+
kind: Component
5+
patches:
6+
- target:
7+
kind: Deployment
8+
name: catalogd-controller-manager
9+
path: patches/enable-featuregate.yaml
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# enable APIv1 meta handler feature gate
2+
- op: add
3+
path: /spec/template/spec/containers/0/args/-
4+
value: "--feature-gates=APIV1GraphQLHandler=true"

config/overlays/tilt-local-dev/patches/catalogd.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
value: null
88
- op: remove
99
# remove --leader-elect so container doesn't restart during breakpoints
10-
path: /spec/template/spec/containers/0/args/2
10+
path: /spec/template/spec/containers/0/args/0

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ require (
1616
github.com/google/go-containerregistry v0.20.6
1717
github.com/google/renameio/v2 v2.0.0
1818
github.com/gorilla/handlers v1.5.2
19+
github.com/graphql-go/graphql v0.8.1
20+
github.com/graphql-go/handler v0.2.4
21+
github.com/itchyny/gojq v0.12.17
1922
github.com/klauspost/compress v1.18.0
2023
github.com/opencontainers/go-digest v1.0.0
2124
github.com/opencontainers/image-spec v1.1.1
@@ -28,6 +31,7 @@ require (
2831
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
2932
golang.org/x/mod v0.26.0
3033
golang.org/x/sync v0.16.0
34+
golang.org/x/text v0.27.0
3135
golang.org/x/tools v0.35.0
3236
gopkg.in/yaml.v2 v2.4.0
3337
helm.sh/helm/v3 v3.18.4
@@ -133,6 +137,7 @@ require (
133137
github.com/hashicorp/go-multierror v1.1.1 // indirect
134138
github.com/huandu/xstrings v1.5.0 // indirect
135139
github.com/inconshreveable/mousetrap v1.1.0 // indirect
140+
github.com/itchyny/timefmt-go v0.1.6 // indirect
136141
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
137142
github.com/jmoiron/sqlx v1.4.0 // indirect
138143
github.com/joelanford/ignore v0.1.1 // indirect
@@ -221,7 +226,6 @@ require (
221226
golang.org/x/oauth2 v0.30.0 // indirect
222227
golang.org/x/sys v0.34.0 // indirect
223228
golang.org/x/term v0.33.0 // indirect
224-
golang.org/x/text v0.27.0 // indirect
225229
golang.org/x/time v0.12.0 // indirect
226230
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated // indirect
227231
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5T
246246
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
247247
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
248248
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
249+
github.com/graphql-go/graphql v0.8.1 h1:p7/Ou/WpmulocJeEx7wjQy611rtXGQaAcXGqanuMMgc=
250+
github.com/graphql-go/graphql v0.8.1/go.mod h1:nKiHzRM0qopJEwCITUuIsxk9PlVlwIiiI8pnJEhordQ=
251+
github.com/graphql-go/handler v0.2.4 h1:gz9q11TUHPNUpqzV8LMa+rkqM5NUuH/nkE3oF2LS3rI=
252+
github.com/graphql-go/handler v0.2.4/go.mod h1:gsQlb4gDvURR0bgN8vWQEh+s5vJALM2lYL3n3cf6OxQ=
249253
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
250254
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
251255
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 h1:JYghRBlGCZyCF2wNUJ8W0cwaQdtpcssJ4CgC406g+WU=
@@ -269,6 +273,10 @@ github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI
269273
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
270274
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
271275
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
276+
github.com/itchyny/gojq v0.12.17 h1:8av8eGduDb5+rvEdaOO+zQUjA04MS0m3Ps8HiD+fceg=
277+
github.com/itchyny/gojq v0.12.17/go.mod h1:WBrEMkgAfAGO1LUcGOckBl5O726KPp+OlkKug0I/FEY=
278+
github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q=
279+
github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
272280
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
273281
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
274282
github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=

internal/catalogd/features/features.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import (
99
)
1010

1111
const (
12-
APIV1MetasHandler = featuregate.Feature("APIV1MetasHandler")
12+
APIV1MetasHandler = featuregate.Feature("APIV1MetasHandler")
13+
APIV1GraphQLHandler = featuregate.Feature("APIV1GraphQLHandler")
1314
)
1415

1516
var catalogdFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
16-
APIV1MetasHandler: {Default: false, PreRelease: featuregate.Alpha},
17+
APIV1MetasHandler: {Default: false, PreRelease: featuregate.Alpha},
18+
APIV1GraphQLHandler: {Default: false, PreRelease: featuregate.Alpha},
1719
}
1820

1921
var CatalogdFeatureGate featuregate.MutableFeatureGate = featuregate.NewFeatureGate()

internal/catalogd/handlers/all.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package handlers
2+
3+
import (
4+
"github.com/operator-framework/operator-controller/internal/catalogd/handlers/internal/handlerutil"
5+
"net/http"
6+
7+
"k8s.io/klog/v2"
8+
9+
"github.com/operator-framework/operator-controller/internal/catalogd/storage"
10+
)
11+
12+
func V1AllHandler(indexer *storage.Indexer) http.Handler {
13+
return handlerutil.AllowedMethodsHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14+
catalog := r.PathValue("catalog")
15+
logger := klog.FromContext(r.Context()).WithValues("catalog", catalog)
16+
17+
idx, err := indexer.GetIndex(catalog)
18+
if err != nil {
19+
logger.Error(err, "error getting index")
20+
http.Error(w, "Not found", http.StatusNotFound)
21+
return
22+
}
23+
24+
catalogFile := idx.All()
25+
catalogStat, err := idx.Stat()
26+
if err != nil {
27+
logger.Error(err, "error stat-ing index")
28+
http.Error(w, "Internal server error", http.StatusInternalServerError)
29+
return
30+
}
31+
32+
w.Header().Add("Content-Type", "application/jsonl")
33+
http.ServeContent(w, r, "", catalogStat.ModTime(), catalogFile)
34+
}), http.MethodGet, http.MethodHead)
35+
}

internal/catalogd/handlers/graphql.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package handlers
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
"sync"
9+
10+
"k8s.io/klog/v2"
11+
12+
"github.com/operator-framework/operator-registry/alpha/declcfg"
13+
14+
"github.com/operator-framework/operator-controller/internal/catalogd/handlers/internal/graphql"
15+
"github.com/operator-framework/operator-controller/internal/catalogd/storage"
16+
)
17+
18+
type GraphQLHandler struct {
19+
catalogHandlers map[string]http.Handler
20+
mu sync.RWMutex
21+
}
22+
23+
var (
24+
_ storage.MetaProcessor = (*GraphQLHandler)(nil)
25+
_ http.Handler = (*GraphQLHandler)(nil)
26+
)
27+
28+
func V1GraphQLHandler() *GraphQLHandler {
29+
return &GraphQLHandler{
30+
catalogHandlers: make(map[string]http.Handler),
31+
}
32+
}
33+
34+
func (h *GraphQLHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
35+
catalog := r.PathValue("catalog")
36+
logger := klog.FromContext(r.Context()).WithValues("catalog", catalog)
37+
38+
h.mu.RLock()
39+
defer h.mu.RUnlock()
40+
41+
handler, ok := h.catalogHandlers[catalog]
42+
if !ok {
43+
logger.Error(errors.New("no handler found for catalog"), "catalog not found")
44+
http.Error(w, "Not found", http.StatusNotFound)
45+
return
46+
}
47+
r = r.WithContext(graphql.NewRequestContext(r.Context()))
48+
handler.ServeHTTP(w, r)
49+
}
50+
51+
func (h *GraphQLHandler) ProcessMetas(ctx context.Context, catalog string, idx *storage.Index, metasChan <-chan *declcfg.Meta) error {
52+
handler, err := graphql.NewHandler(ctx, idx, metasChan)
53+
if err != nil {
54+
return fmt.Errorf("failed to create graphql handler: %w", err)
55+
}
56+
57+
h.mu.Lock()
58+
defer h.mu.Unlock()
59+
60+
h.catalogHandlers[catalog] = handler
61+
return nil
62+
}

0 commit comments

Comments
 (0)