From a625a1767e057a32a68b3eba49602a0356ad0502 Mon Sep 17 00:00:00 2001 From: Ali Ok Date: Wed, 15 Jan 2025 11:03:03 +0300 Subject: [PATCH] Define and implement an OpenAPI spec in the backend (#141) * Define and use an OpenAPI spec Signed-off-by: Ali Ok * Add new codegen to update and verify scripts Signed-off-by: Ali Ok * Update codegen Signed-off-by: Ali Ok * goimports Signed-off-by: Ali Ok * Fix URLs in tests and the plugin Signed-off-by: Ali Ok * Make linter happier Signed-off-by: Ali Ok * Fix scripts Signed-off-by: Ali Ok --------- Signed-off-by: Ali Ok --- backends/pkg/reconciler/eventmesh/api.gen.go | 75 ++++ .../eventmesh/authtokenmiddleware.go | 50 +++ backends/pkg/reconciler/eventmesh/broker.go | 22 -- .../eventmesh/{handler.go => builder.go} | 94 +---- .../{handler_test.go => builder_test.go} | 91 +++-- .../pkg/reconciler/eventmesh/controller.go | 32 +- backends/pkg/reconciler/eventmesh/endpoint.go | 64 ++++ .../pkg/reconciler/eventmesh/eventtype.go | 62 +-- .../pkg/reconciler/eventmesh/server.gen.go | 360 ++++++++++++++++++ backends/pkg/reconciler/eventmesh/util.go | 7 + backends/tests/e2e/integration_test.go | 4 +- .../src/providers/knativeEventMeshProvider.ts | 9 +- go.mod | 13 +- go.sum | 52 ++- hack/generate.go | 4 + hack/oapi-models-config-event-mesh.yaml | 5 + hack/oapi-server-config-event-mesh.yaml | 9 + hack/tools.go | 2 + hack/update-codegen.sh | 1 + hack/update-go-codegen.sh | 23 ++ hack/verify-codegen.sh | 1 + hack/verify-go-codegen.sh | 48 +++ specs/event-mesh.yaml | 180 +++++++++ 23 files changed, 1029 insertions(+), 179 deletions(-) create mode 100644 backends/pkg/reconciler/eventmesh/api.gen.go create mode 100644 backends/pkg/reconciler/eventmesh/authtokenmiddleware.go rename backends/pkg/reconciler/eventmesh/{handler.go => builder.go} (82%) rename backends/pkg/reconciler/eventmesh/{handler_test.go => builder_test.go} (92%) create mode 100644 backends/pkg/reconciler/eventmesh/endpoint.go create mode 100644 backends/pkg/reconciler/eventmesh/server.gen.go create mode 100644 hack/generate.go create mode 100644 hack/oapi-models-config-event-mesh.yaml create mode 100644 hack/oapi-server-config-event-mesh.yaml create mode 100755 hack/update-go-codegen.sh create mode 100755 hack/verify-go-codegen.sh create mode 100644 specs/event-mesh.yaml diff --git a/backends/pkg/reconciler/eventmesh/api.gen.go b/backends/pkg/reconciler/eventmesh/api.gen.go new file mode 100644 index 00000000..befdaf6f --- /dev/null +++ b/backends/pkg/reconciler/eventmesh/api.gen.go @@ -0,0 +1,75 @@ +// Package eventmesh provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +package eventmesh + +const ( + BearerAuthScopes = "bearerAuth.Scopes" +) + +// Broker Broker is a simplified representation of a Knative Eventing Broker that is easier to consume by the Backstage plugin. +type Broker struct { + // Annotations Annotations of the broker. + Annotations map[string]string `json:"annotations"` + + // Labels Labels of the broker. + Labels map[string]string `json:"labels"` + + // Name Name of the broker. + Name string `json:"name"` + + // Namespace Namespace of the broker. + Namespace string `json:"namespace"` + + // ProvidedEventTypes List of event types provided by the broker. + ProvidedEventTypes []string `json:"providedEventTypes"` + + // UID UID of the broker. + UID string `json:"uid"` +} + +// EventMesh EventMesh is the top-level struct that holds the event mesh data. It's the struct that's serialized and sent to the Backstage plugin. +type EventMesh struct { + // Brokers Brokers is a list of all brokers in the cluster. + Brokers []Broker `json:"brokers"` + + // EventTypes EventTypes is a list of all event types in the cluster. While we can embed the event types in the brokers, we keep them separate because not every event type is tied to a broker. + EventTypes []EventType `json:"eventTypes"` +} + +// EventType EventType is a simplified representation of a Knative Eventing EventType that is easier to consume by the Backstage plugin. +type EventType struct { + // Annotations Annotations of the event type. These are passed as is, except that are filtered out by the `FilterAnnotations` function. + Annotations map[string]string `json:"annotations"` + + // ConsumedBy ConsumedBy is a `` list of the consumers of the event type. + ConsumedBy []string `json:"consumedBy"` + + // Description Description of the event type. + Description *string `json:"description,omitempty"` + + // Labels Labels of the event type. These are passed as is. + Labels map[string]string `json:"labels"` + + // Name Name of the event type. + Name string `json:"name"` + + // Namespace Namespace of the event type. + Namespace string `json:"namespace"` + + // Reference Reference is the EventTypes's reference to a resource like a broker or a channel. It is in the format `/`. + Reference *string `json:"reference,omitempty"` + + // SchemaData Schema data. + // Deprecated: + SchemaData *string `json:"schemaData,omitempty"` + + // SchemaURL URL to the schema. + SchemaURL *string `json:"schemaURL,omitempty"` + + // Type Type of the event. + Type string `json:"type"` + + // Uid UID of the event type. + Uid string `json:"uid"` +} diff --git a/backends/pkg/reconciler/eventmesh/authtokenmiddleware.go b/backends/pkg/reconciler/eventmesh/authtokenmiddleware.go new file mode 100644 index 00000000..0bbf0f48 --- /dev/null +++ b/backends/pkg/reconciler/eventmesh/authtokenmiddleware.go @@ -0,0 +1,50 @@ +package eventmesh + +import ( + "context" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type authTokenKey struct{} + +const ( + AuthTokenHeader = "Authorization" + BearerPrefix = "Bearer " +) + +func AuthTokenMiddleware() mux.MiddlewareFunc { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authTokenStr := r.Header.Get(AuthTokenHeader) + if authTokenStr != "" && strings.HasPrefix(authTokenStr, BearerPrefix) { + authTokenStr = strings.TrimPrefix(authTokenStr, BearerPrefix) + } + + // set the token in the context + if authTokenStr == "" || strings.TrimSpace(authTokenStr) == "" { + http.Error(w, "missing auth token. set the 'Authorization: Bearer YOUR_KEY' header", http.StatusUnauthorized) + return + } + + ctx := WithAuthToken(r.Context(), authTokenStr) + + // Call the handler + next.ServeHTTP(w, r.WithContext(ctx)) + }) + } +} + +func WithAuthToken(ctx context.Context, authToken string) context.Context { + return context.WithValue(ctx, authTokenKey{}, authToken) +} + +func GetAuthToken(ctx context.Context) (string, bool) { + token, ok := ctx.Value(authTokenKey{}).(string) + if token == "" { + return "", false + } + return token, ok +} diff --git a/backends/pkg/reconciler/eventmesh/broker.go b/backends/pkg/reconciler/eventmesh/broker.go index 553455d1..f73a88d8 100644 --- a/backends/pkg/reconciler/eventmesh/broker.go +++ b/backends/pkg/reconciler/eventmesh/broker.go @@ -4,28 +4,6 @@ import ( eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" ) -// Broker is a simplified representation of a Knative Eventing Broker that is easier to consume by the Backstage plugin. -type Broker struct { - // Namespace of the broker - Namespace string `json:"namespace"` - - // Name of the broker - Name string `json:"name"` - - // UID of the broker - UID string `json:"uid"` - - // Labels of the broker. These are passed as is. - Labels map[string]string `json:"labels,omitempty"` - - // Annotations of the broker. These are passed as is, except that are filtered out by the FilterAnnotations function. - Annotations map[string]string `json:"annotations,omitempty"` - - // ProvidedEventTypes is a list of event types that the broker provides. - // This is a list of strings, where each string is a "/" of the event type. - ProvidedEventTypes []string `json:"providedEventTypes,omitempty"` -} - // GetNamespacedName returns the name and namespace of the broker in the format "/" func (b Broker) GetNamespacedName() string { return NamespacedName(b.Namespace, b.Name) diff --git a/backends/pkg/reconciler/eventmesh/handler.go b/backends/pkg/reconciler/eventmesh/builder.go similarity index 82% rename from backends/pkg/reconciler/eventmesh/handler.go rename to backends/pkg/reconciler/eventmesh/builder.go index e6253a38..a56d3b42 100644 --- a/backends/pkg/reconciler/eventmesh/handler.go +++ b/backends/pkg/reconciler/eventmesh/builder.go @@ -3,96 +3,27 @@ package eventmesh import ( "context" "fmt" - "log" - "net/http" "sort" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/client-go/rest" + "go.uber.org/zap" + + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" "knative.dev/eventing/pkg/client/clientset/versioned" duckv1 "knative.dev/pkg/apis/duck/v1" - "knative.dev/pkg/logging" - "go.uber.org/zap" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" - - "k8s.io/apimachinery/pkg/util/json" ) -// EventMesh is the top-level struct that holds the event mesh data. -// It's the struct that's serialized and sent to the Backstage plugin. -type EventMesh struct { - // EventTypes is a list of all event types in the cluster. - // While we can embed the event types in the brokers, we keep them separate because - // not every event type is tied to a broker. - EventTypes []*EventType `json:"eventTypes"` - - // Brokers is a list of all brokers in the cluster. - Brokers []*Broker `json:"brokers"` -} - // BackstageKubernetesIDLabel is the label that's used to identify Backstage resources. // In Backstage Kubernetes plugin, a Backstage entity (e.g. a service) is tied to a Kubernetes resource // using this label. // see Backstage Kubernetes plugin for more details. const BackstageKubernetesIDLabel = "backstage.io/kubernetes-id" -// HttpHandler is the HTTP handler that's used to serve the event mesh data. -type HttpHandler struct { - ctx context.Context - inClusterConfig *rest.Config -} - -// This handler simply calls the event mesh builder and returns the result as JSON -func (h HttpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - logger := logging.FromContext(h.ctx) - - w.Header().Add("Content-Type", "application/json") - - logger.Debugw("Handling request", "method", req.Method, "url", req.URL) - - config := rest.CopyConfig(h.inClusterConfig) - authHeader := req.Header.Get("Authorization") - if authHeader == "" { - http.Error(w, "Authorization header is missing", http.StatusUnauthorized) - return - } - // header value is in this format: "Bearer " - // we only need the token part - if len(authHeader) < 8 || authHeader[:7] != "Bearer " { - http.Error(w, "Invalid Authorization header. Should start with `Bearer `", http.StatusUnauthorized) - return - } - config.BearerToken = authHeader[7:] - clientset, err := versioned.NewForConfig(config) - if err != nil { - log.Fatalf("Error creating clientset: %v", err) - } - - dynamicClient, err := dynamic.NewForConfig(config) - if err != nil { - log.Fatalf("Error creating dynamic client: %v", err) - } - - eventMesh, err := BuildEventMesh(h.ctx, clientset, dynamicClient, logger) - if err != nil { - logger.Errorw("Error building event mesh", "error", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - err = json.NewEncoder(w).Encode(eventMesh) - if err != nil { - logger.Errorw("Error encoding event mesh", "error", err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} - // BuildEventMesh builds the event mesh data by fetching and converting the Kubernetes resources. // The procedure is as follows: // - Fetch the brokers and convert them to the representation that's consumed by the Backstage plugin. @@ -124,8 +55,8 @@ func BuildEventMesh(ctx context.Context, clientset versioned.Interface, dynamicC // register the event types in the brokers for _, et := range convertedEventTypes { - if et.Reference != "" { - if br, ok := brokerMap[et.Reference]; ok { + if et.Reference != nil { + if br, ok := brokerMap[*et.Reference]; ok { br.ProvidedEventTypes = append(br.ProvidedEventTypes, et.NamespacedName()) } } @@ -157,9 +88,18 @@ func BuildEventMesh(ctx context.Context, clientset versioned.Interface, dynamicC } } + outputEventTypes := make([]EventType, 0, len(convertedEventTypes)) + for _, et := range convertedEventTypes { + outputEventTypes = append(outputEventTypes, *et) + } + outputBrokers := make([]Broker, 0, len(convertedBrokers)) + for _, br := range convertedBrokers { + outputBrokers = append(outputBrokers, *br) + } + eventMesh := EventMesh{ - EventTypes: convertedEventTypes, - Brokers: convertedBrokers, + EventTypes: outputEventTypes, + Brokers: outputBrokers, } return eventMesh, nil diff --git a/backends/pkg/reconciler/eventmesh/handler_test.go b/backends/pkg/reconciler/eventmesh/builder_test.go similarity index 92% rename from backends/pkg/reconciler/eventmesh/handler_test.go rename to backends/pkg/reconciler/eventmesh/builder_test.go index 7723f429..1097897e 100644 --- a/backends/pkg/reconciler/eventmesh/handler_test.go +++ b/backends/pkg/reconciler/eventmesh/builder_test.go @@ -4,28 +4,26 @@ import ( "context" "testing" - "k8s.io/apimachinery/pkg/types" - - dynamicfake "k8s.io/client-go/dynamic/fake" - "knative.dev/pkg/injection/clients/dynamicclient" - "github.com/google/go-cmp/cmp" + "go.uber.org/zap" + + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "knative.dev/pkg/apis" - - "go.uber.org/zap" + "k8s.io/apimachinery/pkg/types" + dynamicfake "k8s.io/client-go/dynamic/fake" + "k8s.io/utils/ptr" + "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/injection/clients/dynamicclient" eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta2 "knative.dev/eventing/pkg/apis/eventing/v1beta2" - corev1 "k8s.io/api/core/v1" + fakeclientset "knative.dev/eventing/pkg/client/clientset/versioned/fake" testingv1 "knative.dev/eventing/pkg/reconciler/testing/v1" testingv1beta2 "knative.dev/eventing/pkg/reconciler/testing/v1beta2" - - fakeclientset "knative.dev/eventing/pkg/client/clientset/versioned/fake" ) func TestBuildEventMesh(t *testing.T) { @@ -88,7 +86,7 @@ func TestBuildEventMesh(t *testing.T) { }, }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", @@ -97,18 +95,18 @@ func TestBuildEventMesh(t *testing.T) { Annotations: map[string]string{"test-broker-annotation": "foo"}, ProvidedEventTypes: []string{"test-ns/test-eventtype"}}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype", Namespace: "test-ns", Type: "test-eventtype-type", - UID: "test-eventtype-uid", - Description: "test-eventtype-description", - SchemaData: "test-eventtype-schema-data", - SchemaURL: "http://test-eventtype-schema", + Uid: "test-eventtype-uid", + Description: ptr.To("test-eventtype-description"), + SchemaData: ptr.To("test-eventtype-schema-data"), + SchemaURL: ptr.To("http://test-eventtype-schema"), Labels: map[string]string{"test-eventtype-label": "foo"}, Annotations: map[string]string{"test-eventtype-annotation": "foo"}, - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{"test-subscriber"}, }, }, @@ -126,18 +124,18 @@ func TestBuildEventMesh(t *testing.T) { ), }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", ProvidedEventTypes: []string{"test-ns/test-eventtype"}}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype", Namespace: "test-ns", Type: "test-eventtype-type", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{}, }, }, @@ -158,25 +156,25 @@ func TestBuildEventMesh(t *testing.T) { ), }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", ProvidedEventTypes: []string{"test-ns/test-eventtype-1"}}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype-1", Namespace: "test-ns", Type: "test-eventtype-type-1", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{}, }, { Name: "test-eventtype-2", Namespace: "test-ns", Type: "test-eventtype-type-2", - Reference: "", + Reference: nil, ConsumedBy: []string{}, }, }, @@ -199,7 +197,7 @@ func TestBuildEventMesh(t *testing.T) { ), }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker-1", Namespace: "test-ns", @@ -211,19 +209,19 @@ func TestBuildEventMesh(t *testing.T) { ProvidedEventTypes: []string{"test-ns/test-eventtype-2"}, }, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype-1", Namespace: "test-ns", Type: "test-eventtype-type", - Reference: "test-ns/test-broker-1", + Reference: ptr.To("test-ns/test-broker-1"), ConsumedBy: []string{}, }, { Name: "test-eventtype-2", Namespace: "test-ns", Type: "test-eventtype-type", - Reference: "test-ns/test-broker-2", + Reference: ptr.To("test-ns/test-broker-2"), ConsumedBy: []string{}, }, }, @@ -264,18 +262,18 @@ func TestBuildEventMesh(t *testing.T) { }, }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", ProvidedEventTypes: []string{"test-ns/test-eventtype"}}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype", Namespace: "test-ns", Type: "test-eventtype-type", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{}, }, }, @@ -308,18 +306,18 @@ func TestBuildEventMesh(t *testing.T) { }, extraObjects: []runtime.Object{}, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", ProvidedEventTypes: []string{"test-ns/test-eventtype"}}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype", Namespace: "test-ns", Type: "test-eventtype-type", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{}, }, }, @@ -360,18 +358,18 @@ func TestBuildEventMesh(t *testing.T) { }, }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", ProvidedEventTypes: []string{"test-ns/test-eventtype"}}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype", Namespace: "test-ns", Type: "test-eventtype-type", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{}, }, }, @@ -415,7 +413,7 @@ func TestBuildEventMesh(t *testing.T) { }, }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", @@ -424,19 +422,19 @@ func TestBuildEventMesh(t *testing.T) { "test-ns/test-eventtype-2", }}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype-1", Namespace: "test-ns", Type: "test-eventtype-type-1", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{"test-subscriber"}, }, { Name: "test-eventtype-2", Namespace: "test-ns", Type: "test-eventtype-type-2", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{"test-subscriber"}, }, }, @@ -481,7 +479,7 @@ func TestBuildEventMesh(t *testing.T) { }, }, want: EventMesh{ - Brokers: []*Broker{ + Brokers: []Broker{ { Name: "test-broker", Namespace: "test-ns", @@ -490,19 +488,19 @@ func TestBuildEventMesh(t *testing.T) { "test-ns/test-eventtype-2", }}, }, - EventTypes: []*EventType{ + EventTypes: []EventType{ { Name: "test-eventtype-1", Namespace: "test-ns", Type: "test-eventtype-type-1", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{"test-subscriber"}, }, { Name: "test-eventtype-2", Namespace: "test-ns", Type: "test-eventtype-type-2", - Reference: "test-ns/test-broker", + Reference: ptr.To("test-ns/test-broker"), ConsumedBy: []string{"test-subscriber"}, }, }, @@ -516,7 +514,6 @@ func TestBuildEventMesh(t *testing.T) { v1beta2objects = append(v1beta2objects, et) } - //v1objects := make([]runtime.Object, 0, 10) for _, b := range tt.brokers { v1beta2objects = append(v1beta2objects, b) } diff --git a/backends/pkg/reconciler/eventmesh/controller.go b/backends/pkg/reconciler/eventmesh/controller.go index 2c6ac84f..8f74bebe 100644 --- a/backends/pkg/reconciler/eventmesh/controller.go +++ b/backends/pkg/reconciler/eventmesh/controller.go @@ -3,6 +3,13 @@ package eventmesh import ( "context" "log" + "net/http" + + "github.com/getkin/kin-openapi/openapi3filter" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/gorilla/mux" + middleware "github.com/oapi-codegen/nethttp-middleware" "knative.dev/eventing/pkg/kncloudevents" "knative.dev/pkg/injection" @@ -31,7 +38,28 @@ func startWebServer(ctx context.Context) { noTokenConfig.Password = "" noTokenConfig.BearerTokenFile = "" + swagger, err := GetSwagger() + if err != nil { + log.Fatalf("Error loading swagger spec: %v", err) + } + + endpoint := NewEndpoint(noTokenConfig, logger) + strictHandler := NewStrictHandler(endpoint, []StrictMiddlewareFunc{}) + router := mux.NewRouter() + router.Use(AuthTokenMiddleware()) + router.Use(requestValidator(swagger)) + handlerWithMiddleware := HandlerFromMux(strictHandler, router) + r := kncloudevents.NewHTTPEventReceiver(8080) - err := r.StartListen(ctx, HttpHandler{ctx, noTokenConfig}) - log.Fatal(err) + log.Fatal(r.StartListen(ctx, handlerWithMiddleware)) +} + +func requestValidator(swagger *openapi3.T) func(next http.Handler) http.Handler { + return middleware.OapiRequestValidatorWithOptions(swagger, &middleware.Options{ + Options: openapi3filter.Options{ + // we use a NoopAuthenticationFunc because we want to be able to + // set the user in the context in the middleware + AuthenticationFunc: openapi3filter.NoopAuthenticationFunc, + }, + }) } diff --git a/backends/pkg/reconciler/eventmesh/endpoint.go b/backends/pkg/reconciler/eventmesh/endpoint.go new file mode 100644 index 00000000..a64bc458 --- /dev/null +++ b/backends/pkg/reconciler/eventmesh/endpoint.go @@ -0,0 +1,64 @@ +package eventmesh + +import ( + "context" + "fmt" + "log" + + "go.uber.org/zap" + + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "knative.dev/eventing/pkg/client/clientset/versioned" +) + +// Endpoint is the HTTP handler that's used to serve the event mesh data. +type Endpoint struct { + inClusterConfig *rest.Config + logger *zap.SugaredLogger +} + +// ensure that Endpoint implements the StrictServerInterface +var _ StrictServerInterface = &Endpoint{} + +func NewEndpoint(inClusterConfig *rest.Config, logger *zap.SugaredLogger) *Endpoint { + return &Endpoint{ + inClusterConfig: inClusterConfig, + logger: logger, + } +} + +func (e Endpoint) GetEventMesh(ctx context.Context, _ GetEventMeshRequestObject) (GetEventMeshResponseObject, error) { + logger := e.logger + + authToken, ok := GetAuthToken(ctx) + if !ok { + return GetEventMesh401JSONResponse{ + Error: "Authorization header is missing", + }, nil + } + + config := rest.CopyConfig(e.inClusterConfig) + config.BearerToken = authToken + + clientset, err := versioned.NewForConfig(config) + if err != nil { + log.Fatalf("Error creating clientset: %v", err) + } + + dynamicClient, err := dynamic.NewForConfig(config) + if err != nil { + log.Fatalf("Error creating dynamic client: %v", err) + } + + eventMesh, err := BuildEventMesh(ctx, clientset, dynamicClient, logger) + if err != nil { + logger.Errorw("Error building event mesh", "error", err) + return nil, fmt.Errorf("error building event mesh: %w", err) + } + + return GetEventMesh200JSONResponse{ + Brokers: eventMesh.Brokers, + EventTypes: eventMesh.EventTypes, + }, nil +} diff --git a/backends/pkg/reconciler/eventmesh/eventtype.go b/backends/pkg/reconciler/eventmesh/eventtype.go index 488cf35f..171812b4 100644 --- a/backends/pkg/reconciler/eventmesh/eventtype.go +++ b/backends/pkg/reconciler/eventmesh/eventtype.go @@ -2,27 +2,9 @@ package eventmesh import ( "knative.dev/eventing/pkg/apis/eventing/v1beta2" + "knative.dev/eventing/pkg/apis/eventing/v1beta3" ) -// EventType is a simplified representation of a Knative Eventing EventType that is easier to consume by the Backstage plugin. -type EventType struct { - Namespace string `json:"namespace"` - Name string `json:"name"` - Type string `json:"type"` - UID string `json:"uid"` - Description string `json:"description,omitempty"` - SchemaData string `json:"schemaData,omitempty"` - SchemaURL string `json:"schemaURL,omitempty"` - // Labels of the event type. These are passed as is. - Labels map[string]string `json:"labels,omitempty"` - // Annotations of the event type. These are passed as is, except that are filtered out by the FilterAnnotations function. - Annotations map[string]string `json:"annotations,omitempty"` - // Reference is the ET's reference to a resource like a broker or a channel. It is in the format "/". - Reference string `json:"reference,omitempty"` - // ConsumedBy is a list of the consumers of the event type. - ConsumedBy []string `json:"consumedBy,omitempty"` -} - // NamespacedName returns the name and namespace of the event type in the format "/" func (et EventType) NamespacedName() string { return NamespacedName(et.Namespace, et.Name) @@ -33,6 +15,7 @@ func (et EventType) NamespacedType() string { return NamespacedName(et.Namespace, et.Type) } +// TODO: remove // convertEventType converts a Knative Eventing EventType to a simplified representation that is easier to consume by the Backstage plugin. // see EventType. func convertEventType(et *v1beta2.EventType) EventType { @@ -40,14 +23,45 @@ func convertEventType(et *v1beta2.EventType) EventType { Name: et.Name, Namespace: et.Namespace, Type: et.Spec.Type, - UID: string(et.UID), - Description: et.Spec.Description, - SchemaData: et.Spec.SchemaData, - SchemaURL: et.Spec.Schema.String(), + Uid: string(et.UID), + Description: ToStrPtrOrNil(et.Spec.Description), + SchemaData: ToStrPtrOrNil(et.Spec.SchemaData), + SchemaURL: ToStrPtrOrNil(et.Spec.Schema.String()), + Labels: et.Labels, + Annotations: FilterAnnotations(et.Annotations), + Reference: ToStrPtrOrNil(NamespacedRefName(et.Spec.Reference)), + // this field will be populated later on, when we have process the triggers + ConsumedBy: make([]string, 0), + } +} + +// convertEventType converts a Knative Eventing EventType to a simplified representation that is easier to consume by the Backstage plugin. +// see EventType. +func convertEventTypev1beta3(et *v1beta3.EventType) EventType { + cet := EventType{ + Name: et.Name, + Namespace: et.Namespace, + Uid: string(et.UID), + Description: ToStrPtrOrNil(et.Spec.Description), Labels: et.Labels, Annotations: FilterAnnotations(et.Annotations), - Reference: NamespacedRefName(et.Spec.Reference), + Reference: ToStrPtrOrNil(NamespacedRefName(et.Spec.Reference)), // this field will be populated later on, when we have process the triggers ConsumedBy: make([]string, 0), } + + if len(et.Spec.Attributes) == 0 { + return cet + } + + for _, attr := range et.Spec.Attributes { + switch attr.Name { + case "type": // TODO: any CE constant for these? + cet.Type = attr.Value + case "schemadata": + cet.SchemaURL = ToStrPtrOrNil(attr.Value) + } + } + + return cet } diff --git a/backends/pkg/reconciler/eventmesh/server.gen.go b/backends/pkg/reconciler/eventmesh/server.gen.go new file mode 100644 index 00000000..2968bbac --- /dev/null +++ b/backends/pkg/reconciler/eventmesh/server.gen.go @@ -0,0 +1,360 @@ +// Package eventmesh provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT. +package eventmesh + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "encoding/json" + "fmt" + "net/http" + "net/url" + "path" + "strings" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/gorilla/mux" + strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp" +) + +// ServerInterface represents all server handlers. +type ServerInterface interface { + // Retrieve EventMesh + // (GET /getEventMesh) + GetEventMesh(w http.ResponseWriter, r *http.Request) +} + +// ServerInterfaceWrapper converts contexts to parameters. +type ServerInterfaceWrapper struct { + Handler ServerInterface + HandlerMiddlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +type MiddlewareFunc func(http.Handler) http.Handler + +// GetEventMesh operation middleware +func (siw *ServerInterfaceWrapper) GetEventMesh(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetEventMesh(w, r) + })) + + for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- { + handler = siw.HandlerMiddlewares[i](handler) + } + + handler.ServeHTTP(w, r) +} + +type UnescapedCookieParamError struct { + ParamName string + Err error +} + +func (e *UnescapedCookieParamError) Error() string { + return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName) +} + +func (e *UnescapedCookieParamError) Unwrap() error { + return e.Err +} + +type UnmarshalingParamError struct { + ParamName string + Err error +} + +func (e *UnmarshalingParamError) Error() string { + return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error()) +} + +func (e *UnmarshalingParamError) Unwrap() error { + return e.Err +} + +type RequiredParamError struct { + ParamName string +} + +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) +} + +type RequiredHeaderError struct { + ParamName string + Err error +} + +func (e *RequiredHeaderError) Error() string { + return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName) +} + +func (e *RequiredHeaderError) Unwrap() error { + return e.Err +} + +type InvalidParamFormatError struct { + ParamName string + Err error +} + +func (e *InvalidParamFormatError) Error() string { + return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error()) +} + +func (e *InvalidParamFormatError) Unwrap() error { + return e.Err +} + +type TooManyValuesForParamError struct { + ParamName string + Count int +} + +func (e *TooManyValuesForParamError) Error() string { + return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) +} + +// Handler creates http.Handler with routing matching OpenAPI spec. +func Handler(si ServerInterface) http.Handler { + return HandlerWithOptions(si, GorillaServerOptions{}) +} + +type GorillaServerOptions struct { + BaseURL string + BaseRouter *mux.Router + Middlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. +func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler { + return HandlerWithOptions(si, GorillaServerOptions{ + BaseRouter: r, + }) +} + +func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler { + return HandlerWithOptions(si, GorillaServerOptions{ + BaseURL: baseURL, + BaseRouter: r, + }) +} + +// HandlerWithOptions creates http.Handler with additional options +func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler { + r := options.BaseRouter + + if r == nil { + r = mux.NewRouter() + } + if options.ErrorHandlerFunc == nil { + options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandlerFunc: options.ErrorHandlerFunc, + } + + r.HandleFunc(options.BaseURL+"/getEventMesh", wrapper.GetEventMesh).Methods("GET") + + return r +} + +type GetEventMeshRequestObject struct { +} + +type GetEventMeshResponseObject interface { + VisitGetEventMeshResponse(w http.ResponseWriter) error +} + +type GetEventMesh200JSONResponse EventMesh + +func (response GetEventMesh200JSONResponse) VisitGetEventMeshResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type GetEventMesh401JSONResponse struct { + Error string `json:"error"` +} + +func (response GetEventMesh401JSONResponse) VisitGetEventMeshResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(401) + + return json.NewEncoder(w).Encode(response) +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + // Retrieve EventMesh + // (GET /getEventMesh) + GetEventMesh(ctx context.Context, request GetEventMeshRequestObject) (GetEventMeshResponseObject, error) +} + +type StrictHandlerFunc = strictnethttp.StrictHTTPHandlerFunc +type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc + +type StrictHTTPServerOptions struct { + RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) + ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{ + RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + }, + ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusInternalServerError) + }, + }} +} + +func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares, options: options} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc + options StrictHTTPServerOptions +} + +// GetEventMesh operation middleware +func (sh *strictHandler) GetEventMesh(w http.ResponseWriter, r *http.Request) { + var request GetEventMeshRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.GetEventMesh(ctx, request.(GetEventMeshRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetEventMesh") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(GetEventMeshResponseObject); ok { + if err := validResponse.VisitGetEventMeshResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// Base64 encoded, gzipped, json marshaled Swagger object +var swaggerSpec = []string{ + + "H4sIAAAAAAAC/9RYWW8bNxD+KwRbIC+rK0kvvTlNWxhNi8C10QfLgKndkZYxl2TJWcVbQ/+9GHK1hy5L", + "jfvQJy+vmW9mvjnkJ56awhoNGj2fPnGf5lCI8PnOmQdw9JWBT520KI3m03qfSc8E87KwSi4kZMyBdeBB", + "o6B7zCyYYL9qgXIF7KcVaJR6yeq3mAskASC8pKVhqdG+LIDNK4Y5sHciffAolsCsKpdSD3nCrTMWHEoI", + "6ITWJqqKyyyTtBDqY+/awrhCIJ9yj07qJU84Vhba9TrZsu6ilUs2EJh5AE0Q4FEUVgEJfoCKT/lKqBJI", + "SC3VzD9BirShxBzUy0L7EER+ESotCtiN6O+igCNieVEN4jZPTkFNSrwV6QFN4egZda2IkzRaZ1Yygyzw", + "7Lqy0cFb3pMeSSvQHUYiPNu829BuD5rbHpxRUQ2CgEHAcJdwiVCcGs56QzgnKlqXMtvFeXP5/phzJq/f", + "vB188+133w9+GE9en+CehD8OlmYQI0/S+XqdcAd/ldJBRgZ2nR2uRWQNh5Nesu319t0eroXj38DnuzY2", + "R1QEyFI0dqBgBYp5dGWKsULkRmXxPAatoBeZQDFkl/gqnnTuv/LMg5NCyb8hY0JnzIdQmxNLSnS3P1Tx", + "fCx5quaRUKoOkGdSBxWpKj3GgDW0+NrBgk/5V6O2zo7qIjuqK+weZsARIrdu3wXUJfcWKPZnLhWwz8BS", + "oRkUc8g6ru09qc1K6PIDgKXNgnmwwgkENodUlB6YNkivXdWREQJK7QANEx0Cn+SPxrJdl2xRtuOfpInb", + "QRIGkYf9+O9aWfv8/9XN2lgN2XUOHphwwKzwnpKGOJUweEzB1klIpwupEBxkzJS4Mer+57DZ0XDPFqVO", + "6fPMrlS7K3tX7Ubpx+Yshul+Vo7Hb9K2ItNX2IP7JhUC7+NDt8/w4wV+8/JLy3vPkG273rerZwDy65zI", + "1UsxKCQiZOxzDpp5UwDmxMlcWAvaD0/rmv/5iPI81V58fDnkw37ffvEx5ojaM0cZBwtwoPdpvdocbbpm", + "2wleedY8jKXXgTelS4Ep+QBNKWbGMcHSXGgNirooiaqrfgS3k2Axt0btbp1shw0dnTkvxvL/XqCINlsH", + "qUAq9OhK2KbYH+F2HAN6EJ5mQfSMT2c1ZWY8mXUK7YxPn2Z8IUFlk/jd3I9gZny9Xp+D+ebqw54B7urD", + "ZuaIt/owc0TrpyNyUn2cmqKrtHTqcHXZVhYaUJeEfWVNaRjE0gDZaeY9N5ke4vvZ0+kJs2idsUdH0k4H", + "2Z0CKFyQlk5iFchTT3sgHLiLEvPmdy89itstTgoX0SLhUi/MrlMuPl5StB2gk7CCNi/jeKujA+qeiBKD", + "m9oLFx8vecJX4HwUNxmOh2OKgLGghZV8yt8Mx8MJTQwC84B8tATsDddLwH3VAkun/Rag6BNqjiikpp6x", + "mWFpXu7MggSXEidgv8z4lP/S1UpR89ZoH535ejymPyQWdAAjrFUyDa9Hn3zsgJHvJ02BQUlw+1b2l2kK", + "3i9KparG6dleI4fkxrfjyVnA+mMZOGfCf0Baht9oUWJuHP3GeJbN8f0eRu7Y1RU77FGWT2/7ZL29W98l", + "3JdFIVwVAx2p13Pc+p8AAAD//43lNAHaEQAA", +} + +// GetSwagger returns the content of the embedded swagger specification file +// or error if failed to decode +func decodeSpec() ([]byte, error) { + zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) + if err != nil { + return nil, fmt.Errorf("error base64 decoding spec: %w", err) + } + zr, err := gzip.NewReader(bytes.NewReader(zipped)) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %w", err) + } + var buf bytes.Buffer + _, err = buf.ReadFrom(zr) + if err != nil { + return nil, fmt.Errorf("error decompressing spec: %w", err) + } + + return buf.Bytes(), nil +} + +var rawSpec = decodeSpecCached() + +// a naive cached of a decoded swagger spec +func decodeSpecCached() func() ([]byte, error) { + data, err := decodeSpec() + return func() ([]byte, error) { + return data, err + } +} + +// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. +func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { + res := make(map[string]func() ([]byte, error)) + if len(pathToFile) > 0 { + res[pathToFile] = rawSpec + } + + return res +} + +// GetSwagger returns the Swagger specification corresponding to the generated code +// in this file. The external references of Swagger specification are resolved. +// The logic of resolving external references is tightly connected to "import-mapping" feature. +// Externally referenced files must be embedded in the corresponding golang packages. +// Urls can be supported but this task was out of the scope. +func GetSwagger() (swagger *openapi3.T, err error) { + resolvePath := PathToRawSpec("") + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { + pathToFile := url.String() + pathToFile = path.Clean(pathToFile) + getSpec, ok := resolvePath[pathToFile] + if !ok { + err1 := fmt.Errorf("path not found: %s", pathToFile) + return nil, err1 + } + return getSpec() + } + var specData []byte + specData, err = rawSpec() + if err != nil { + return + } + swagger, err = loader.LoadFromData(specData) + if err != nil { + return + } + return +} diff --git a/backends/pkg/reconciler/eventmesh/util.go b/backends/pkg/reconciler/eventmesh/util.go index ddfef881..660d2f4c 100644 --- a/backends/pkg/reconciler/eventmesh/util.go +++ b/backends/pkg/reconciler/eventmesh/util.go @@ -20,3 +20,10 @@ func NamespacedRefName(ref *v1.KReference) string { func NamespacedName(namespace, name string) string { return fmt.Sprintf("%s/%s", namespace, name) } + +func ToStrPtrOrNil(s string) *string { + if s == "" { + return nil + } + return &s +} diff --git a/backends/tests/e2e/integration_test.go b/backends/tests/e2e/integration_test.go index 48c93bf4..2f072dcf 100644 --- a/backends/tests/e2e/integration_test.go +++ b/backends/tests/e2e/integration_test.go @@ -49,14 +49,14 @@ func VerifyBackstageBackendAuthentication() *feature.Feature { token := string(secret.Data["token"]) eventshub.Install(authenticatedClientName, - eventshub.StartSenderURL("http://eventmesh-backend.knative-eventing.svc.cluster.local:8080"), + eventshub.StartSenderURL("http://eventmesh-backend.knative-eventing.svc.cluster.local:8080/getEventMesh"), eventshub.InputHeader("Authorization", "Bearer "+token), eventshub.InputMethod("GET"), )(ctx, t) }) f.Setup("request with unauthenticated client", eventshub.Install( unauthenticatedClientName, - eventshub.StartSenderURL("http://eventmesh-backend.knative-eventing.svc.cluster.local:8080"), + eventshub.StartSenderURL("http://eventmesh-backend.knative-eventing.svc.cluster.local:8080/getEventMesh"), eventshub.InputHeader("Foo", "Bar"), eventshub.InputMethod("GET")), ) diff --git a/backstage/plugins/knative-event-mesh-backend/src/providers/knativeEventMeshProvider.ts b/backstage/plugins/knative-event-mesh-backend/src/providers/knativeEventMeshProvider.ts index 0f85420b..ae541293 100644 --- a/backstage/plugins/knative-event-mesh-backend/src/providers/knativeEventMeshProvider.ts +++ b/backstage/plugins/knative-event-mesh-backend/src/providers/knativeEventMeshProvider.ts @@ -49,8 +49,8 @@ type EventMesh = { brokers:Broker[]; }; -export async function getEventMesh(baseUrl: string, token: string | undefined):Promise { - const response = await fetch(`${baseUrl}`, { +export async function getEventMesh(url: string, token: string | undefined):Promise { + const response = await fetch(`${url}`, { headers: { 'Authorization': `Bearer ${token}` } @@ -169,9 +169,12 @@ export class KnativeEventMeshProvider implements EntityProvider { throw new Error('Not initialized'); } - const url = this.baseUrl; + // remove the trailing slash if it exists + const baseUrl = this.baseUrl.replace(/\/$/, ''); const token = this.token; + const url = `${baseUrl}/getEventMesh`; + const eventMesh = await getEventMesh(url, token); const entities = this.buildEntities(eventMesh); diff --git a/go.mod b/go.mod index 2c364e89..84c1a17e 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,17 @@ module knative.dev/backstage-plugins go 1.22.0 require ( + github.com/getkin/kin-openapi v0.128.0 github.com/google/go-cmp v0.6.0 + github.com/gorilla/mux v1.8.1 + github.com/oapi-codegen/nethttp-middleware v1.0.2 + github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 + github.com/oapi-codegen/runtime v1.1.1 go.uber.org/zap v1.27.0 k8s.io/api v0.30.3 k8s.io/apimachinery v0.30.3 k8s.io/client-go v0.30.3 + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 knative.dev/eventing v0.43.0 knative.dev/hack v0.0.0-20241010131451-05b2fb30cb4d knative.dev/pkg v0.0.0-20241021183759-9b9d535af5ad @@ -29,6 +35,7 @@ require ( github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect github.com/coreos/go-oidc/v3 v3.9.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect @@ -50,14 +57,17 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/imdario/mergo v0.3.16 // indirect + github.com/invopop/yaml v0.3.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kelseyhightower/envconfig v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.3 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.19.1 // indirect @@ -69,9 +79,11 @@ require ( github.com/rickb777/plural v1.2.1 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -102,7 +114,6 @@ require ( k8s.io/klog v1.0.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240808142205-8e686545bdb8 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 2d9e09e5..c575cab5 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,9 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -103,6 +106,11 @@ github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= +github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -131,9 +139,12 @@ github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDsl github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -202,6 +213,7 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -212,6 +224,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= @@ -228,9 +242,12 @@ github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= +github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -277,26 +294,44 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oapi-codegen/nethttp-middleware v1.0.2 h1:A5tfAcKJhWIbIPnlQH+l/DtfVE1i5TFgPlQAiW+l1vQ= +github.com/oapi-codegen/nethttp-middleware v1.0.2/go.mod h1:DfDalonSO+eRQ3RTb8kYoWZByCCPFRxm9WKq1UbY0E4= +github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q= +github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8= +github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= +github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -353,10 +388,14 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -374,6 +413,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -383,8 +423,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= +github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -491,6 +535,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -539,6 +584,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -560,6 +606,7 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -641,6 +688,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= @@ -754,6 +802,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -764,6 +813,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/hack/generate.go b/hack/generate.go new file mode 100644 index 00000000..5525fec1 --- /dev/null +++ b/hack/generate.go @@ -0,0 +1,4 @@ +package hack + +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config oapi-models-config-event-mesh.yaml ../specs/event-mesh.yaml +//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config oapi-server-config-event-mesh.yaml ../specs/event-mesh.yaml diff --git a/hack/oapi-models-config-event-mesh.yaml b/hack/oapi-models-config-event-mesh.yaml new file mode 100644 index 00000000..d3c15833 --- /dev/null +++ b/hack/oapi-models-config-event-mesh.yaml @@ -0,0 +1,5 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json +package: eventmesh +generate: + models: true +output: ../backends/pkg/reconciler/eventmesh/api.gen.go diff --git a/hack/oapi-server-config-event-mesh.yaml b/hack/oapi-server-config-event-mesh.yaml new file mode 100644 index 00000000..af4c9568 --- /dev/null +++ b/hack/oapi-server-config-event-mesh.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json +package: eventmesh +generate: + gorilla-server: true + strict-server: true + embedded-spec: true +output: ../backends/pkg/reconciler/eventmesh/server.gen.go +compatibility: + apply-gorilla-middleware-first-to-last: true diff --git a/hack/tools.go b/hack/tools.go index 15acd9e9..781a81f7 100644 --- a/hack/tools.go +++ b/hack/tools.go @@ -27,4 +27,6 @@ import ( // eventshub is a cloudevents sender/receiver utility for e2e testing. _ "knative.dev/reconciler-test/cmd/eventshub" + + _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen" ) diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index e55d8e4e..f1a40137 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -19,4 +19,5 @@ set -o nounset set -o pipefail $(dirname "$0")/update-templates.sh "$@" +$(dirname "$0")/update-go-codegen.sh "$@" $(dirname "$0")/update-deps.sh "$@" diff --git a/hack/update-go-codegen.sh b/hack/update-go-codegen.sh new file mode 100755 index 00000000..793ee345 --- /dev/null +++ b/hack/update-go-codegen.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Copyright 2023 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +source "$(go run knative.dev/hack/cmd/script library.sh)" + +go generate $(dirname "$0") diff --git a/hack/verify-codegen.sh b/hack/verify-codegen.sh index bc430ff8..cd6a7b85 100755 --- a/hack/verify-codegen.sh +++ b/hack/verify-codegen.sh @@ -21,4 +21,5 @@ set -o pipefail source "$(go run knative.dev/hack/cmd/script library.sh)" "${REPO_ROOT_DIR}/hack/verify-templates.sh" +"${REPO_ROOT_DIR}/hack/verify-go-codegen.sh" "${REPO_ROOT_DIR}/hack/verify-deps.sh" diff --git a/hack/verify-go-codegen.sh b/hack/verify-go-codegen.sh new file mode 100755 index 00000000..10fbca9c --- /dev/null +++ b/hack/verify-go-codegen.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# Copyright 2024 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +source "$(go run knative.dev/hack/cmd/script library.sh)" + +readonly TMP_DIFFROOT="$(mktemp -d ${REPO_ROOT_DIR}/tmpgocodegendiffroot.XXXXXX)" + +cleanup() { + rm -rf "${TMP_DIFFROOT}" +} + +trap "cleanup" EXIT SIGINT + +# Save working tree state +mkdir -p "${TMP_DIFFROOT}" +cp -aR "${REPO_ROOT_DIR}/backends" "${TMP_DIFFROOT}/" + +ret=0 +echo "Checking generated FS" +"${REPO_ROOT_DIR}/hack/update-go-codegen.sh" + +echo "Diffing ${REPO_ROOT_DIR} against freshly generated codegen" +diff -Nupr --no-dereference "${REPO_ROOT_DIR}/backends" "${TMP_DIFFROOT}/backends" || ret=1 + +if [[ $ret -eq 0 ]] +then + echo "${REPO_ROOT_DIR} is up to date." +else + echo "ERROR: ${REPO_ROOT_DIR} is out of date. Please run ./hack/update-go-codegen.sh" + exit 1 +fi diff --git a/specs/event-mesh.yaml b/specs/event-mesh.yaml new file mode 100644 index 00000000..835643bd --- /dev/null +++ b/specs/event-mesh.yaml @@ -0,0 +1,180 @@ +openapi: 3.0.1 +info: + title: EventMesh API + description: API to retrieve the EventMesh information. + version: 1.0.0 +paths: + /getEventMesh: + get: + summary: Retrieve EventMesh + description: Returns the EventMesh object containing brokers and event types. + operationId: getEventMesh + security: + - bearerAuth: [ ] + responses: + '200': + description: Successfully retrieved the EventMesh object. + content: + application/json: + schema: + $ref: '#/components/schemas/EventMesh' + '401': + description: Unauthorized. + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: Unauthorized + required: + - error +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + schemas: + Broker: + type: object + description: Broker is a simplified representation of a Knative Eventing Broker that is easier to consume by the Backstage plugin. + properties: + namespace: + type: string + description: Namespace of the broker. + format: string + example: my-namespace + name: + type: string + description: Name of the broker. + format: string + example: my-broker + uid: + type: string + description: UID of the broker. + format: string + x-go-name: UID + example: 1234-5678-9012 + labels: + type: object + additionalProperties: + type: string + format: string + description: Labels of the broker. + example: { "key": "value" } + annotations: + type: object + additionalProperties: + type: string + format: string + description: Annotations of the broker. + example: { "key": "value" } + providedEventTypes: + type: array + items: + type: string + format: string + description: List of event types provided by the broker. + example: [ "my-namespace/my-event-type" ] + required: + - namespace + - name + - uid + - labels + - annotations + - providedEventTypes + EventType: + type: object + description: EventType is a simplified representation of a Knative Eventing EventType that is easier to consume by the Backstage plugin. + properties: + namespace: + type: string + description: Namespace of the event type. + format: string + example: my-namespace + name: + type: string + description: Name of the event type. + format: string + example: my-event-type + type: + type: string + description: Type of the event. + format: string + example: something-happened + uid: + type: string + description: UID of the event type. + format: string + example: 1234-5678-9012 + description: + type: string + description: Description of the event type. + format: string + example: This event type is emitted when something happens. + schemaData: + type: string + description: Schema data. + deprecated: true + format: string + example: '{"type":"object","properties":{"field1":{"type":"string"}}}' + schemaURL: + type: string + description: URL to the schema. + format: url + example: https://my-schema.com + labels: + type: object + additionalProperties: + type: string + format: string + description: Labels of the event type. These are passed as is. + example: { "key": "value" } + annotations: + type: object + additionalProperties: + type: string + format: string + description: Annotations of the event type. These are passed as is, except that are filtered out by the `FilterAnnotations` function. + example: { "key": "value" } + reference: + type: string + format: string + description: Reference is the EventTypes's reference to a resource like a broker or a channel. It is in the format `/`. + example: my-namespace/my-broker + consumedBy: + type: array + items: + type: string + format: string + description: ConsumedBy is a `` list of the consumers of the event type. + minItems: 0 + example: [ "my-namespace/my-consumer" ] + required: + - namespace + - name + - type + - uid + - labels + - annotations + - consumedBy + EventMesh: + type: object + description: EventMesh is the top-level struct that holds the event mesh data. It's the struct that's serialized and sent to the Backstage plugin. + properties: + eventTypes: + type: array + items: + $ref: '#/components/schemas/EventType' + description: EventTypes is a list of all event types in the cluster. While we can embed the event types in the brokers, we keep them separate because not every event type is tied to a broker. + minItems: 0 + brokers: + type: array + items: + $ref: '#/components/schemas/Broker' + description: Brokers is a list of all brokers in the cluster. + minItems: 0 + required: + - eventTypes + - brokers