diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e8eef57..3ec00745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.90.68 (09-15-2020) +- Added DB_DSN env for mysql, postgres or sqlite DSN database connection string +- Added READ_ONLY env for a read only connection to the database + # 0.90.67 (09-14-2020) - Modified core settings to update config.yml on save - Modified Theme Editor to restart the HTTP router on create/delete (fixing 404's) diff --git a/database/database.go b/database/database.go index c6136cfc..79b6fc2a 100644 --- a/database/database.go +++ b/database/database.go @@ -169,10 +169,6 @@ func Available(db Database) bool { return true } -func AmountGreaterThan1000(db *gorm.DB) *gorm.DB { - return db.Where("service = ?", 1000) -} - func (it *Db) MultipleSelects(args ...string) Database { joined := strings.Join(args, ", ") return it.Select(joined) @@ -181,6 +177,7 @@ func (it *Db) MultipleSelects(args ...string) Database { type Db struct { Database *gorm.DB Type string + ReadOnly bool } // Openw is a drop-in replacement for Open() @@ -223,6 +220,9 @@ func OpenTester() (Database, error) { default: dbString = fmt.Sprintf("file:%s?mode=memory&cache=shared", utils.RandomString(12)) } + if utils.Params.IsSet("DB_DSN") { + dbString = utils.Params.GetString("DB_DSN") + } newDb, err := Openw(testDB, dbString) if err != nil { return nil, err @@ -239,6 +239,7 @@ func Wrap(db *gorm.DB) Database { return &Db{ Database: db, Type: db.Dialect().GetName(), + ReadOnly: utils.Params.GetBool("READ_ONLY"), } } @@ -379,14 +380,26 @@ func (it *Db) Related(value interface{}, foreignKeys ...string) Database { } func (it *Db) FirstOrInit(out interface{}, where ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.FirstOrInit(out, where...)) } func (it *Db) FirstOrCreate(out interface{}, where ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.FirstOrCreate(out, where...)) } func (it *Db) Update(attrs ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Update(attrs...)) } @@ -395,22 +408,42 @@ func (it *Db) Updates(values interface{}, ignoreProtectedAttrs ...bool) Database } func (it *Db) UpdateColumn(attrs ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.UpdateColumn(attrs...)) } func (it *Db) UpdateColumns(values interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.UpdateColumns(values)) } func (it *Db) Save(value interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Save(value)) } func (it *Db) Create(value interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Create(value)) } func (it *Db) Delete(value interface{}, where ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Delete(value, where...)) } @@ -435,14 +468,26 @@ func (it *Db) Debug() Database { } func (it *Db) Begin() Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Begin()) } func (it *Db) Commit() Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Commit()) } func (it *Db) Rollback() Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.Rollback()) } @@ -455,14 +500,26 @@ func (it *Db) RecordNotFound() bool { } func (it *Db) CreateTable(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.CreateTable(values...)) } func (it *Db) DropTable(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.DropTable(values...)) } func (it *Db) DropTableIfExists(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.DropTableIfExists(values...)) } @@ -471,26 +528,50 @@ func (it *Db) HasTable(value interface{}) bool { } func (it *Db) AutoMigrate(values ...interface{}) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AutoMigrate(values...)) } func (it *Db) ModifyColumn(column string, typ string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.ModifyColumn(column, typ)) } func (it *Db) DropColumn(column string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.DropColumn(column)) } func (it *Db) AddIndex(indexName string, columns ...string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AddIndex(indexName, columns...)) } func (it *Db) AddUniqueIndex(indexName string, columns ...string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AddUniqueIndex(indexName, columns...)) } func (it *Db) RemoveIndex(indexName string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.RemoveIndex(indexName)) } @@ -519,6 +600,10 @@ func (it *Db) SetJoinTableHandler(source interface{}, column string, handler gor } func (it *Db) AddForeignKey(field string, dest string, onDelete string, onUpdate string) Database { + if it.ReadOnly { + it.Database.Error = nil + return Wrap(it.Database) + } return Wrap(it.Database.AddForeignKey(field, dest, onDelete, onUpdate)) } diff --git a/database/routines.go b/database/routines.go index 92583e64..591277da 100644 --- a/database/routines.go +++ b/database/routines.go @@ -16,6 +16,8 @@ var ( // Maintenance will automatically delete old records from 'failures' and 'hits' // this function is currently set to delete records 7+ days old every 60 minutes +// env: REMOVE_AFTER - golang duration parsed time for deleting records older than REMOVE_AFTER duration from now +// env: CLEANUP_INTERVAL - golang duration parsed time for checking old records routine func Maintenance() { dur := utils.Params.GetDuration("REMOVE_AFTER") interval := utils.Params.GetDuration("CLEANUP_INTERVAL") diff --git a/frontend/src/API.js b/frontend/src/API.js index 8a0d3fcc..e027fcb4 100644 --- a/frontend/src/API.js +++ b/frontend/src/API.js @@ -7,8 +7,8 @@ const tokenKey = "statping_auth"; class Api { constructor() { - this.version = "0.90.66"; - this.commit = "a3ce4124f654b13c7f2af88b8410f998bd57fcef"; + this.version = "0.90.67"; + this.commit = "7e121335791d2143a2eefd404dbcce83b8f46f61"; } async oauth() { diff --git a/frontend/src/pages/Help.vue b/frontend/src/pages/Help.vue index 55639c5b..61654a40 100755 --- a/frontend/src/pages/Help.vue +++ b/frontend/src/pages/Help.vue @@ -1545,8 +1545,8 @@ systemctl start statping
You can even run Statping on your Raspberry Pi by installing the precompiled binary from Latest Releases. For the Raspberry Pi 3 you’ll want to download the statping-linux-arm7.tar.gz
file. Be sure to change VERSION
to the latest version in Releases, and include the ‘v’.
VERSION=$(curl -sL "https://github.com/statping/statping/releases/latest" | grep -o 'tag/[v.0-9]*' | awk -F/ '{print $2}' | head -n1)
-wget https://github.com/statping/statping/releases/download/$VERSION/statping-linux-arm7.tar.gz
-tar -xvzf statping-linux-arm7.tar.gz
+wget https://github.com/statping/statping/releases/download/$VERSION/statping-linux-arm-7.tar.gz
+tar -xvzf statping-linux-arm-7.tar.gz
chmod +x statping
mv statping /usr/local/bin/statping
@@ -2275,7 +2275,7 @@ OluFxewsEO0QNDrfFb+0gnjYlnGqOFcZjUMXbDdY5oLSPtXohynuTK1qyQ==
-Automatically generated from Statping's Wiki on 2020-09-09 01:24:21.649582 +0000 UTC
+Automatically generated from Statping's Wiki on 2020-09-15 19:09:14.703237 +0000 UTC
diff --git a/handlers/setup.go b/handlers/setup.go
index 17148b06..4c663eb2 100644
--- a/handlers/setup.go
+++ b/handlers/setup.go
@@ -59,7 +59,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
return
}
- if err := configs.CreateAdminUser(confgs); err != nil {
+ if err := configs.CreateAdminUser(); err != nil {
sendErrorJson(err, w, r)
return
}
diff --git a/types/configs/connection.go b/types/configs/connection.go
index c2fb2d96..1067b068 100644
--- a/types/configs/connection.go
+++ b/types/configs/connection.go
@@ -20,6 +20,7 @@ import (
"time"
)
+// initModels sets the database for each Statping type packages
func initModels(db database.Database) {
core.SetDB(db)
services.SetDB(db)
@@ -67,6 +68,10 @@ func Connect(configs *DbConfig, retry bool) error {
log.Infoln(fmt.Sprintf("Database %s connection was successful.", configs.DbConn))
}
+ if utils.Params.GetBool("READ_ONLY") {
+ log.Warnln("Running in READ ONLY MODE")
+ }
+
configs.Db = dbSession
initModels(configs.Db)
@@ -74,7 +79,9 @@ func Connect(configs *DbConfig, retry bool) error {
return err
}
-func CreateAdminUser(c *DbConfig) error {
+// CreateAdminUser will create the default admin user "admin", "admin", or use the
+// environment variables ADMIN_USER, ADMIN_PASSWORD, and ADMIN_EMAIL if set.
+func CreateAdminUser() error {
adminUser := utils.Params.GetString("ADMIN_USER")
adminPass := utils.Params.GetString("ADMIN_PASSWORD")
adminEmail := utils.Params.GetString("ADMIN_EMAIL")
diff --git a/types/configs/file.go b/types/configs/file.go
index 9c71e075..87ff21e6 100644
--- a/types/configs/file.go
+++ b/types/configs/file.go
@@ -8,8 +8,9 @@ import (
"strings"
)
-var log = utils.Log
+var log = utils.Log.WithField("type", "configs")
+// ConnectConfigs will connect to the database and save the config.yml file
func ConnectConfigs(configs *DbConfig, retry bool) error {
err := Connect(configs, retry)
if err != nil {
@@ -21,6 +22,8 @@ func ConnectConfigs(configs *DbConfig, retry bool) error {
return nil
}
+// findDbFile will attempt to find the "statping.db" database file in the current
+// working directory, or from STATPING_DIR env.
func findDbFile(configs *DbConfig) (string, error) {
location := utils.Directory + "/" + SqliteFilename
if configs == nil {
@@ -37,6 +40,7 @@ func findDbFile(configs *DbConfig) (string, error) {
return location, nil
}
+// findSQLin walks the current walking directory for statping.db
func findSQLin(path string) (string, error) {
filename := SqliteFilename
var found []string
diff --git a/types/configs/migration.go b/types/configs/migration.go
index 976639b3..1a3704f4 100644
--- a/types/configs/migration.go
+++ b/types/configs/migration.go
@@ -38,7 +38,7 @@ func (d *DbConfig) ResetCore() error {
if err := d.CreateDatabase(); err != nil {
return errors.Wrap(err, "error creating database")
}
- if err := CreateAdminUser(d); err != nil {
+ if err := CreateAdminUser(); err != nil {
return errors.Wrap(err, "error creating default admin user")
}
if utils.Params.GetBool("SAMPLE_DATA") {
diff --git a/types/configs/struct.go b/types/configs/struct.go
index 93ec5ef6..c0f4741a 100644
--- a/types/configs/struct.go
+++ b/types/configs/struct.go
@@ -7,11 +7,11 @@ const SqliteFilename = "statping.db"
// DbConfig struct is used for the Db connection and creates the 'config.yml' file
type DbConfig struct {
DbConn string `yaml:"connection" json:"connection"`
- DbHost string `yaml:"host" json:"-"`
- DbUser string `yaml:"user" json:"-"`
- DbPass string `yaml:"password" json:"-"`
- DbData string `yaml:"database" json:"-"`
- DbPort int `yaml:"port" json:"-"`
+ DbHost string `yaml:"host,omitempty" json:"-"`
+ DbUser string `yaml:"user,omitempty" json:"-"`
+ DbPass string `yaml:"password,omitempty" json:"-"`
+ DbData string `yaml:"database,omitempty" json:"-"`
+ DbPort int `yaml:"port,omitempty" json:"-"`
ApiSecret string `yaml:"api_secret" json:"-"`
Language string `yaml:"language" json:"language"`
AllowReports bool `yaml:"allow_reports" json:"allow_reports"`
@@ -33,21 +33,21 @@ type DbConfig struct {
DemoMode bool `yaml:"demo_mode" json:"demo_mode"`
DisableLogs bool `yaml:"disable_logs" json:"disable_logs"`
UseAssets bool `yaml:"use_assets" json:"use_assets"`
- BasePath string `yaml:"base_path" json:"base_path"`
+ BasePath string `yaml:"base_path,omitempty" json:"base_path"`
- AdminUser string `yaml:"admin_user" json:"admin_user"`
- AdminPassword string `yaml:"admin_password" json:"admin_password"`
- AdminEmail string `yaml:"admin_email" json:"admin_email"`
+ AdminUser string `yaml:"admin_user,omitempty" json:"admin_user"`
+ AdminPassword string `yaml:"admin_password,omitempty" json:"admin_password"`
+ AdminEmail string `yaml:"admin_email,omitempty" json:"admin_email"`
- MaxOpenConnections int `yaml:"db_open_connections" json:"db_open_connections"`
- MaxIdleConnections int `yaml:"db_idle_connections" json:"db_idle_connections"`
- MaxLifeConnections int `yaml:"db_max_life_connections" json:"db_max_life_connections"`
+ MaxOpenConnections int `yaml:"db_open_connections,omitempty" json:"db_open_connections"`
+ MaxIdleConnections int `yaml:"db_idle_connections,omitempty" json:"db_idle_connections"`
+ MaxLifeConnections int `yaml:"db_max_life_connections,omitempty" json:"db_max_life_connections"`
SampleData bool `yaml:"sample_data" json:"sample_data"`
UseCDN bool `yaml:"use_cdn" json:"use_cdn"`
DisableColors bool `yaml:"disable_colors" json:"disable_colors"`
- PostgresSSLMode string `yaml:"postgres_ssl" json:"postgres_ssl"`
+ PostgresSSLMode string `yaml:"postgres_ssl,omitempty" json:"postgres_ssl"`
Db database.Database `yaml:"-" json:"-"`
}
diff --git a/utils/env.go b/utils/env.go
index d823fba0..a7bf9c12 100644
--- a/utils/env.go
+++ b/utils/env.go
@@ -30,6 +30,7 @@ func InitEnvs() {
Params.SetDefault("DEBUG", false)
Params.SetDefault("DEMO_MODE", false)
Params.SetDefault("DB_CONN", "")
+ Params.SetDefault("DB_DSN", "")
Params.SetDefault("DISABLE_LOGS", false)
Params.SetDefault("USE_ASSETS", false)
Params.SetDefault("BASE_PATH", "")
@@ -53,6 +54,7 @@ func InitEnvs() {
Params.SetDefault("LETSENCRYPT_EMAIL", "")
Params.SetDefault("LETSENCRYPT_LOCAL", false)
Params.SetDefault("LETSENCRYPT_ENABLE", false)
+ Params.SetDefault("READ_ONLY", false)
Params.SetDefault("LOGS_MAX_COUNT", 5)
Params.SetDefault("LOGS_MAX_AGE", 28)
Params.SetDefault("LOGS_MAX_SIZE", 16)
diff --git a/version.txt b/version.txt
index b102d03f..95684375 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-0.90.67
\ No newline at end of file
+0.90.68