Permalink
Browse files

Added a status API to check database

The API makes a direct request to the database
for its schema version to ensure the connection
is still active. This can be used with monitoring
software to ensure the database connection doesn't
break again.

This endpoint can be expanded to include memory
information and other status stuff.

Users must have the ViewDebugInfo permission which
is given to all full admins and any one in the
APIStatusUsers group.
  • Loading branch information...
lfkeitel committed Feb 6, 2018
1 parent 525b6fd commit c09027b562147be93d3b4a4e770a44858b79be21
@@ -101,6 +101,7 @@ type Config struct {
ReadOnlyUsers []string
APIReadOnlyUsers []string
APIReadWriteUsers []string
APIStatusUsers []string
LDAP struct {
UseAD bool
@@ -240,8 +241,8 @@ func setSensibleDefaults(c *Config) (*Config, error) {
if len(c.Auth.HelpDeskUsers) == 0 {
c.Auth.HelpDeskUsers = []string{"helpdesk"}
}
if len(c.Auth.HelpDeskUsers) == 0 {
c.Auth.HelpDeskUsers = []string{"readonly"}
if len(c.Auth.ReadOnlyUsers) == 0 {
c.Auth.ReadOnlyUsers = []string{"readonly"}
}
// DHCP
@@ -104,3 +104,13 @@ type DatabaseAccessor struct {
*sql.DB
Driver string
}
func (d *DatabaseAccessor) SchemaVersion() int {
var currDBVer int
verRow := d.DB.QueryRow(`SELECT "value" FROM "settings" WHERE "id" = 'db_version'`)
if verRow == nil {
return 0
}
verRow.Scan(&currDBVer)
return currDBVer
}
@@ -0,0 +1,41 @@
package api
import (
"net/http"
"github.com/julienschmidt/httprouter"
"github.com/packet-guardian/packet-guardian/src/common"
"github.com/packet-guardian/packet-guardian/src/db"
"github.com/packet-guardian/packet-guardian/src/models"
)
type Status struct {
e *common.Environment
}
func NewStatusController(e *common.Environment) *Status {
return &Status{e: e}
}
func (s *Status) GetStatus(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
sessionUser := models.GetUserFromContext(r)
if !sessionUser.Can(models.ViewDebugInfo) {
w.WriteHeader(http.StatusUnauthorized)
return
}
dbVer := s.e.DB.SchemaVersion()
dbStatus := "ok"
if dbVer != db.DBVersion {
dbStatus = "warning"
}
data := map[string]interface{}{
"database_version": dbVer,
"database_status": dbStatus,
"database_type": s.e.DB.Driver,
}
common.NewAPIResponse("", data).WriteResponse(w, http.StatusOK)
}
@@ -12,7 +12,7 @@ import (
"github.com/packet-guardian/packet-guardian/src/common"
)
const dbVersion = 2
const DBVersion = 2
type dbInit interface {
init(*common.DatabaseAccessor, *common.Config) error
@@ -124,19 +124,19 @@ func (m *mySQLDB) migrateTables(d *common.DatabaseAccessor) error {
common.SystemLogger.WithFields(verbose.Fields{
"current-version": currDBVer,
"active-version": dbVersion,
"active-version": DBVersion,
}).Debug("Database Versions")
// No migration needed
if currDBVer == dbVersion {
if currDBVer == DBVersion {
return nil
}
if currDBVer > dbVersion {
if currDBVer > DBVersion {
return errors.New("Database is too new, can't rollback")
}
neededMigrations := m.migrateFuncs[currDBVer:dbVersion]
neededMigrations := m.migrateFuncs[currDBVer:DBVersion]
for _, migrate := range neededMigrations {
if migrate == nil {
continue
@@ -146,7 +146,7 @@ func (m *mySQLDB) migrateTables(d *common.DatabaseAccessor) error {
}
}
_, err := d.DB.Exec(`UPDATE "settings" SET "value" = ? WHERE "id" = 'db_version'`, dbVersion)
_, err := d.DB.Exec(`UPDATE "settings" SET "value" = ? WHERE "id" = 'db_version'`, DBVersion)
return err
}
@@ -234,7 +234,7 @@ func (m *mySQLDB) createSettingTable(d *common.DatabaseAccessor) error {
return err
}
_, err := d.DB.Exec(`INSERT INTO "settings" ("id", "value") VALUES ('db_version', ?)`, dbVersion)
_, err := d.DB.Exec(`INSERT INTO "settings" ("id", "value") VALUES ('db_version', ?)`, DBVersion)
return err
}
@@ -104,15 +104,15 @@ func (s *sqliteDB) migrateTables(d *common.DatabaseAccessor) error {
common.SystemLogger.WithFields(verbose.Fields{
"current-version": currDBVer,
"active-version": dbVersion,
"active-version": DBVersion,
}).Debug("Database Versions")
// No migration needed
if currDBVer == dbVersion {
if currDBVer == DBVersion {
return nil
}
neededMigrations := s.migrateFuncs[currDBVer:dbVersion]
neededMigrations := s.migrateFuncs[currDBVer:DBVersion]
for _, migrate := range neededMigrations {
if migrate == nil {
continue
@@ -122,7 +122,7 @@ func (s *sqliteDB) migrateTables(d *common.DatabaseAccessor) error {
}
}
_, err := d.DB.Exec(`UPDATE "settings" SET "value" = ? WHERE "id" = 'db_version'`, dbVersion)
_, err := d.DB.Exec(`UPDATE "settings" SET "value" = ? WHERE "id" = 'db_version'`, DBVersion)
return err
}
@@ -210,7 +210,7 @@ func (s *sqliteDB) createSettingTable(d *common.DatabaseAccessor) error {
return err
}
_, err := d.DB.Exec(`INSERT INTO "settings" ("id", "value") VALUES ('db_version', ?)`, dbVersion)
_, err := d.DB.Exec(`INSERT INTO "settings" ("id", "value") VALUES ('db_version', ?)`, DBVersion)
return err
}
@@ -84,6 +84,9 @@ func (u *User) LoadRights() {
u.Rights = u.Rights.With(APIRead)
u.Rights = u.Rights.With(APIWrite)
}
if common.StringInSlice(u.Username, u.e.Config.Auth.APIStatusUsers) {
u.Rights = u.Rights.With(ViewDebugInfo)
}
if u.IsBlacklisted() {
u.Rights = u.Rights.Without(ManageOwnRights)
@@ -173,6 +173,9 @@ func apiRouter(e *common.Environment) http.Handler {
r.POST("/api/user", userAPIController.UserHandler)
r.DELETE("/api/user", userAPIController.UserHandler)
statusAPIController := api.NewStatusController(e)
r.GET("/api/status", statusAPIController.GetStatus)
return mid.CheckAuthAPI(r)
}

0 comments on commit c09027b

Please sign in to comment.