diff --git a/internal/httputil/healthcheck.go b/internal/httputil/healthcheck.go new file mode 100644 index 000000000..827f5ff04 --- /dev/null +++ b/internal/httputil/healthcheck.go @@ -0,0 +1,82 @@ +// Copyright 2020 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package httputil + +import ( + "database/sql" + "encoding/json" + "net/http" + + "github.com/matrix-org/dendrite/internal/config" + "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/sirupsen/logrus" +) + +// healthResponse is returned on requests to /api/health +type healthResponse struct { + Code int `json:"code"` + FirstError string `json:"error"` +} + +// HealthCheckHandler adds a /health endpoint to the internal api mux +func HealthCheckHandler(dbConfig ...config.DatabaseOptions) http.HandlerFunc { + if len(dbConfig) == 0 { + return func(_ http.ResponseWriter, _ *http.Request) {} + } + conns := make([]*sql.DB, len(dbConfig)) + // populate sql connections + for i, conf := range dbConfig { + c, err := sqlutil.Open(&conf) + if err != nil { + panic(err) + } + conns[i] = c + } + + return func(resp http.ResponseWriter, _ *http.Request) { + var ( + errMsg string + code = http.StatusOK + ) + err := dbPingCheck(conns, &errMsg, &code) + if err != nil { + resp.WriteHeader(http.StatusInternalServerError) + } + data, err := json.Marshal(healthResponse{ + Code: code, + FirstError: errMsg, + }) + if err != nil { + logrus.WithError(err).Error("Unable to encode response") + resp.WriteHeader(http.StatusInternalServerError) + return + } + if _, err = resp.Write(data); err != nil { + logrus.WithError(err).Error("Unable to write health response") + } + } +} + +func dbPingCheck(conns []*sql.DB, errMsg *string, code *int) error { + // check every database connection + for _, conn := range conns { + if err := conn.Ping(); err != nil { + *errMsg = err.Error() + *code = http.StatusInternalServerError + return err + } + } + return nil +} diff --git a/internal/setup/base.go b/internal/setup/base.go index 2fdacf957..081409317 100644 --- a/internal/setup/base.go +++ b/internal/setup/base.go @@ -15,8 +15,6 @@ package setup import ( - "database/sql" - "encoding/json" "fmt" "io" "net/http" @@ -25,7 +23,6 @@ import ( "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/httputil" - "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/gomatrixserverlib" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -270,7 +267,7 @@ func (b *BaseDendrite) CreateFederationClient() *gomatrixserverlib.FederationCli // nolint:gocyclo func (b *BaseDendrite) SetupAndServeHTTP( internalHTTPAddr, externalHTTPAddr config.HTTPAddress, - certFile, keyFile *string, + certFile, keyFile *string, dbConfigs ...config.DatabaseOptions, ) { internalAddr, _ := internalHTTPAddr.Address() externalAddr, _ := externalHTTPAddr.Address() @@ -299,6 +296,8 @@ func (b *BaseDendrite) SetupAndServeHTTP( internalRouter.Handle("/metrics", httputil.WrapHandlerInBasicAuth(promhttp.Handler(), b.Cfg.Global.Metrics.BasicAuth)) } + b.InternalAPIMux.HandleFunc("/health", httputil.HealthCheckHandler(dbConfigs...)) + externalRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(b.PublicClientAPIMux) externalRouter.PathPrefix(httputil.PublicKeyPathPrefix).Handler(b.PublicKeyAPIMux) externalRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(b.PublicFederationAPIMux) @@ -364,60 +363,3 @@ func setupNaffka(cfg *config.Dendrite) (sarama.Consumer, sarama.SyncProducer) { } return naff, naff } - -// healthResponse is returned on requests to /api/health -type healthResponse struct { - Code int `json:"code"` - FirstError string `json:"error"` -} - -// AddHealthCheck adds a /health endpoint to the internal api mux -func AddHealthCheck(apiMux *mux.Router, dbConfig ...config.DatabaseOptions) { - if len(dbConfig) == 0 { - return - } - conns := make([]*sql.DB, len(dbConfig)) - // populate sql connections - for i, conf := range dbConfig { - c, err := sqlutil.Open(&conf) - if err != nil { - panic(err) - } - conns[i] = c - } - - apiMux.HandleFunc("/health", func(resp http.ResponseWriter, _ *http.Request) { - var ( - errMsg string - code = http.StatusOK - ) - err := dbPingCheck(conns, &errMsg, &code) - if err != nil { - resp.WriteHeader(http.StatusInternalServerError) - } - data, err := json.Marshal(healthResponse{ - Code: code, - FirstError: errMsg, - }) - if err != nil { - logrus.WithError(err).Error("Unable to encode response") - resp.WriteHeader(http.StatusInternalServerError) - return - } - if _, err = resp.Write(data); err != nil { - logrus.WithError(err).Error("Unable to write health response") - } - }) -} - -func dbPingCheck(conns []*sql.DB, errMsg *string, code *int) error { - // check every database connection - for _, conn := range conns { - if err := conn.Ping(); err != nil { - *errMsg = err.Error() - *code = http.StatusInternalServerError - return err - } - } - return nil -}