diff --git a/docs/content/en/docs/crd-ref/options/v1alpha1/_index.md b/docs/content/en/docs/crd-ref/options/v1alpha1/_index.md index d3d3bf9661..3f0f7cc6c9 100644 --- a/docs/content/en/docs/crd-ref/options/v1alpha1/_index.md +++ b/docs/content/en/docs/crd-ref/options/v1alpha1/_index.md @@ -65,5 +65,6 @@ _Appears in:_ | --- | --- | | `OTelCollectorUrl` _string_ | OTelCollectorUrl can be used to set the Open Telemetry collector that the lifecycle operator should use | | `keptnAppCreationRequestTimeoutSeconds` _integer_ | KeptnAppCreationRequestTimeoutSeconds is used to set the interval in which automatic app discovery searches for workload to put into the same auto-generated KeptnApp | +| `cloudEventsEndpoint` _string_ | CloudEventsEndpoint can be used to set the endpoint where Cloud Events should be posted by the lifecycle operator | diff --git a/helm/chart/templates/keptnconfig-crd.yaml b/helm/chart/templates/keptnconfig-crd.yaml index cbf508d36e..b3658aacb1 100644 --- a/helm/chart/templates/keptnconfig-crd.yaml +++ b/helm/chart/templates/keptnconfig-crd.yaml @@ -42,6 +42,10 @@ spec: description: OTelCollectorUrl can be used to set the Open Telemetry collector that the lifecycle operator should use type: string + cloudEventsEndpoint: + description: CloudEventsEndpoint can be used to set the endpoint where + Cloud Events should be posted by the lifecycle operator + type: string keptnAppCreationRequestTimeoutSeconds: default: 30 description: KeptnAppCreationRequestTimeoutSeconds is used to set the diff --git a/lifecycle-operator/apis/options/v1alpha1/keptnconfig_types.go b/lifecycle-operator/apis/options/v1alpha1/keptnconfig_types.go index 50d72d5eae..4428c70cfe 100644 --- a/lifecycle-operator/apis/options/v1alpha1/keptnconfig_types.go +++ b/lifecycle-operator/apis/options/v1alpha1/keptnconfig_types.go @@ -31,11 +31,16 @@ type KeptnConfigSpec struct { // OTelCollectorUrl can be used to set the Open Telemetry collector that the lifecycle operator should use // +optional OTelCollectorUrl string `json:"OTelCollectorUrl,omitempty"` + // KeptnAppCreationRequestTimeoutSeconds is used to set the interval in which automatic app discovery // searches for workload to put into the same auto-generated KeptnApp // +kubebuilder:default:=30 // +optional KeptnAppCreationRequestTimeoutSeconds uint `json:"keptnAppCreationRequestTimeoutSeconds,omitempty"` + + // CloudEventsEndpoint can be used to set the endpoint where Cloud Events should be posted by the lifecycle operator + // +optional + CloudEventsEndpoint string `json:"cloudEventsEndpoint,omitempty"` } // +kubebuilder:object:root=true diff --git a/lifecycle-operator/config/crd/bases/options.keptn.sh_keptnconfigs.yaml b/lifecycle-operator/config/crd/bases/options.keptn.sh_keptnconfigs.yaml index c1a66a3c79..778e639bcb 100644 --- a/lifecycle-operator/config/crd/bases/options.keptn.sh_keptnconfigs.yaml +++ b/lifecycle-operator/config/crd/bases/options.keptn.sh_keptnconfigs.yaml @@ -38,6 +38,10 @@ spec: description: OTelCollectorUrl can be used to set the Open Telemetry collector that the lifecycle operator should use type: string + cloudEventsEndpoint: + description: CloudEventsEndpoint can be used to set the endpoint where + Cloud Events should be posted by the lifecycle operator + type: string keptnAppCreationRequestTimeoutSeconds: default: 30 description: KeptnAppCreationRequestTimeoutSeconds is used to set diff --git a/lifecycle-operator/controllers/common/config/config.go b/lifecycle-operator/controllers/common/config/config.go index c2df8f2b85..043edb4348 100644 --- a/lifecycle-operator/controllers/common/config/config.go +++ b/lifecycle-operator/controllers/common/config/config.go @@ -11,10 +11,13 @@ const defaultKeptnAppCreationRequestTimeout = 30 * time.Second type IConfig interface { SetCreationRequestTimeout(value time.Duration) GetCreationRequestTimeout() time.Duration + SetCloudEventsEndpoint(endpoint string) + GetCloudEventsEndpoint() string } type ControllerConfig struct { keptnAppCreationRequestTimeout time.Duration + cloudEventsEndpoint string } var instance *ControllerConfig @@ -34,3 +37,11 @@ func (o *ControllerConfig) SetCreationRequestTimeout(value time.Duration) { func (o *ControllerConfig) GetCreationRequestTimeout() time.Duration { return o.keptnAppCreationRequestTimeout } + +func (o *ControllerConfig) SetCloudEventsEndpoint(endpoint string) { + o.cloudEventsEndpoint = endpoint +} + +func (o *ControllerConfig) GetCloudEventsEndpoint() string { + return o.cloudEventsEndpoint +} diff --git a/lifecycle-operator/controllers/common/config/fake/config_mock.go b/lifecycle-operator/controllers/common/config/fake/config_mock.go index 1d6034c832..0bbe4fc009 100644 --- a/lifecycle-operator/controllers/common/config/fake/config_mock.go +++ b/lifecycle-operator/controllers/common/config/fake/config_mock.go @@ -14,9 +14,15 @@ import ( // // // make and configure a mocked config.IConfig // mockedIConfig := &MockConfig{ +// GetCloudEventsEndpointFunc: func() string { +// panic("mock out the GetCloudEventsEndpoint method") +// }, // GetCreationRequestTimeoutFunc: func() time.Duration { // panic("mock out the GetCreationRequestTimeout method") // }, +// SetCloudEventsEndpointFunc: func(endpoint string) { +// panic("mock out the SetCloudEventsEndpoint method") +// }, // SetCreationRequestTimeoutFunc: func(value time.Duration) { // panic("mock out the SetCreationRequestTimeout method") // }, @@ -27,27 +33,70 @@ import ( // // } type MockConfig struct { + // GetCloudEventsEndpointFunc mocks the GetCloudEventsEndpoint method. + GetCloudEventsEndpointFunc func() string + // GetCreationRequestTimeoutFunc mocks the GetCreationRequestTimeout method. GetCreationRequestTimeoutFunc func() time.Duration + // SetCloudEventsEndpointFunc mocks the SetCloudEventsEndpoint method. + SetCloudEventsEndpointFunc func(endpoint string) + // SetCreationRequestTimeoutFunc mocks the SetCreationRequestTimeout method. SetCreationRequestTimeoutFunc func(value time.Duration) // calls tracks calls to the methods. calls struct { + // GetCloudEventsEndpoint holds details about calls to the GetCloudEventsEndpoint method. + GetCloudEventsEndpoint []struct { + } // GetCreationRequestTimeout holds details about calls to the GetCreationRequestTimeout method. GetCreationRequestTimeout []struct { } + // SetCloudEventsEndpoint holds details about calls to the SetCloudEventsEndpoint method. + SetCloudEventsEndpoint []struct { + // Endpoint is the endpoint argument value. + Endpoint string + } // SetCreationRequestTimeout holds details about calls to the SetCreationRequestTimeout method. SetCreationRequestTimeout []struct { // Value is the value argument value. Value time.Duration } } + lockGetCloudEventsEndpoint sync.RWMutex lockGetCreationRequestTimeout sync.RWMutex + lockSetCloudEventsEndpoint sync.RWMutex lockSetCreationRequestTimeout sync.RWMutex } +// GetCloudEventsEndpoint calls GetCloudEventsEndpointFunc. +func (mock *MockConfig) GetCloudEventsEndpoint() string { + if mock.GetCloudEventsEndpointFunc == nil { + panic("MockConfig.GetCloudEventsEndpointFunc: method is nil but IConfig.GetCloudEventsEndpoint was just called") + } + callInfo := struct { + }{} + mock.lockGetCloudEventsEndpoint.Lock() + mock.calls.GetCloudEventsEndpoint = append(mock.calls.GetCloudEventsEndpoint, callInfo) + mock.lockGetCloudEventsEndpoint.Unlock() + return mock.GetCloudEventsEndpointFunc() +} + +// GetCloudEventsEndpointCalls gets all the calls that were made to GetCloudEventsEndpoint. +// Check the length with: +// +// len(mockedIConfig.GetCloudEventsEndpointCalls()) +func (mock *MockConfig) GetCloudEventsEndpointCalls() []struct { +} { + var calls []struct { + } + mock.lockGetCloudEventsEndpoint.RLock() + calls = mock.calls.GetCloudEventsEndpoint + mock.lockGetCloudEventsEndpoint.RUnlock() + return calls +} + // GetCreationRequestTimeout calls GetCreationRequestTimeoutFunc. func (mock *MockConfig) GetCreationRequestTimeout() time.Duration { if mock.GetCreationRequestTimeoutFunc == nil { @@ -75,6 +124,38 @@ func (mock *MockConfig) GetCreationRequestTimeoutCalls() []struct { return calls } +// SetCloudEventsEndpoint calls SetCloudEventsEndpointFunc. +func (mock *MockConfig) SetCloudEventsEndpoint(endpoint string) { + if mock.SetCloudEventsEndpointFunc == nil { + panic("MockConfig.SetCloudEventsEndpointFunc: method is nil but IConfig.SetCloudEventsEndpoint was just called") + } + callInfo := struct { + Endpoint string + }{ + Endpoint: endpoint, + } + mock.lockSetCloudEventsEndpoint.Lock() + mock.calls.SetCloudEventsEndpoint = append(mock.calls.SetCloudEventsEndpoint, callInfo) + mock.lockSetCloudEventsEndpoint.Unlock() + mock.SetCloudEventsEndpointFunc(endpoint) +} + +// SetCloudEventsEndpointCalls gets all the calls that were made to SetCloudEventsEndpoint. +// Check the length with: +// +// len(mockedIConfig.SetCloudEventsEndpointCalls()) +func (mock *MockConfig) SetCloudEventsEndpointCalls() []struct { + Endpoint string +} { + var calls []struct { + Endpoint string + } + mock.lockSetCloudEventsEndpoint.RLock() + calls = mock.calls.SetCloudEventsEndpoint + mock.lockSetCloudEventsEndpoint.RUnlock() + return calls +} + // SetCreationRequestTimeout calls SetCreationRequestTimeoutFunc. func (mock *MockConfig) SetCreationRequestTimeout(value time.Duration) { if mock.SetCreationRequestTimeoutFunc == nil { diff --git a/lifecycle-operator/controllers/common/evaluationhandler_test.go b/lifecycle-operator/controllers/common/evaluationhandler_test.go index 74242b0af5..f47b33809f 100644 --- a/lifecycle-operator/controllers/common/evaluationhandler_test.go +++ b/lifecycle-operator/controllers/common/evaluationhandler_test.go @@ -268,7 +268,7 @@ func TestEvaluationHandler(t *testing.T) { handler := EvaluationHandler{ SpanHandler: &spanHandlerMock, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(fakeRecorder), + EventSender: NewK8sSender(fakeRecorder), Client: fake.NewClientBuilder().WithObjects(&tt.evalObj).Build(), Tracer: trace.NewNoopTracerProvider().Tracer("tracer"), Scheme: scheme.Scheme, @@ -349,7 +349,7 @@ func TestEvaluationHandler_createEvaluation(t *testing.T) { handler := EvaluationHandler{ SpanHandler: &kltfake.ISpanHandlerMock{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().Build(), Tracer: trace.NewNoopTracerProvider().Tracer("tracer"), Scheme: scheme.Scheme, diff --git a/lifecycle-operator/controllers/common/eventsender.go b/lifecycle-operator/controllers/common/eventsender.go index b9fa76b5f5..969a0ff334 100644 --- a/lifecycle-operator/controllers/common/eventsender.go +++ b/lifecycle-operator/controllers/common/eventsender.go @@ -1,9 +1,14 @@ package common import ( + "context" "fmt" + "strings" + ce "github.com/cloudevents/sdk-go/v2" + "github.com/go-logr/logr" apicommon "github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1alpha3/common" + "github.com/keptn/lifecycle-toolkit/lifecycle-operator/controllers/common/config" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -15,12 +20,84 @@ type IEvent interface { // ===== Main ===== -func NewEventSender(recorder record.EventRecorder) IEvent { - return newK8sSender(recorder) +type EventMultiplexer struct { + logger logr.Logger + emitters []IEvent +} + +func NewEventMultiplexer(logger logr.Logger, recorder record.EventRecorder, client ce.Client) *EventMultiplexer { + multiplexer := &EventMultiplexer{ + logger: logger, + } + multiplexer.register(newCloudEventSender(logger, client)) + multiplexer.register(NewK8sSender(recorder)) + return multiplexer +} + +func (e *EventMultiplexer) register(emitter IEvent) { + if emitter != nil { + e.emitters = append(e.emitters, emitter) + } +} + +func (e *EventMultiplexer) Emit(phase apicommon.KeptnPhaseType, eventType string, reconcileObject client.Object, status string, message string, version string) { + for _, emitter := range e.emitters { + e.logger.Info(fmt.Sprintf("Emitting event using %T", emitter)) + go emitter.Emit(phase, eventType, reconcileObject, status, message, version) + } } // ===== Cloud Event Sender ===== -// TODO: implement Cloud Event logic + +type cloudEvent struct { + client ce.Client + logger logr.Logger +} + +func newCloudEventSender(logger logr.Logger, client ce.Client) *cloudEvent { + return &cloudEvent{ + client: client, + logger: logger, + } +} + +// Emit creates a Cloud Event and send it to the endpoint +func (e *cloudEvent) Emit(phase apicommon.KeptnPhaseType, eventType string, reconcileObject client.Object, status string, message string, version string) { + endpoint := config.Instance().GetCloudEventsEndpoint() + if endpoint == "" { + // if no endpoint is configured we don't emit any event + if !strings.HasPrefix(endpoint, "http") { + e.logger.V(5).Info(fmt.Sprintf("CloudEvent endpoint configured but it does not start with http: %s", endpoint)) + } + return + } + event := ce.NewEvent() + event.SetSource("keptn.sh") + event.SetType(fmt.Sprintf("%s.%s", phase.LongName, status)) + + msg := setEventMessage(phase, reconcileObject, message, version) + err := event.SetData(ce.ApplicationJSON, map[string]interface{}{ + "message": msg, + "type": eventType, + "version": version, + "resource": map[string]string{ + "group": reconcileObject.GetObjectKind().GroupVersionKind().Group, + "kind": reconcileObject.GetObjectKind().GroupVersionKind().Kind, + "version": reconcileObject.GetObjectKind().GroupVersionKind().Version, + "name": reconcileObject.GetName(), + "namespace": reconcileObject.GetNamespace(), + }, + }) + if err != nil { + e.logger.V(5).Info(fmt.Sprintf("Failed to set data for CloudEvent: %v", err)) + return + } + + ctx := ce.ContextWithTarget(context.TODO(), endpoint) + if result := e.client.Send(ctx, event); ce.IsUndelivered(result) { + e.logger.V(5).Info(fmt.Sprintf("Failed to send CloudEvent: %v", event)) + } +} // ===== K8s Event Sender ===== @@ -28,15 +105,15 @@ type k8sEvent struct { recorder record.EventRecorder } -func newK8sSender(recorder record.EventRecorder) IEvent { +func NewK8sSender(recorder record.EventRecorder) IEvent { return &k8sEvent{ recorder: recorder, } } -// SendEvent creates k8s Event and adds it to Eventqueue -func (s *k8sEvent) Emit(phase apicommon.KeptnPhaseType, eventType string, reconcileObject client.Object, status string, message string, version string) { +// Emit creates k8s Event and adds it to Eventqueue +func (e *k8sEvent) Emit(phase apicommon.KeptnPhaseType, eventType string, reconcileObject client.Object, status string, message string, version string) { msg := setEventMessage(phase, reconcileObject, message, version) annotations := setAnnotations(reconcileObject, phase) - s.recorder.AnnotatedEventf(reconcileObject, annotations, eventType, fmt.Sprintf("%s%s", phase.ShortName, status), msg) + e.recorder.AnnotatedEventf(reconcileObject, annotations, eventType, fmt.Sprintf("%s%s", phase.ShortName, status), msg) } diff --git a/lifecycle-operator/controllers/common/eventsender_test.go b/lifecycle-operator/controllers/common/eventsender_test.go index 2b8285ea29..a8a004bf3b 100644 --- a/lifecycle-operator/controllers/common/eventsender_test.go +++ b/lifecycle-operator/controllers/common/eventsender_test.go @@ -2,18 +2,28 @@ package common import ( "fmt" + "io" + "log" + "net/http" + "net/http/httptest" "testing" + "time" + ce "github.com/cloudevents/sdk-go/v2" "github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1alpha3" "github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1alpha3/common" + "github.com/keptn/lifecycle-toolkit/lifecycle-operator/controllers/common/config" "github.com/stretchr/testify/require" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log/zap" ) func TestEventSender_SendK8sEvent(t *testing.T) { fakeRecorder := record.NewFakeRecorder(100) - eventSender := newK8sSender(fakeRecorder) + eventSender := NewK8sSender(fakeRecorder) eventSender.Emit(common.PhaseAppDeployment, "pre-event", &v1alpha3.KeptnAppVersion{ ObjectMeta: v1.ObjectMeta{ @@ -26,3 +36,160 @@ func TestEventSender_SendK8sEvent(t *testing.T) { require.Contains(t, event, fmt.Sprintf("%s: reason-long / Namespace: ns, Name: app, Version: ver1", common.PhaseAppDeployment.LongName)) } + +func TestEventSender_SendCloudEvent(t *testing.T) { + //config + name := "app" + ns := "my-ns" + status := "my-status" + eventType := "my-type" + version := "v0.0.1-dev" + msg := "my message" + phase := common.PhaseAppDeployment + waitToReceive := make(chan bool, 1) + // when + // we have a CloudEvent endpoint + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "POST", r.Method) + require.Equal(t, "/", r.URL.Path) + require.Equal(t, 1, len(r.Header["Ce-Id"])) + require.Equal(t, 1, len(r.Header["Ce-Time"])) + require.Equal(t, 1, len(r.Header["Ce-Type"])) + data, err := io.ReadAll(r.Body) + require.Nil(t, err) + expected := fmt.Sprintf("{\"message\":\"%s: %s / Namespace: %s, Name: %s, Version: %s\",\"resource\":{\"group\":\"\",\"kind\":\"\",\"name\":\"%s\",\"namespace\":\"%s\",\"version\":\"\"},\"type\":\"%s\",\"version\":\"%s\"}", + phase.LongName, msg, ns, name, version, name, ns, eventType, version) + require.Equal(t, expected, string(data)) + + w.WriteHeader(http.StatusOK) + _, err = w.Write([]byte("")) + require.Nil(t, err) + waitToReceive <- true + })) + defer svr.Close() + config.Instance().SetCloudEventsEndpoint(svr.URL) + + // then + // we send a Cloud Event + c, err := ce.NewClientHTTP() + if err != nil { + log.Fatalf("failed to create client, %v", err) + } + ceSender := newCloudEventSender(ctrl.Log.WithName("testytest"), c) + ceSender.Emit(phase, eventType, &v1alpha3.KeptnAppVersion{ + ObjectMeta: v1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + }, status, msg, version) + + select { + case <-waitToReceive: + // we sent a Cloud Event + return + case <-time.After(5 * time.Second): + t.Error("Didn't receive the cloud event") + } +} + +func TestEventSender_CloudEventNoFailure(t *testing.T) { + + tests := []struct { + name string + input string + }{ + { + name: "no endpoint", + input: "", + }, + { + name: "invalid endpoint", + input: "ftp://localhost:9080/", + }, + { + name: "not existing endpoint", + input: "http://127.0.0", + }, + } + + for _, tt := range tests { + // when + // we don't have a CloudEvent endpoint + config.Instance().SetCloudEventsEndpoint(tt.input) + + // then + // we send a Cloud Event + c, err := ce.NewClientHTTP() + if err != nil { + log.Fatalf("failed to create client, %v", err) + } + ceSender := newCloudEventSender(ctrl.Log.WithName("testytest"), c) + ceSender.Emit(common.PhaseAppCompleted, "type", &v1alpha3.KeptnAppVersion{ + ObjectMeta: v1.ObjectMeta{ + Name: "app", + Namespace: "ns", + }, + }, "status", tt.name, "version") + // we don't fail + } +} + +type EventEmitterTest struct { + events []string +} + +func (e *EventEmitterTest) Emit(_ common.KeptnPhaseType, _ string, _ client.Object, _ string, message string, _ string) { + e.events = append(e.events, message) +} + +func TestEventSender_Multiplexer_register(t *testing.T) { + tests := []struct { + input IEvent + expect int + }{ + { + input: &EventEmitterTest{}, + expect: 1, + }, + { + input: nil, + expect: 0, + }, + } + for _, tt := range tests { + em := EventMultiplexer{} + em.register(tt.input) + require.Equal(t, tt.expect, len(em.emitters)) + } +} + +func TestEventSender_Multiplexer_new(t *testing.T) { + // when + // init the object + em := NewEventMultiplexer(zap.New(), nil, nil) + // then assert + // k8s and ce are registered + require.Equal(t, 2, len(em.emitters)) +} + +func TestEventSender_Multiplexer_emit(t *testing.T) { + // when + // init the object with two emitter + em1 := &EventEmitterTest{} + em2 := &EventEmitterTest{} + emitter := EventMultiplexer{} + emitter.register(em1) + emitter.register(em2) + // then + // fire a new event + msg := "my special message" + emitter.Emit(common.PhaseAppDeployment, "", nil, "", msg, "") + // assert we got one event + // let's wait few seconds so the async emit takes place + <-time.After(3 * time.Second) + require.Equal(t, 2, len(emitter.emitters)) + require.Equal(t, 1, len(em1.events)) + require.Equal(t, 1, len(em2.events)) + require.Equal(t, msg, em1.events[0]) + require.Equal(t, msg, em2.events[0]) +} diff --git a/lifecycle-operator/controllers/common/fake/event_mock.go b/lifecycle-operator/controllers/common/fake/event_mock.go new file mode 100644 index 0000000000..b79fa9aaca --- /dev/null +++ b/lifecycle-operator/controllers/common/fake/event_mock.go @@ -0,0 +1,102 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package fake + +import ( + apicommon "github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1alpha3/common" + "sigs.k8s.io/controller-runtime/pkg/client" + "sync" +) + +// MockEvent is a mock implementation of common.IEvent. +// +// func TestSomethingThatUsesIEvent(t *testing.T) { +// +// // make and configure a mocked common.IEvent +// mockedIEvent := &MockEvent{ +// EmitFunc: func(phase apicommon.KeptnPhaseType, eventType string, reconcileObject client.Object, status string, message string, version string) { +// panic("mock out the Emit method") +// }, +// } +// +// // use mockedIEvent in code that requires common.IEvent +// // and then make assertions. +// +// } +type MockEvent struct { + // EmitFunc mocks the Emit method. + EmitFunc func(phase apicommon.KeptnPhaseType, eventType string, reconcileObject client.Object, status string, message string, version string) + + // calls tracks calls to the methods. + calls struct { + // Emit holds details about calls to the Emit method. + Emit []struct { + // Phase is the phase argument value. + Phase apicommon.KeptnPhaseType + // EventType is the eventType argument value. + EventType string + // ReconcileObject is the reconcileObject argument value. + ReconcileObject client.Object + // Status is the status argument value. + Status string + // Message is the message argument value. + Message string + // Version is the version argument value. + Version string + } + } + lockEmit sync.RWMutex +} + +// Emit calls EmitFunc. +func (mock *MockEvent) Emit(phase apicommon.KeptnPhaseType, eventType string, reconcileObject client.Object, status string, message string, version string) { + if mock.EmitFunc == nil { + panic("MockEvent.EmitFunc: method is nil but IEvent.Emit was just called") + } + callInfo := struct { + Phase apicommon.KeptnPhaseType + EventType string + ReconcileObject client.Object + Status string + Message string + Version string + }{ + Phase: phase, + EventType: eventType, + ReconcileObject: reconcileObject, + Status: status, + Message: message, + Version: version, + } + mock.lockEmit.Lock() + mock.calls.Emit = append(mock.calls.Emit, callInfo) + mock.lockEmit.Unlock() + mock.EmitFunc(phase, eventType, reconcileObject, status, message, version) +} + +// EmitCalls gets all the calls that were made to Emit. +// Check the length with: +// +// len(mockedIEvent.EmitCalls()) +func (mock *MockEvent) EmitCalls() []struct { + Phase apicommon.KeptnPhaseType + EventType string + ReconcileObject client.Object + Status string + Message string + Version string +} { + var calls []struct { + Phase apicommon.KeptnPhaseType + EventType string + ReconcileObject client.Object + Status string + Message string + Version string + } + mock.lockEmit.RLock() + calls = mock.calls.Emit + mock.lockEmit.RUnlock() + return calls +} diff --git a/lifecycle-operator/controllers/common/phasehandler_test.go b/lifecycle-operator/controllers/common/phasehandler_test.go index 09a73d0ba6..afcc5cdc51 100644 --- a/lifecycle-operator/controllers/common/phasehandler_test.go +++ b/lifecycle-operator/controllers/common/phasehandler_test.go @@ -54,7 +54,7 @@ func TestPhaseHandler(t *testing.T) { handler: PhaseHandler{ SpanHandler: &telemetry.SpanHandler{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().WithScheme(scheme.Scheme).Build(), }, object: &v1alpha3.KeptnAppVersion{ @@ -81,7 +81,7 @@ func TestPhaseHandler(t *testing.T) { handler: PhaseHandler{ SpanHandler: &telemetry.SpanHandler{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().WithScheme(scheme.Scheme).Build(), }, object: &v1alpha3.KeptnAppVersion{ @@ -108,7 +108,7 @@ func TestPhaseHandler(t *testing.T) { handler: PhaseHandler{ SpanHandler: &telemetry.SpanHandler{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().WithScheme(scheme.Scheme).Build(), }, object: &v1alpha3.KeptnAppVersion{ @@ -135,7 +135,7 @@ func TestPhaseHandler(t *testing.T) { handler: PhaseHandler{ SpanHandler: &telemetry.SpanHandler{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().WithScheme(scheme.Scheme).Build(), }, object: &v1alpha3.KeptnAppVersion{ @@ -162,7 +162,7 @@ func TestPhaseHandler(t *testing.T) { handler: PhaseHandler{ SpanHandler: &telemetry.SpanHandler{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().WithScheme(scheme.Scheme).Build(), }, object: &v1alpha3.KeptnAppVersion{ @@ -190,7 +190,7 @@ func TestPhaseHandler(t *testing.T) { handler: PhaseHandler{ SpanHandler: &telemetry.SpanHandler{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().WithScheme(scheme.Scheme).Build(), }, object: &v1alpha3.KeptnAppVersion{ diff --git a/lifecycle-operator/controllers/common/taskhandler_test.go b/lifecycle-operator/controllers/common/taskhandler_test.go index 37dad2bf52..f71a76ca62 100644 --- a/lifecycle-operator/controllers/common/taskhandler_test.go +++ b/lifecycle-operator/controllers/common/taskhandler_test.go @@ -373,7 +373,7 @@ func TestTaskHandler(t *testing.T) { handler := TaskHandler{ SpanHandler: &spanHandlerMock, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().WithObjects(initObjs...).Build(), Tracer: trace.NewNoopTracerProvider().Tracer("tracer"), Scheme: scheme.Scheme, @@ -444,7 +444,7 @@ func TestTaskHandler_createTask(t *testing.T) { handler := TaskHandler{ SpanHandler: &kltfake.ISpanHandlerMock{}, Log: ctrl.Log.WithName("controller"), - EventSender: NewEventSender(record.NewFakeRecorder(100)), + EventSender: NewK8sSender(record.NewFakeRecorder(100)), Client: fake.NewClientBuilder().Build(), Tracer: trace.NewNoopTracerProvider().Tracer("tracer"), Scheme: scheme.Scheme, diff --git a/lifecycle-operator/controllers/lifecycle/keptnapp/controller_test.go b/lifecycle-operator/controllers/lifecycle/keptnapp/controller_test.go index 36bec91f73..908c787cbc 100644 --- a/lifecycle-operator/controllers/lifecycle/keptnapp/controller_test.go +++ b/lifecycle-operator/controllers/lifecycle/keptnapp/controller_test.go @@ -211,7 +211,7 @@ func setupReconciler() (*KeptnAppReconciler, chan string, *fake.ITracerMock) { r := &KeptnAppReconciler{ Client: fakeClient, Scheme: scheme.Scheme, - EventSender: controllercommon.NewEventSender(recorder), + EventSender: controllercommon.NewK8sSender(recorder), Log: ctrl.Log.WithName("test-appController"), TracerFactory: tf, } diff --git a/lifecycle-operator/controllers/lifecycle/keptnappversion/controller_test.go b/lifecycle-operator/controllers/lifecycle/keptnappversion/controller_test.go index 3abaa0d795..27424edbb1 100644 --- a/lifecycle-operator/controllers/lifecycle/keptnappversion/controller_test.go +++ b/lifecycle-operator/controllers/lifecycle/keptnappversion/controller_test.go @@ -308,7 +308,7 @@ func setupReconciler(objs ...client.Object) (*KeptnAppVersionReconciler, chan st r := &KeptnAppVersionReconciler{ Client: fakeClient, Scheme: scheme.Scheme, - EventSender: controllercommon.NewEventSender(recorder), + EventSender: controllercommon.NewK8sSender(recorder), Log: ctrl.Log.WithName("test-appVersionController"), TracerFactory: tf, SpanHandler: spanRecorder, diff --git a/lifecycle-operator/controllers/lifecycle/keptnevaluation/controller_test.go b/lifecycle-operator/controllers/lifecycle/keptnevaluation/controller_test.go index c17e6c0482..582addeb02 100644 --- a/lifecycle-operator/controllers/lifecycle/keptnevaluation/controller_test.go +++ b/lifecycle-operator/controllers/lifecycle/keptnevaluation/controller_test.go @@ -260,7 +260,7 @@ func setupReconcilerAndClient(t *testing.T, objects ...client.Object) (*KeptnEva Client: fakeClient, Scheme: fakeClient.Scheme(), Log: logr.Logger{}, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Meters: telemetry.SetUpKeptnTaskMeters(meter), TracerFactory: tf, } diff --git a/lifecycle-operator/controllers/lifecycle/keptntask/job_utils_test.go b/lifecycle-operator/controllers/lifecycle/keptntask/job_utils_test.go index 6a0cf2eb1c..b7929137ad 100644 --- a/lifecycle-operator/controllers/lifecycle/keptntask/job_utils_test.go +++ b/lifecycle-operator/controllers/lifecycle/keptntask/job_utils_test.go @@ -41,7 +41,7 @@ func TestKeptnTaskReconciler_createJob(t *testing.T) { r := &KeptnTaskReconciler{ Client: fakeClient, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: ctrl.Log.WithName("task-controller"), Scheme: fakeClient.Scheme(), } @@ -113,7 +113,7 @@ func TestKeptnTaskReconciler_createJob_withTaskDefInDefaultNamespace(t *testing. r := &KeptnTaskReconciler{ Client: fakeClient, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: ctrl.Log.WithName("task-controller"), Scheme: fakeClient.Scheme(), } @@ -184,7 +184,7 @@ func TestKeptnTaskReconciler_updateTaskStatus(t *testing.T) { r := &KeptnTaskReconciler{ Client: fakeClient, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: ctrl.Log.WithName("task-controller"), Scheme: fakeClient.Scheme(), } diff --git a/lifecycle-operator/controllers/lifecycle/keptntask/runtime_builder_test.go b/lifecycle-operator/controllers/lifecycle/keptntask/runtime_builder_test.go index fe6729853f..3a07d6834a 100644 --- a/lifecycle-operator/controllers/lifecycle/keptntask/runtime_builder_test.go +++ b/lifecycle-operator/controllers/lifecycle/keptntask/runtime_builder_test.go @@ -60,7 +60,7 @@ func TestJSBuilder_handleParent(t *testing.T) { name: "no definition", options: BuilderOptions{ Client: fake.NewClient(), - eventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + eventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), req: ctrl.Request{ NamespacedName: types.NamespacedName{Namespace: "default"}, }, @@ -76,7 +76,7 @@ func TestJSBuilder_handleParent(t *testing.T) { name: "definition exists, recursive", options: BuilderOptions{ Client: fake.NewClient(def), - eventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + eventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), req: ctrl.Request{ NamespacedName: types.NamespacedName{Namespace: "default"}, }, @@ -91,7 +91,7 @@ func TestJSBuilder_handleParent(t *testing.T) { name: "definition exists, with parameters and secrets", options: BuilderOptions{ Client: fake.NewClient(paramDef, def), - eventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + eventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), req: ctrl.Request{ NamespacedName: types.NamespacedName{Namespace: "default"}, }, @@ -207,7 +207,7 @@ func TestJSBuilder_getParams(t *testing.T) { name: "definition exists, no parent", options: BuilderOptions{ Client: fake.NewClient(def), - eventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + eventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), req: ctrl.Request{ NamespacedName: types.NamespacedName{Namespace: "default"}, }, @@ -238,7 +238,7 @@ func TestJSBuilder_getParams(t *testing.T) { name: "definition exists, parent with parameters and secrets", options: BuilderOptions{ Client: fake.NewClient(paramDef, def), - eventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + eventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), req: ctrl.Request{ NamespacedName: types.NamespacedName{Namespace: "default"}, }, @@ -270,7 +270,7 @@ func TestJSBuilder_getParams(t *testing.T) { name: "definition exists, parent is of a different runtime", options: BuilderOptions{ Client: fake.NewClient(parentPy, defJS), - eventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + eventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), req: ctrl.Request{ NamespacedName: types.NamespacedName{Namespace: "default"}, }, diff --git a/lifecycle-operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go b/lifecycle-operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go index d5f10c2a86..b55387fe19 100644 --- a/lifecycle-operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go +++ b/lifecycle-operator/controllers/lifecycle/keptnworkloadinstance/controller_test.go @@ -1064,7 +1064,7 @@ func setupReconciler() (*KeptnWorkloadInstanceReconciler, chan string, *fake.ITr r := &KeptnWorkloadInstanceReconciler{ Client: fakeClient, Scheme: scheme.Scheme, - EventSender: controllercommon.NewEventSender(recorder), + EventSender: controllercommon.NewK8sSender(recorder), Log: ctrl.Log.WithName("test-appController"), TracerFactory: tf, Meters: controllercommon.InitAppMeters(), diff --git a/lifecycle-operator/go.mod b/lifecycle-operator/go.mod index 760ae15b2f..58642b992b 100644 --- a/lifecycle-operator/go.mod +++ b/lifecycle-operator/go.mod @@ -6,6 +6,7 @@ require ( dario.cat/mergo v1.0.0 github.com/argoproj/argo-rollouts v1.5.1 github.com/benbjohnson/clock v1.3.5 + github.com/cloudevents/sdk-go/v2 v2.14.0 github.com/go-logr/logr v1.2.4 github.com/kelseyhightower/envconfig v1.4.0 github.com/keptn/lifecycle-toolkit/klt-cert-manager v0.0.0-20230807110601-88a54f97c157 diff --git a/lifecycle-operator/go.sum b/lifecycle-operator/go.sum index 658c15ffb9..e836fac541 100644 --- a/lifecycle-operator/go.sum +++ b/lifecycle-operator/go.sum @@ -61,6 +61,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go/v2 v2.14.0 h1:Nrob4FwVgi5L4tV9lhjzZcjYqFVyJzsA56CwPaPfv6s= +github.com/cloudevents/sdk-go/v2 v2.14.0/go.mod h1:xDmKfzNjM8gBvjaF8ijFjM1VYOVUEeUfapHMUX1T5To= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -270,6 +272,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/lifecycle-operator/main.go b/lifecycle-operator/main.go index 72943d3fcc..6d395d340f 100644 --- a/lifecycle-operator/main.go +++ b/lifecycle-operator/main.go @@ -24,6 +24,7 @@ import ( "os" argov1alpha1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + ce "github.com/cloudevents/sdk-go/v2" "github.com/kelseyhightower/envconfig" "github.com/keptn/lifecycle-toolkit/klt-cert-manager/pkg/certificates" certCommon "github.com/keptn/lifecycle-toolkit/klt-cert-manager/pkg/common" @@ -172,12 +173,20 @@ func main() { spanHandler := &telemetry.SpanHandler{} - taskLogger := ctrl.Log.WithName("KeptnTask Controller") + // create Cloud Event client + ceClient, err := ce.NewClientHTTP() + if err != nil { + setupLog.Error(err, "failed to create CloudEvent client") + os.Exit(1) + } + + taskLogger := ctrl.Log.WithName("KeptnTask Controller").V(env.KeptnTaskControllerLogLevel) + taskRecorder := mgr.GetEventRecorderFor("keptntask-controller") taskReconciler := &keptntask.KeptnTaskReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: taskLogger.V(env.KeptnTaskControllerLogLevel), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptntask-controller")), + Log: taskLogger, + EventSender: controllercommon.NewEventMultiplexer(taskLogger, taskRecorder, ceClient), Meters: keptnMeters, TracerFactory: telemetry.GetOtelInstance(), } @@ -186,24 +195,26 @@ func main() { os.Exit(1) } - taskDefinitionLogger := ctrl.Log.WithName("KeptnTaskDefinition Controller") + taskDefinitionLogger := ctrl.Log.WithName("KeptnTaskDefinition Controller").V(env.KeptnTaskDefinitionControllerLogLevel) + taskDefinitionRecorder := mgr.GetEventRecorderFor("keptntaskdefinition-controller") taskDefinitionReconciler := &keptntaskdefinition.KeptnTaskDefinitionReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: taskDefinitionLogger.V(env.KeptnTaskDefinitionControllerLogLevel), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptntaskdefinition-controller")), + Log: taskDefinitionLogger, + EventSender: controllercommon.NewEventMultiplexer(taskDefinitionLogger, taskDefinitionRecorder, ceClient), } if err = (taskDefinitionReconciler).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "KeptnTaskDefinition") os.Exit(1) } - appLogger := ctrl.Log.WithName("KeptnApp Controller") + appLogger := ctrl.Log.WithName("KeptnApp Controller").V(env.KeptnAppControllerLogLevel) + appRecorder := mgr.GetEventRecorderFor("keptnapp-controller") appReconciler := &keptnapp.KeptnAppReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: appLogger.V(env.KeptnAppControllerLogLevel), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptnapp-controller")), + Log: appLogger, + EventSender: controllercommon.NewEventMultiplexer(appLogger, appRecorder, ceClient), TracerFactory: telemetry.GetOtelInstance(), } if err = (appReconciler).SetupWithManager(mgr); err != nil { @@ -222,12 +233,13 @@ func main() { os.Exit(1) } - workloadLogger := ctrl.Log.WithName("KeptnWorkload Controller") + workloadLogger := ctrl.Log.WithName("KeptnWorkload Controller").V(env.KeptnWorkloadControllerLogLevel) + workloadRecorder := mgr.GetEventRecorderFor("keptnworkload-controller") workloadReconciler := &keptnworkload.KeptnWorkloadReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: workloadLogger.V(env.KeptnWorkloadControllerLogLevel), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptnworkload-controller")), + Log: workloadLogger, + EventSender: controllercommon.NewEventMultiplexer(workloadLogger, workloadRecorder, ceClient), TracerFactory: telemetry.GetOtelInstance(), } if err = (workloadReconciler).SetupWithManager(mgr); err != nil { @@ -235,12 +247,13 @@ func main() { os.Exit(1) } - workloadInstanceLogger := ctrl.Log.WithName("KeptnWorkloadInstance Controller") + workloadInstanceLogger := ctrl.Log.WithName("KeptnWorkloadInstance Controller").V(env.KeptnWorkloadInstanceControllerLogLevel) + workloadInstanceRecorder := mgr.GetEventRecorderFor("keptnworkloadinstance-controller") workloadInstanceReconciler := &keptnworkloadinstance.KeptnWorkloadInstanceReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: workloadInstanceLogger.V(env.KeptnWorkloadInstanceControllerLogLevel), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptnworkloadinstance-controller")), + Log: workloadInstanceLogger, + EventSender: controllercommon.NewEventMultiplexer(workloadInstanceLogger, workloadInstanceRecorder, ceClient), Meters: keptnMeters, TracerFactory: telemetry.GetOtelInstance(), SpanHandler: spanHandler, @@ -250,12 +263,13 @@ func main() { os.Exit(1) } - appVersionLogger := ctrl.Log.WithName("KeptnAppVersion Controller") + appVersionLogger := ctrl.Log.WithName("KeptnAppVersion Controller").V(env.KeptnAppVersionControllerLogLevel) + appVersionRecorder := mgr.GetEventRecorderFor("keptnappversion-controller") appVersionReconciler := &keptnappversion.KeptnAppVersionReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: appVersionLogger.V(env.KeptnAppVersionControllerLogLevel), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptnappversion-controller")), + Log: appVersionLogger, + EventSender: controllercommon.NewEventMultiplexer(appVersionLogger, appVersionRecorder, ceClient), TracerFactory: telemetry.GetOtelInstance(), Meters: keptnMeters, SpanHandler: spanHandler, @@ -265,12 +279,13 @@ func main() { os.Exit(1) } - evaluationLogger := ctrl.Log.WithName("KeptnEvaluation Controller") + evaluationLogger := ctrl.Log.WithName("KeptnEvaluation Controller").V(env.KeptnEvaluationControllerLogLevel) + evaluationRecorder := mgr.GetEventRecorderFor("keptnevaluation-controller") evaluationReconciler := &keptnevaluation.KeptnEvaluationReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: evaluationLogger.V(env.KeptnEvaluationControllerLogLevel), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptnevaluation-controller")), + Log: evaluationLogger, + EventSender: controllercommon.NewEventMultiplexer(evaluationLogger, evaluationRecorder, ceClient), TracerFactory: telemetry.GetOtelInstance(), Meters: keptnMeters, Namespace: env.PodNamespace, @@ -280,11 +295,11 @@ func main() { os.Exit(1) } - configLogger := ctrl.Log.WithName("KeptnConfig Controller") + configLogger := ctrl.Log.WithName("KeptnConfig Controller").V(env.KeptnOptionsControllerLogLevel) configReconciler := &controlleroptions.KeptnConfigReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Log: configLogger.V(env.KeptnOptionsControllerLogLevel), + Log: configLogger, DefaultCollectorURL: env.KeptnOptionsCollectorURL, } if err = (configReconciler).SetupWithManager(mgr); err != nil { @@ -350,14 +365,16 @@ func main() { os.Exit(1) } + webhookLogger := ctrl.Log.WithName("Mutating Webhook") + webhookRecorder := mgr.GetEventRecorderFor("keptn/webhook") if err := webhookBuilder.Run(mgr, map[string]*ctrlWebhook.Admission{ "/mutate-v1-pod": { Handler: &pod_mutator.PodMutatingWebhook{ Client: mgr.GetClient(), Tracer: otel.Tracer("keptn/webhook"), - EventSender: controllercommon.NewEventSender(mgr.GetEventRecorderFor("keptn/webhook")), + EventSender: controllercommon.NewEventMultiplexer(webhookLogger, webhookRecorder, ceClient), Decoder: decoder, - Log: ctrl.Log.WithName("Mutating Webhook"), + Log: webhookLogger, }, }, }); err != nil { diff --git a/lifecycle-operator/test/component/app/app_suite_test.go b/lifecycle-operator/test/component/app/app_suite_test.go index 255681189e..3c18394402 100644 --- a/lifecycle-operator/test/component/app/app_suite_test.go +++ b/lifecycle-operator/test/component/app/app_suite_test.go @@ -40,7 +40,7 @@ var _ = BeforeSuite(func() { controller := &keptnapp.KeptnAppReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("test-app-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("test-app-controller")), Log: GinkgoLogr, TracerFactory: &common.TracerFactory{Tracer: tracer}, } diff --git a/lifecycle-operator/test/component/appversion/appversion_suite_test.go b/lifecycle-operator/test/component/appversion/appversion_suite_test.go index 08a389e7aa..5ea5311949 100644 --- a/lifecycle-operator/test/component/appversion/appversion_suite_test.go +++ b/lifecycle-operator/test/component/appversion/appversion_suite_test.go @@ -41,7 +41,7 @@ var _ = BeforeSuite(func() { controller := &keptnappversion.KeptnAppVersionReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("test-appversion-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("test-appversion-controller")), Log: GinkgoLogr, Meters: common.InitKeptnMeters(), SpanHandler: &telemetry.SpanHandler{}, diff --git a/lifecycle-operator/test/component/evaluation/evaluation_suite_test.go b/lifecycle-operator/test/component/evaluation/evaluation_suite_test.go index 3bf626377e..855c25ce7a 100644 --- a/lifecycle-operator/test/component/evaluation/evaluation_suite_test.go +++ b/lifecycle-operator/test/component/evaluation/evaluation_suite_test.go @@ -44,7 +44,7 @@ var _ = BeforeSuite(func() { controller := &keptnevaluation.KeptnEvaluationReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("test-evaluation-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("test-evaluation-controller")), Log: GinkgoLogr, Meters: common.InitKeptnMeters(), TracerFactory: &common.TracerFactory{Tracer: tracer}, diff --git a/lifecycle-operator/test/component/load/load_suite_test.go b/lifecycle-operator/test/component/load/load_suite_test.go index d86bd61a08..e5bc79f8eb 100644 --- a/lifecycle-operator/test/component/load/load_suite_test.go +++ b/lifecycle-operator/test/component/load/load_suite_test.go @@ -40,7 +40,7 @@ var _ = BeforeSuite(func() { controller := &keptnapp.KeptnAppReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("load-app-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("load-app-controller")), Log: GinkgoLogr, TracerFactory: &common.TracerFactory{Tracer: tracer}, } diff --git a/lifecycle-operator/test/component/task/task_suite_test.go b/lifecycle-operator/test/component/task/task_suite_test.go index abf0b7ae54..ee71257483 100644 --- a/lifecycle-operator/test/component/task/task_suite_test.go +++ b/lifecycle-operator/test/component/task/task_suite_test.go @@ -41,7 +41,7 @@ var _ = BeforeSuite(func() { controller := &keptntask.KeptnTaskReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("test-task-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("test-task-controller")), Log: GinkgoLogr, Meters: common.InitKeptnMeters(), TracerFactory: &common.TracerFactory{Tracer: tracer}, diff --git a/lifecycle-operator/test/component/taskdefinition/taskdefinition_suite_test.go b/lifecycle-operator/test/component/taskdefinition/taskdefinition_suite_test.go index d332e236bf..4a0fb3ea24 100644 --- a/lifecycle-operator/test/component/taskdefinition/taskdefinition_suite_test.go +++ b/lifecycle-operator/test/component/taskdefinition/taskdefinition_suite_test.go @@ -34,7 +34,7 @@ var _ = BeforeSuite(func() { controller := &keptntaskdefinition.KeptnTaskDefinitionReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("test-taskdefinition-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("test-taskdefinition-controller")), Log: GinkgoLogr, } Eventually(controller.SetupWithManager(k8sManager)).WithTimeout(30 * time.Second).WithPolling(time.Second).Should(Succeed()) diff --git a/lifecycle-operator/test/component/workload/workload_suite_test.go b/lifecycle-operator/test/component/workload/workload_suite_test.go index a930493afd..27a8d666d7 100644 --- a/lifecycle-operator/test/component/workload/workload_suite_test.go +++ b/lifecycle-operator/test/component/workload/workload_suite_test.go @@ -40,7 +40,7 @@ var _ = BeforeSuite(func() { controller := &keptnworkload.KeptnWorkloadReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("test-workload-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("test-workload-controller")), Log: GinkgoLogr, TracerFactory: &common.TracerFactory{Tracer: tracer}, } diff --git a/lifecycle-operator/test/component/workloadinstance/workloadinstance_suite_test.go b/lifecycle-operator/test/component/workloadinstance/workloadinstance_suite_test.go index 446fa3b491..91da1a60e1 100644 --- a/lifecycle-operator/test/component/workloadinstance/workloadinstance_suite_test.go +++ b/lifecycle-operator/test/component/workloadinstance/workloadinstance_suite_test.go @@ -41,7 +41,7 @@ var _ = BeforeSuite(func() { controller := &keptnworkloadinstance.KeptnWorkloadInstanceReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), - EventSender: controllercommon.NewEventSender(k8sManager.GetEventRecorderFor("test-workloadinstance-controller")), + EventSender: controllercommon.NewK8sSender(k8sManager.GetEventRecorderFor("test-workloadinstance-controller")), Log: GinkgoLogr, Meters: common.InitKeptnMeters(), SpanHandler: &telemetry.SpanHandler{}, diff --git a/lifecycle-operator/webhooks/pod_mutator/pod_mutating_webhook_test.go b/lifecycle-operator/webhooks/pod_mutator/pod_mutating_webhook_test.go index 1fb0c46d06..b43b38780c 100644 --- a/lifecycle-operator/webhooks/pod_mutator/pod_mutating_webhook_test.go +++ b/lifecycle-operator/webhooks/pod_mutator/pod_mutating_webhook_test.go @@ -966,7 +966,7 @@ func TestPodMutatingWebhook_Handle_DisabledNamespace(t *testing.T) { Client: fakeClient, Tracer: tr, Decoder: decoder, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: testr.New(t), } @@ -1029,7 +1029,7 @@ func TestPodMutatingWebhook_Handle_UnsupportedOwner(t *testing.T) { Client: fakeClient, Tracer: tr, Decoder: decoder, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: testr.New(t), } @@ -1125,7 +1125,7 @@ func TestPodMutatingWebhook_Handle_SingleService(t *testing.T) { Client: fakeClient, Tracer: tr, Decoder: decoder, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: testr.New(t), } @@ -1246,7 +1246,7 @@ func TestPodMutatingWebhook_Handle_SingleService_AppCreationRequestAlreadyPresen Client: fakeClient, Tracer: tr, Decoder: decoder, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: testr.New(t), } @@ -1354,7 +1354,7 @@ func TestPodMutatingWebhook_Handle_MultiService(t *testing.T) { Client: fakeClient, Tracer: tr, Decoder: decoder, - EventSender: controllercommon.NewEventSender(record.NewFakeRecorder(100)), + EventSender: controllercommon.NewK8sSender(record.NewFakeRecorder(100)), Log: testr.New(t), }