diff --git a/pkg/api/factory.go b/pkg/api/factory.go index e280b192..41b71fe9 100644 --- a/pkg/api/factory.go +++ b/pkg/api/factory.go @@ -33,6 +33,7 @@ type Settings struct { type Factory interface { GetAPI() (API, error) GetAPIsFromNamespace(namespace string) (map[string]API, error) + GetAPIsFromFactory(resource interface{}) (map[string]API, error) } type apiFactory struct { @@ -170,6 +171,10 @@ func (f *apiFactory) GetAPIsFromNamespace(namespace string) (map[string]API, err return apis, nil } +func (f *apiFactory) GetAPIsFromFactory(resource interface{}) (map[string]API, error) { + return nil, fmt.Errorf("not implemented") +} + func (f *apiFactory) getApiFromNamespace(namespace string) (API, error) { cm, secret, err := f.getConfigMapAndSecret(namespace) if err != nil { diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index a492526f..878d69f8 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -154,6 +154,18 @@ func NewControllerWithNamespaceSupport( return ctrl } +// NewControllerWithNamespaceSupport For self-service notification getting configuration from apiFactory +func NewControllerWithFactorySupport( + client dynamic.NamespaceableResourceInterface, + informer cache.SharedIndexInformer, + apiFactory api.Factory, + opts ...Opts, +) *notificationController { + ctrl := NewController(client, informer, apiFactory, opts...) + ctrl.factorySupport = true + return ctrl +} + type notificationController struct { client dynamic.NamespaceableResourceInterface informer cache.SharedIndexInformer @@ -165,6 +177,7 @@ type notificationController struct { toUnstructured func(obj v1.Object) (*unstructured.Unstructured, error) eventCallback func(eventSequence NotificationEventSequence) namespaceSupport bool + factorySupport bool } func (c *notificationController) Run(threadiness int, stopCh <-chan struct{}) { @@ -304,15 +317,17 @@ func (c *notificationController) processQueueItem() (processNext bool) { } } - if !c.namespaceSupport { - api, err := c.apiFactory.GetAPI() + if c.factorySupport { + apisWithNamespace, err := c.apiFactory.GetAPIsFromFactory(resource) if err != nil { - logEntry.Errorf("Failed to get api: %v", err) + logEntry.Errorf("Failed to get api with key: %v", err) eventSequence.addError(err) - return } - c.processResource(api, resource, logEntry, &eventSequence) - } else { + for _, api := range apisWithNamespace { + c.processResource(api, resource, logEntry, &eventSequence) + } + + } else if c.namespaceSupport { apisWithNamespace, err := c.apiFactory.GetAPIsFromNamespace(resource.GetNamespace()) if err != nil { logEntry.Errorf("Failed to get api with namespace: %v", err) @@ -321,7 +336,16 @@ func (c *notificationController) processQueueItem() (processNext bool) { for _, api := range apisWithNamespace { c.processResource(api, resource, logEntry, &eventSequence) } + } else { + api, err := c.apiFactory.GetAPI() + if err != nil { + logEntry.Errorf("Failed to get api: %v", err) + eventSequence.addError(err) + return + } + c.processResource(api, resource, logEntry, &eventSequence) } + logEntry.Info("Processing completed") return diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index 2f76a1c8..66ccba15 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -65,7 +65,7 @@ func newResource(name string, modifiers ...func(app *unstructured.Unstructured)) return &app } -func newController(t *testing.T, ctx context.Context, client dynamic.Interface, opts ...Opts) (*notificationController, *mocks.MockAPI, error) { +func newController(t *testing.T, ctx context.Context, client dynamic.Interface, factorySupport bool, opts ...Opts) (*notificationController, *mocks.MockAPI, error) { mockCtrl := gomock.NewController(t) go func() { <-ctx.Done() @@ -90,7 +90,12 @@ func newController(t *testing.T, ctx context.Context, client dynamic.Interface, go informer.Run(ctx.Done()) - c := NewControllerWithNamespaceSupport(resourceClient, informer, &mocks.FakeFactory{Api: mockAPI}, opts...) + var c *notificationController + if factorySupport { + c = NewControllerWithFactorySupport(resourceClient, informer, &mocks.FakeFactory{Api: mockAPI}, opts...) + } else { + c = NewControllerWithNamespaceSupport(resourceClient, informer, &mocks.FakeFactory{Api: mockAPI}, opts...) + } if !cache.WaitForCacheSync(ctx.Done(), informer.HasSynced) { return nil, nil, errors.New("failed to sync informers") } @@ -105,7 +110,7 @@ func TestSendsNotificationIfTriggered(t *testing.T) { subscriptions.SubscribeAnnotationKey("my-trigger", "mock"): "recipient", })) - ctrl, api, err := newController(t, ctx, newFakeClient(app)) + ctrl, api, err := newController(t, ctx, newFakeClient(app), false) assert.NoError(t, err) receivedObj := map[string]interface{}{} @@ -136,7 +141,7 @@ func TestDoesNotSendNotificationIfAnnotationPresent(t *testing.T) { subscriptions.SubscribeAnnotationKey("my-trigger", "mock"): "recipient", notifiedAnnotationKey: mustToJson(state), })) - ctrl, api, err := newController(t, ctx, newFakeClient(app)) + ctrl, api, err := newController(t, ctx, newFakeClient(app), false) assert.NoError(t, err) api.EXPECT().RunTrigger("my-trigger", gomock.Any()).Return([]triggers.ConditionResult{{Triggered: true, Templates: []string{"test"}}}, nil) @@ -158,7 +163,7 @@ func TestRemovesAnnotationIfNoTrigger(t *testing.T) { subscriptions.SubscribeAnnotationKey("my-trigger", "mock"): "recipient", notifiedAnnotationKey: mustToJson(state), })) - ctrl, api, err := newController(t, ctx, newFakeClient(app)) + ctrl, api, err := newController(t, ctx, newFakeClient(app), false) assert.NoError(t, err) api.EXPECT().RunTrigger("my-trigger", gomock.Any()).Return([]triggers.ConditionResult{{Triggered: false}}, nil) @@ -173,6 +178,14 @@ func TestRemovesAnnotationIfNoTrigger(t *testing.T) { } func TestUpdatedAnnotationsSavedAsPatch(t *testing.T) { + controllerRunAndVerifyResult(t, false) +} + +func TestSendsNotificationUsingAPIFromFactory(t *testing.T) { + controllerRunAndVerifyResult(t, true) +} + +func controllerRunAndVerifyResult(t *testing.T, factorySupport bool) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() @@ -191,7 +204,7 @@ func TestUpdatedAnnotationsSavedAsPatch(t *testing.T) { patchCh <- action.(kubetesting.PatchAction).GetPatch() return true, nil, nil }) - ctrl, api, err := newController(t, ctx, client) + ctrl, api, err := newController(t, ctx, client, factorySupport) assert.NoError(t, err) api.EXPECT().RunTrigger("my-trigger", gomock.Any()).Return([]triggers.ConditionResult{{Triggered: false}}, nil) @@ -322,7 +335,7 @@ func TestWithEventCallback(t *testing.T) { subscriptions.SubscribeAnnotationKey("my-trigger", "mock"): "recipient", })) - ctrl, api, err := newController(t, ctx, newFakeClient(app), WithEventCallback(mockEventCallback)) + ctrl, api, err := newController(t, ctx, newFakeClient(app), false, WithEventCallback(mockEventCallback)) ctrl.namespaceSupport = false assert.NoError(t, err) ctrl.apiFactory = &mocks.FakeFactory{Api: api, Err: tc.apiErr} diff --git a/pkg/mocks/factory.go b/pkg/mocks/factory.go index 7ebbb5a1..4064e418 100644 --- a/pkg/mocks/factory.go +++ b/pkg/mocks/factory.go @@ -16,3 +16,9 @@ func (f *FakeFactory) GetAPIsFromNamespace(namespace string) (map[string]api.API apiMap[namespace] = f.Api return apiMap, f.Err } + +func (f *FakeFactory) GetAPIsFromFactory(resource interface{}) (map[string]api.API, error) { + apiMap := make(map[string]api.API) + apiMap["key1"] = f.Api + return apiMap, f.Err +}