Skip to content

Commit ab7ec16

Browse files
committed
Sources working - finally
Signed-off-by: Ali Ok <aliok@redhat.com>
1 parent ae1d35b commit ab7ec16

File tree

9 files changed

+298
-38
lines changed

9 files changed

+298
-38
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package v1
2+
3+
import "knative.dev/backstage-plugins/backends/pkg/util"
4+
5+
func (gknn GroupKindNamespacedName) String() string {
6+
return util.GKNamespacedName(gknn.Group, gknn.Kind, gknn.Namespace, gknn.Name)
7+
}

backends/pkg/eventmesh/v1/api.gen.go

Lines changed: 24 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backends/pkg/eventmesh/v1/builder.go

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ func BuildEventMesh(ctx context.Context, clientset versioned.Interface, dynamicC
4848
return EventMesh{}, err
4949
}
5050

51+
convertedSourceEntries, err := fetchSources(ctx, dynamicClient, logger)
52+
if err != nil {
53+
logger.Errorw("Error fetching and converting sources", "error", err)
54+
return EventMesh{}, err
55+
}
56+
5157
// build a broker map and a subscribable map for easier access.
5258
// we need this map to register the event types in the brokers when we are processing the event types.
5359
// map key: "<namespace>/<name>"
@@ -73,9 +79,9 @@ func BuildEventMesh(ctx context.Context, clientset versioned.Interface, dynamicC
7379
// register the event types in the brokers and channels
7480
for _, et := range convertedEventTypes {
7581
if et.Reference != nil {
76-
if br, ok := brokerMap[*et.Reference]; ok {
82+
if br, ok := brokerMap[et.Reference.String()]; ok {
7783
br.ProvidedEventTypes = append(br.ProvidedEventTypes, et.NamespacedName())
78-
} else if subscribable, ok := subscribableMap[*et.Reference]; ok {
84+
} else if subscribable, ok := subscribableMap[et.Reference.String()]; ok {
7985
subscribable.ProvidedEventTypes = append(subscribable.ProvidedEventTypes, et.NamespacedName())
8086
} else {
8187
logger.Infow("Event type reference not found", "eventType", et.NamespacedName(), "reference", *et.Reference)
@@ -92,6 +98,29 @@ func BuildEventMesh(ctx context.Context, clientset versioned.Interface, dynamicC
9298
etByNamespacedName[et.NamespacedName()] = et
9399
}
94100

101+
// build a map for easier access to the ETs by their type.
102+
// there can be multiple ETs with the same type but different names.
103+
// we need this map when processing the sources to find out ET definitions for the ET types.
104+
// map key does not have a namespace: "<eventType.type>"
105+
etsByType := make(map[string][]*EventType)
106+
for _, et := range convertedEventTypes {
107+
etsByType[et.Type] = append(etsByType[et.Type], et)
108+
}
109+
110+
// register the event types in the sources
111+
for _, source := range convertedSourceEntries {
112+
if source.ProvidedEventTypeTypes == nil {
113+
continue
114+
}
115+
for _, providedType := range *source.ProvidedEventTypeTypes {
116+
if ets, ok := etsByType[providedType]; ok {
117+
for _, et := range ets {
118+
source.ProvidedEventTypes = append(source.ProvidedEventTypes, et.NamespacedName())
119+
}
120+
}
121+
}
122+
}
123+
95124
// fetch the triggers we will process them later
96125
triggers, err := clientset.EventingV1().Triggers(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{})
97126
if err != nil {
@@ -135,11 +164,16 @@ func BuildEventMesh(ctx context.Context, clientset versioned.Interface, dynamicC
135164
for _, s := range convertedSubscribables {
136165
outputSubscribables = append(outputSubscribables, *s)
137166
}
167+
outputSources := make([]Source, 0, len(convertedSourceEntries))
168+
for _, s := range convertedSourceEntries {
169+
outputSources = append(outputSources, *s)
170+
}
138171

139172
eventMesh := EventMesh{
140173
EventTypes: outputEventTypes,
141174
Brokers: outputBrokers,
142175
Subscribables: outputSubscribables,
176+
Sources: outputSources,
143177
}
144178

145179
return eventMesh, nil
@@ -341,6 +375,58 @@ func fetchSubscribables(ctx context.Context, dynamicClient dynamic.Interface, lo
341375
return subscribables, nil
342376
}
343377

378+
func fetchSources(ctx context.Context, dynamicClient dynamic.Interface, logger *zap.SugaredLogger) ([]*Source, error) {
379+
// first, fetch the source CRDs
380+
sourceCRDs, err := dynamicClient.Resource(
381+
schema.GroupVersionResource{
382+
Group: "apiextensions.k8s.io",
383+
Version: "v1",
384+
Resource: "customresourcedefinitions",
385+
},
386+
).List(ctx, metav1.ListOptions{LabelSelector: labels.Set{"duck.knative.dev/source": "true"}.String()})
387+
388+
if errors.IsNotFound(err) {
389+
return nil, nil
390+
}
391+
392+
if err != nil {
393+
logger.Errorw("Error listing source CRDs", "error", err)
394+
return nil, err
395+
}
396+
397+
// then, fetch the sources
398+
sources := make([]*Source, 0)
399+
for _, crd := range sourceCRDs.Items {
400+
gvr, err := util.GVRFromUnstructured(&crd)
401+
if err != nil {
402+
logger.Errorw("Error getting GVR from CRD", "error", err)
403+
return nil, err
404+
}
405+
406+
sourceResources, err := dynamicClient.Resource(gvr).Namespace(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
407+
408+
if errors.IsNotFound(err) {
409+
continue
410+
}
411+
412+
if err != nil {
413+
logger.Errorw("Error listing source resources", "error", err)
414+
return nil, err
415+
}
416+
417+
for _, resource := range sourceResources.Items {
418+
sourceEntry, err := convertSource(gvr, crd, &resource)
419+
if err != nil {
420+
logger.Errorw("Error converting source", "error", err)
421+
return nil, err
422+
}
423+
sources = append(sources, &sourceEntry)
424+
}
425+
}
426+
427+
return sources, nil
428+
}
429+
344430
// fetchEventTypes fetches the event types and converts them to the representation that's consumed by the Backstage plugin.
345431
func fetchEventTypes(clientset versioned.Interface, logger *zap.SugaredLogger) ([]*EventType, error) {
346432
eventTypeResponse, err := clientset.EventingV1beta2().EventTypes(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{})

backends/pkg/eventmesh/v1/endpoint.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,6 @@ func (e Endpoint) GetEventMesh(ctx context.Context, _ GetEventMeshRequestObject)
6363
Brokers: eventMesh.Brokers,
6464
EventTypes: eventMesh.EventTypes,
6565
Subscribables: eventMesh.Subscribables,
66+
Sources: eventMesh.Sources,
6667
}, nil
6768
}

backends/pkg/eventmesh/v1/eventtype.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ func (et EventType) NamespacedType() string {
1515
return util.NamespacedName(et.Namespace, et.Type)
1616
}
1717

18-
// TODO: remove
1918
// convertEventType converts a Knative Eventing EventType to a simplified representation that is easier to consume by the Backstage plugin.
2019
// see EventType.
2120
func convertEventType(et *v1beta2.EventType) EventType {
22-
reference := ""
21+
var reference *GroupKindNamespacedName
2322
if et.Spec.Reference != nil {
24-
reference = util.GKNamespacedName(util.APIVersionToGroup(et.Spec.Reference.APIVersion), et.Spec.Reference.Kind, et.Namespace, et.Spec.Reference.Name)
23+
reference = &GroupKindNamespacedName{
24+
Group: util.APIVersionToGroup(et.Spec.Reference.APIVersion),
25+
Kind: et.Spec.Reference.Kind,
26+
Namespace: et.Namespace,
27+
Name: et.Spec.Reference.Name,
28+
}
2529
}
2630
return EventType{
2731
Name: et.Name,
@@ -33,7 +37,7 @@ func convertEventType(et *v1beta2.EventType) EventType {
3337
SchemaURL: util.ToStrPtrOrNil(et.Spec.Schema.String()),
3438
Labels: et.Labels,
3539
Annotations: util.FilterAnnotations(et.Annotations),
36-
Reference: util.ToStrPtrOrNil(reference),
40+
Reference: reference,
3741
// this field will be populated later on, when we have process the triggers
3842
ConsumedBy: make([]string, 0),
3943
}

backends/pkg/eventmesh/v1/server.gen.go

Lines changed: 27 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package v1
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
7+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8+
"k8s.io/apimachinery/pkg/runtime/schema"
9+
10+
"knative.dev/eventing/pkg/apis/eventing"
11+
12+
"knative.dev/backstage-plugins/backends/pkg/util"
13+
)
14+
15+
// eventTypeEntry refers to an entry in the registry.knative.dev/eventTypes annotation.
16+
type eventTypeEntry struct {
17+
Type string `json:"type"`
18+
Schema string `json:"schema,omitempty"`
19+
Description string `json:"description,omitempty"`
20+
}
21+
22+
func convertSource(gvr schema.GroupVersionResource, crd unstructured.Unstructured, source *unstructured.Unstructured) (Source, error) {
23+
providedEventTypeTypes := []string{}
24+
25+
crdAnnotations := crd.GetAnnotations()
26+
if eventTypesJson, ok := crdAnnotations[eventing.EventTypesAnnotationKey]; ok {
27+
var providedEventTypeEntries []eventTypeEntry
28+
if err := json.Unmarshal([]byte(eventTypesJson), &providedEventTypeEntries); err != nil {
29+
return Source{}, errors.New("failed to unmarshal event types")
30+
}
31+
32+
providedEventTypeTypes = make([]string, len(providedEventTypeEntries))
33+
for i, entry := range providedEventTypeEntries {
34+
providedEventTypeTypes[i] = entry.Type
35+
}
36+
}
37+
38+
src := Source{
39+
Namespace: source.GetNamespace(),
40+
Name: source.GetName(),
41+
UID: string(source.GetUID()),
42+
Annotations: util.FilterAnnotations(source.GetAnnotations()),
43+
Labels: source.GetLabels(),
44+
ProvidedEventTypeTypes: &providedEventTypeTypes,
45+
// this field will be populated later on
46+
ProvidedEventTypes: []string{},
47+
Group: gvr.Group,
48+
Kind: source.GetKind(),
49+
}
50+
51+
if sinkRef, ok := getSinkRef(source); ok {
52+
src.Sink = &sinkRef
53+
}
54+
55+
return src, nil
56+
}
57+
58+
func getSinkRef(u *unstructured.Unstructured) (GroupKindNamespacedName, bool) {
59+
stringMap, ok, err := unstructured.NestedStringMap(u.Object, "spec", "sink", "ref")
60+
if err != nil {
61+
return GroupKindNamespacedName{}, false
62+
}
63+
64+
if !ok {
65+
return GroupKindNamespacedName{}, false
66+
}
67+
68+
apiVersion, ok := stringMap["apiVersion"]
69+
if !ok {
70+
// if apiVersion is not present (e.g. using a URL as the sink), we don't care/
71+
// same story with others
72+
return GroupKindNamespacedName{}, false
73+
}
74+
kind, ok := stringMap["kind"]
75+
if !ok {
76+
return GroupKindNamespacedName{}, false
77+
}
78+
name, ok := stringMap["name"]
79+
if !ok {
80+
return GroupKindNamespacedName{}, false
81+
}
82+
83+
return GroupKindNamespacedName{
84+
Group: util.APIVersionToGroup(apiVersion),
85+
Kind: kind,
86+
Namespace: u.GetNamespace(),
87+
Name: name,
88+
}, true
89+
}

0 commit comments

Comments
 (0)