github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/healthz/ready.go (about) 1 package healthz 2 3 import ( 4 "context" 5 "net/http" 6 7 "github.com/kyma-incubator/compass/components/director/pkg/log" 8 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 9 "github.com/pkg/errors" 10 ) 11 12 // Repository missing godoc 13 //go:generate mockery --name=Repository --output=automock --outpkg=automock --case=underscore --disable-version-string 14 type Repository interface { 15 GetVersion(ctx context.Context) (string, bool, error) 16 } 17 18 // ReadyConfig missing godoc 19 type ReadyConfig struct { 20 SchemaMigrationVersion string `envconfig:"APP_SCHEMA_MIGRATION_VERSION"` 21 } 22 23 // Ready missing godoc 24 type Ready struct { 25 transactioner persistence.Transactioner 26 schemaCompatible bool 27 cfg ReadyConfig 28 repo Repository 29 } 30 31 // NewReady missing godoc 32 func NewReady(transactioner persistence.Transactioner, cfg ReadyConfig, repository Repository) *Ready { 33 return &Ready{ 34 transactioner: transactioner, 35 schemaCompatible: false, 36 cfg: cfg, 37 repo: repository, 38 } 39 } 40 41 // NewReadinessHandler returns handler that returns OK if the db schema is compatible and successful 42 // db ping is performed or InternalServerError otherwise 43 func NewReadinessHandler(r *Ready) func(writer http.ResponseWriter, request *http.Request) { 44 return func(writer http.ResponseWriter, request *http.Request) { 45 if r.schemaCompatible = r.checkSchemaCompatibility(request.Context()); !r.schemaCompatible { 46 writer.WriteHeader(http.StatusInternalServerError) 47 return 48 } 49 50 if err := r.transactioner.PingContext(request.Context()); err != nil { 51 writer.WriteHeader(http.StatusInternalServerError) 52 return 53 } 54 55 writer.WriteHeader(http.StatusOK) 56 } 57 } 58 59 func (r *Ready) checkSchemaCompatibility(ctx context.Context) bool { 60 if r.schemaCompatible { 61 return true 62 } 63 64 tx, err := r.transactioner.Begin() 65 if err != nil { 66 log.C(ctx).Errorf(errors.Wrap(err, "while starting transaction").Error()) 67 return false 68 } 69 defer r.transactioner.RollbackUnlessCommitted(ctx, tx) 70 71 ctx = persistence.SaveToContext(ctx, tx) 72 73 schemaVersion, dirty, err := r.repo.GetVersion(ctx) 74 if err != nil { 75 log.C(ctx).Error(err.Error()) 76 return false 77 } 78 79 if err := tx.Commit(); err != nil { 80 log.C(ctx).Error(errors.Wrap(err, "while committing transaction").Error()) 81 return false 82 } 83 84 if r.cfg.SchemaMigrationVersion != schemaVersion || dirty { 85 log.C(ctx).Errorf("Incompatible schema version. Expected: %s, Current (version, dirty): (%s, %v)", r.cfg.SchemaMigrationVersion, schemaVersion, dirty) 86 return false 87 } 88 89 return true 90 }