From 070c0a7613aecc5fe65b4f1ddcdab9a596d63ebb Mon Sep 17 00:00:00 2001 From: Bastien Beuchat Date: Tue, 26 Sep 2023 10:00:05 +0200 Subject: [PATCH] [CLOUDTRUST-5196] Add health check for AuditEventsReporterModule (#126) --- healthcheck/audit.go | 59 +++++++++++++++++++++++++++++++++++++++ healthcheck/audit_test.go | 42 ++++++++++++++++++++++++++++ healthcheck/health.go | 7 +++++ healthcheck/mock_test.go | 1 + 4 files changed, 109 insertions(+) create mode 100644 healthcheck/audit.go create mode 100644 healthcheck/audit_test.go diff --git a/healthcheck/audit.go b/healthcheck/audit.go new file mode 100644 index 0000000..e95edce --- /dev/null +++ b/healthcheck/audit.go @@ -0,0 +1,59 @@ +package healthcheck + +import ( + "context" + "time" + + "github.com/cloudtrust/common-service/v2/events" + log "github.com/cloudtrust/common-service/v2/log" +) + +type auditEventsReporterChecker struct { + alias string + reporter events.AuditEventsReporterModule + timeout time.Duration + response HealthStatus + logger log.Logger +} + +func newAuditEventsReporterChecker(alias string, reporter events.AuditEventsReporterModule, timeout time.Duration, cacheDuration time.Duration, logger log.Logger) BasicChecker { + healthStatusType := "auditEventreporter" + response := HealthStatus{Name: &alias, Type: &healthStatusType, CacheDuration: cacheDuration} + response.connection("init") + response.stateUp() + return &auditEventsReporterChecker{ + alias: alias, + reporter: reporter, + timeout: timeout, + response: response, + logger: logger, + } +} + +func (a *auditEventsReporterChecker) CheckStatus() HealthStatus { + if a.response.hasExpired() { + go a.updateStatus() + } + + return a.response +} + +func (a *auditEventsReporterChecker) updateStatus() { + finished := make(chan bool) + go func() { + event := events.NewEvent("healthcheck", "", "master", "health_checker", "health_checker", "master", map[string]string{}) + a.reporter.ReportEvent(context.Background(), event) + finished <- true + }() + + select { + case <-finished: + a.response.connection("established") + a.response.stateUp() + case <-time.After(a.timeout): + a.response.stateDown("Events reporter timeout") + a.logger.Error(context.Background(), "msg", "Audit Events Reporter timeout to produce events", "timeout", a.timeout) + } + + a.response.touch() +} diff --git a/healthcheck/audit_test.go b/healthcheck/audit_test.go new file mode 100644 index 0000000..05f291e --- /dev/null +++ b/healthcheck/audit_test.go @@ -0,0 +1,42 @@ +package healthcheck + +import ( + "testing" + "time" + + "github.com/cloudtrust/common-service/v2/healthcheck/mock" + log "github.com/cloudtrust/common-service/v2/log" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +func TestAuditEventsReporterChecker(t *testing.T) { + var mockCtrl = gomock.NewController(t) + defer mockCtrl.Finish() + + var mockAuditEventReporter = mock.NewAuditEventsReporterModule(mockCtrl) + + t.Run("Success ", func(t *testing.T) { + var auditEventReporterChecker = newAuditEventsReporterChecker("alias", mockAuditEventReporter, 10*time.Second, 10*time.Second, log.NewNopLogger()) + internalChecker := auditEventReporterChecker.(*auditEventsReporterChecker) + mockAuditEventReporter.EXPECT().ReportEvent(gomock.Any(), gomock.Any()).Times(1) + + internalChecker.updateStatus() + var res = internalChecker.response + assert.NotNil(t, res.Connection) + assert.Equal(t, "established", *res.Connection) + }) + + t.Run("Failure ", func(t *testing.T) { + var auditEventReporterChecker = newAuditEventsReporterChecker("alias", mockAuditEventReporter, 1*time.Second, 10*time.Second, log.NewNopLogger()) + internalChecker := auditEventReporterChecker.(*auditEventsReporterChecker) + mockAuditEventReporter.EXPECT().ReportEvent(gomock.Any(), gomock.Any()).Do(func(arg0 interface{}, arg1 interface{}) { + time.Sleep(2 * time.Second) + }) + + internalChecker.updateStatus() + res := internalChecker.response + assert.NotNil(t, res.Message) + assert.Equal(t, "Events reporter timeout", *res.Message) + }) +} diff --git a/healthcheck/health.go b/healthcheck/health.go index 4e262ed..ba2c7a4 100644 --- a/healthcheck/health.go +++ b/healthcheck/health.go @@ -5,6 +5,7 @@ import ( "net/http" "time" + "github.com/cloudtrust/common-service/v2/events" commonhttp "github.com/cloudtrust/common-service/v2/http" log "github.com/cloudtrust/common-service/v2/log" "github.com/go-kit/kit/ratelimit" @@ -17,6 +18,7 @@ type HealthChecker interface { AddHTTPEndpoint(name string, targetURL string, timeoutDuration time.Duration, expectedStatus int, cacheDuration time.Duration) AddHTTPEndpoints(endpoints map[string]string, timeoutDuration time.Duration, expectedStatus int, cacheDuration time.Duration) AddDatabase(name string, db HealthDatabase, cacheDuration time.Duration) + AddAuditEventsReporterModule(name string, reporter events.AuditEventsReporterModule, timeout time.Duration, cacheDuration time.Duration) MakeHandler(rateLimit ratelimit.Allower) http.HandlerFunc } @@ -131,6 +133,11 @@ func (hc *healthchecker) AddDatabase(name string, db HealthDatabase, cacheDurati hc.AddHealthChecker(name, newDatabaseChecker(name, db, cacheDuration)) } +func (hc *healthchecker) AddAuditEventsReporterModule(name string, reporter events.AuditEventsReporterModule, timeout time.Duration, cacheDuration time.Duration) { + hc.logger.Info(context.Background(), "msg", "Adding audit event reporter module", "processor", name) + hc.AddHealthChecker(name, newAuditEventsReporterChecker(name, reporter, timeout, cacheDuration, hc.logger)) +} + // MakeHandler makes a HTTP handler that returns health check information func (hc *healthchecker) MakeHandler(rateLimit ratelimit.Allower) http.HandlerFunc { var ctx = context.Background() diff --git a/healthcheck/mock_test.go b/healthcheck/mock_test.go index aad9fc1..6bc8a87 100644 --- a/healthcheck/mock_test.go +++ b/healthcheck/mock_test.go @@ -1,3 +1,4 @@ package healthcheck //go:generate mockgen --build_flags=--mod=mod -destination=./mock/healthcheck.go -package=mock -mock_names=HealthDatabase=HealthDatabase github.com/cloudtrust/common-service/v2/healthcheck HealthDatabase +//go:generate mockgen --build_flags=--mod=mod -destination=./mock/eventsreportermodule.go -package=mock -mock_names=AuditEventsReporterModule=AuditEventsReporterModule github.com/cloudtrust/common-service/v2/events AuditEventsReporterModule