diff --git a/Makefile b/Makefile index fdc895e1..93dbdcbb 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ XGO=xgo -go $(GOVERSION) --dest=build BUILDVERSION=-ldflags "-X main.VERSION=${VERSION} -X main.COMMIT=$(TRAVIS_COMMIT)" TRVIS_SECRET=CAVxMvW04wS/APA6QGjlWjLfTx5hc+TWwCKuBkMV2MioZSQGOTQBC4nITySUwepAFY25mI8zNV5oROOKzG0FxYvr2iIqKDkTTdVF1+XS2uyHfEKlsWMPErcqkGjRksDil75Pckz15uvvOYPndetK2QiamQkSf9U8dUJgzrPuV+UOFj6RO/kkEWhzmoyTdVdwIRKmiL8jINkvvFOWCAfg3WlBmucgYHHqjqeTn1kSeUJ+DV9lF8+ENq+74GZrnsq26UtskJexywDeFhhUYjWEvOFXQ19txB/JrvdZ2KSkYeuhHr1ZxlENSpQ/rySQqBvg7+XAl1RhQlL5V7/feXA+I/COqNYG5KqbDgeSUwGkZIumz1ITi24Lz4xATG5hnuRQkOIaO8/FGHAeQxU0JcdWlzS8M5RpvpN9tT12XSFDPYswFmkO+gGSEpu+2gSEbiaX7qocLLvZiMpkQxfOmItaUW5ZMXRvTWijhQTb2nyPOQ9JEabuAtAUrCwe7Enmc8P8ZasNZaJLJO53iQ8FyzrNFyAFwY5F87OQ/v3Hnjv0ADG8fDc4VUxlj8TweuRzETT8U2hchxqnK4BON2WMSj4d1V96pDuzb5fArtq5PTbI4VB7mZPriXYZEiKdfLEIufOYhg7uKdNRekMLkuJRr+ttH0Gyb+lILzSiHMHwxOH5bfM= PUBLISH_BODY='{ "request": { "branch": "master", "message": "Homebrew update version v${VERSION}", "config": { "env": { "VERSION": "${VERSION}", "COMMIT": "$(TRAVIS_COMMIT)" } } } }' -TRAVIS_BUILD_CMD='{ "request": { "branch": "master", "message": "Compile master for Statping v${VERSION}", "config": {"merge_mode": ["deep_merge"], "os": [ "linux" ], "language": "go", "go": [ "${GOVERSION}" ], "go_import_path": "github.com/hunterlong/statping", "install": true, "sudo": "required", "services": [ "docker" ], "env": { "VERSION": "${VERSION}" }, "matrix": { "allow_failures": [ { "go": "master" } ], "fast_finish": true }, "before_deploy": [ "git config --local user.name \"hunterlong\"", "git config --local user.email \"info@socialeck.com\"", "git tag v$(VERSION) --force"], "deploy": [ { "provider": "releases", "api_key": {"secret": "$(TRVIS_SECRET)"}, "file_glob": true, "file": "build/*", "skip_cleanup": true } ], "notifications": { "email": false }, "before_script": ["gem install sass"], "script": [ "travis_wait 30 docker pull crazymax/xgo:$(GOVERSION)", "make release" ], "after_success": [], "after_deploy": [ "make publish-homebrew" ] } } }' +TRAVIS_BUILD_CMD='{ "request": { "branch": "master", "message": "Compile master for Statping v${VERSION}", "config": { "os": [ "linux" ], "language": "go", "go": [ "${GOVERSION}" ], "go_import_path": "github.com/hunterlong/statping", "install": true, "sudo": "required", "services": [ "docker" ], "env": { "VERSION": "${VERSION}" }, "matrix": { "allow_failures": [ { "go": "master" } ], "fast_finish": true }, "before_deploy": [ "git config --local user.name \"hunterlong\"", "git config --local user.email \"info@socialeck.com\"", "git tag v$(VERSION) --force"], "deploy": [ { "provider": "releases", "api_key": {"secret": "$(TRVIS_SECRET)"}, "file_glob": true, "file": "build/*", "skip_cleanup": true, "on": {"branch": "master"} } ], "notifications": { "email": false }, "before_script": ["gem install sass"], "script": [ "travis_wait 30 docker pull crazymax/xgo:$(GOVERSION)", "make release" ], "after_success": [], "after_deploy": [ "make publish-homebrew" ] } } }' TEST_DIR=$(GOPATH)/src/github.com/hunterlong/statping PATH:=/usr/local/bin:$(GOPATH)/bin:$(PATH) diff --git a/cmd/cli.go b/cmd/cli.go index a798992f..f90f615b 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -88,17 +88,17 @@ func catchCLI(args []string) error { return err } fmt.Printf("Statping v%v Exporting Static 'index.html' page...\n", VERSION) - if core.Configs, err = core.LoadConfigFile(dir); err != nil { - utils.Log.Errorln("config.yml file not found") + if core.CoreApp.Config, err = core.LoadConfigFile(dir); err != nil { + log.Errorln("config.yml file not found") return err } indexSource := ExportIndexHTML() //core.CloseDB() if err = utils.SaveFile(dir+"/index.html", indexSource); err != nil { - utils.Log.Errorln(err) + log.Errorln(err) return err } - utils.Log.Infoln("Exported Statping index page: 'index.html'") + log.Infoln("Exported Statping index page: 'index.html'") case "help": HelpEcho() return errors.New("end") @@ -111,10 +111,10 @@ func catchCLI(args []string) error { if err = runAssets(); err != nil { return err } - if core.Configs, err = core.LoadConfigFile(dir); err != nil { + if core.CoreApp.Config, err = core.LoadConfigFile(dir); err != nil { return err } - if err = core.Configs.Connect(false, dir); err != nil { + if err = core.CoreApp.Connect(false, dir); err != nil { return err } if data, err = core.ExportSettings(); err != nil { @@ -147,7 +147,7 @@ func catchCLI(args []string) error { if err := runAssets(); err != nil { return err } - utils.Log.Infoln("Running 1 time and saving to database...") + log.Infoln("Running 1 time and saving to database...") runOnce() //core.CloseDB() fmt.Println("Check is complete.") @@ -162,7 +162,7 @@ func catchCLI(args []string) error { } envs, err := godotenv.Read(".env") if err != nil { - utils.Log.Errorln("No .env file found in current directory.") + log.Errorln("No .env file found in current directory.") return err } for k, e := range envs { @@ -177,7 +177,7 @@ func catchCLI(args []string) error { // ExportIndexHTML returns the HTML of the index page as a string func ExportIndexHTML() []byte { source.Assets() - core.Configs.Connect(false, utils.Directory) + core.CoreApp.Connect(false, utils.Directory) core.CoreApp.SelectAllServices(false) core.CoreApp.UseCdn = types.NewNullBool(true) for _, srv := range core.CoreApp.Services { @@ -208,13 +208,13 @@ func updateDisplay() error { // runOnce will initialize the Statping application and check each service 1 time, will not run HTTP server func runOnce() { var err error - core.Configs, err = core.LoadConfigFile(utils.Directory) + core.CoreApp.Config, err = core.LoadConfigFile(utils.Directory) if err != nil { - utils.Log.Errorln("config.yml file not found") + log.Errorln("config.yml file not found") } - err = core.Configs.Connect(false, utils.Directory) + err = core.CoreApp.Connect(false, utils.Directory) if err != nil { - utils.Log.Errorln(err) + log.Errorln(err) } core.CoreApp, err = core.SelectCore() if err != nil { @@ -222,7 +222,7 @@ func runOnce() { } _, err = core.CoreApp.SelectAllServices(true) if err != nil { - utils.Log.Errorln(err) + log.Errorln(err) } for _, out := range core.CoreApp.Services { out.Check(true) diff --git a/cmd/main.go b/cmd/main.go index 4772655e..f5fbe151 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -39,6 +39,7 @@ var ( envFile string verboseMode int port int + log = utils.Log.WithField("type", "cmd") ) func init() { @@ -52,7 +53,7 @@ func parseFlags() { flag.StringVar(&ipAddress, "ip", "0.0.0.0", "IP address to run the Statping HTTP server") flag.StringVar(&envFile, "env", "", "IP address to run the Statping HTTP server") flag.IntVar(&port, "port", 8080, "Port to run the HTTP server") - flag.IntVar(&verboseMode, "verbose", 1, "Run in verbose mode to see detailed logs (1 - 4)") + flag.IntVar(&verboseMode, "verbose", 2, "Run in verbose mode to see detailed logs (1 - 4)") flag.Parse() if os.Getenv("PORT") != "" { @@ -75,8 +76,7 @@ func main() { source.Assets() utils.VerboseMode = verboseMode if err := utils.InitLogs(); err != nil { - fmt.Printf("Statping Log Error: \n %v\n", err) - os.Exit(2) + log.Fatalln("Statping Log Error: \n %v\n", err) } args := flag.Args() @@ -90,16 +90,18 @@ func main() { os.Exit(1) } } - utils.Log.Info(fmt.Sprintf("Starting Statping v%v", VERSION)) + log.Info(fmt.Sprintf("Starting Statping v%v", VERSION)) updateDisplay() - core.Configs, err = core.LoadConfigFile(utils.Directory) + configs, err := core.LoadConfigFile(utils.Directory) if err != nil { - utils.Log.Errorln(err) + log.Errorln(err) core.SetupMode = true - utils.Log.Infoln(handlers.RunHTTPServer(ipAddress, port)) - os.Exit(1) + if err := handlers.RunHTTPServer(ipAddress, port); err != nil { + log.Fatalln(err) + } } + core.CoreApp.Config = configs mainProcess() } @@ -122,7 +124,7 @@ func sigterm() { func loadDotEnvs() error { err := godotenv.Load(envFile) if err == nil { - utils.Log.Infoln("Environment file '.env' Loaded") + log.Infoln("Environment file '.env' Loaded") } return err } @@ -131,15 +133,16 @@ func loadDotEnvs() error { func mainProcess() { dir := utils.Directory var err error - err = core.Configs.Connect(false, dir) + err = core.CoreApp.Connect(false, dir) if err != nil { - utils.Log.Errorln(fmt.Sprintf("could not connect to database: %v", err)) + log.Errorln(fmt.Sprintf("could not connect to database: %v", err)) } - core.Configs.MigrateDatabase() + core.CoreApp.MigrateDatabase() core.InitApp() if !core.SetupMode { plugin.LoadPlugins() - fmt.Println(handlers.RunHTTPServer(ipAddress, port)) - os.Exit(1) + if err := handlers.RunHTTPServer(ipAddress, port); err != nil { + log.Fatalln(err) + } } } diff --git a/core/configs.go b/core/configs.go index 9d6384cf..e268057d 100644 --- a/core/configs.go +++ b/core/configs.go @@ -31,12 +31,13 @@ type ErrorResponse struct { } // LoadConfigFile will attempt to load the 'config.yml' file in a specific directory -func LoadConfigFile(directory string) (*DbConfig, error) { - var configs *DbConfig +func LoadConfigFile(directory string) (*types.DbConfig, error) { + var configs *types.DbConfig if os.Getenv("DB_CONN") != "" { log.Infoln("DB_CONN environment variable was found, waiting for database...") return LoadUsingEnv() } + log.Debugln("attempting to read config file at: " + directory + "/config.yml") file, err := ioutil.ReadFile(directory + "/config.yml") if err != nil { return nil, errors.New("config.yml file not found at " + directory + "/config.yml - starting in setup mode") @@ -45,12 +46,13 @@ func LoadConfigFile(directory string) (*DbConfig, error) { if err != nil { return nil, err } - Configs = configs - return Configs, err + log.WithFields(utils.ToFields(configs)).Debugln("read config file: " + directory + "/config.yml") + CoreApp.Config = configs + return configs, err } // LoadUsingEnv will attempt to load database configs based on environment variables. If DB_CONN is set if will force this function. -func LoadUsingEnv() (*DbConfig, error) { +func LoadUsingEnv() (*types.DbConfig, error) { Configs, err := EnvToConfig() if err != nil { return Configs, err @@ -61,21 +63,20 @@ func LoadUsingEnv() (*DbConfig, error) { } else { CoreApp.Domain = os.Getenv("DOMAIN") } - CoreApp.DbConnection = Configs.DbConn CoreApp.UseCdn = types.NewNullBool(os.Getenv("USE_CDN") == "true") - err = Configs.Connect(true, utils.Directory) + err = CoreApp.Connect(true, utils.Directory) if err != nil { log.Errorln(err) return nil, err } - Configs.Save() + CoreApp.SaveConfig(Configs) exists := DbSession.HasTable("core") if !exists { log.Infoln(fmt.Sprintf("Core database does not exist, creating now!")) - Configs.DropDatabase() - Configs.CreateDatabase() - CoreApp, err = Configs.InsertCore() + CoreApp.DropDatabase() + CoreApp.CreateDatabase() + CoreApp, err = CoreApp.InsertCore(Configs) if err != nil { log.Errorln(err) } @@ -118,24 +119,23 @@ func DefaultPort(db string) int64 { } // EnvToConfig converts environment variables to a DbConfig variable -func EnvToConfig() (*DbConfig, error) { - Configs = new(DbConfig) +func EnvToConfig() (*types.DbConfig, error) { var err error if os.Getenv("DB_CONN") == "" { - return Configs, errors.New("Missing DB_CONN environment variable") + return nil, errors.New("Missing DB_CONN environment variable") } if os.Getenv("DB_CONN") != "sqlite" { if os.Getenv("DB_HOST") == "" { - return Configs, errors.New("Missing DB_HOST environment variable") + return nil, errors.New("Missing DB_HOST environment variable") } if os.Getenv("DB_USER") == "" { - return Configs, errors.New("Missing DB_USER environment variable") + return nil, errors.New("Missing DB_USER environment variable") } if os.Getenv("DB_PASS") == "" { - return Configs, errors.New("Missing DB_PASS environment variable") + return nil, errors.New("Missing DB_PASS environment variable") } if os.Getenv("DB_DATABASE") == "" { - return Configs, errors.New("Missing DB_DATABASE environment variable") + return nil, errors.New("Missing DB_DATABASE environment variable") } } port := utils.ToInt(os.Getenv("DB_PORT")) @@ -161,7 +161,7 @@ func EnvToConfig() (*DbConfig, error) { adminPass = "admin" } - Configs = &DbConfig{ + configs := &types.DbConfig{ DbConn: os.Getenv("DB_CONN"), DbHost: os.Getenv("DB_HOST"), DbUser: os.Getenv("DB_USER"), @@ -178,7 +178,8 @@ func EnvToConfig() (*DbConfig, error) { Location: utils.Directory, SqlFile: os.Getenv("SQL_FILE"), } - return Configs, err + CoreApp.Config = configs + return configs, err } // SampleData runs all the sample data for a new Statping installation @@ -194,7 +195,8 @@ func SampleData() error { // DeleteConfig will delete the 'config.yml' file func DeleteConfig() error { - err := os.Remove(utils.Directory + "/config.yml") + log.Debugln("deleting config yaml file", utils.Directory+"/config.yml") + err := utils.DeleteFile(utils.Directory + "/config.yml") if err != nil { log.Errorln(err) return err diff --git a/core/core.go b/core/core.go index 6fc985e2..433835db 100644 --- a/core/core.go +++ b/core/core.go @@ -36,10 +36,9 @@ type Core struct { } var ( - Configs *DbConfig // Configs holds all of the config.yml and database info - CoreApp *Core // CoreApp is a global variable that contains many elements - SetupMode bool // SetupMode will be true if Statping does not have a database connection - VERSION string // VERSION is set on build automatically by setting a -ldflag + CoreApp *Core // CoreApp is a global variable that contains many elements + SetupMode bool // SetupMode will be true if Statping does not have a database connection + VERSION string // VERSION is set on build automatically by setting a -ldflag log = utils.Log.WithField("type", "core") ) @@ -49,9 +48,10 @@ func init() { // NewCore return a new *core.Core struct func NewCore() *Core { - CoreApp = new(Core) - CoreApp.Core = new(types.Core) - CoreApp.Started = time.Now() + CoreApp = &Core{&types.Core{ + Started: time.Now(), + }, + } return CoreApp } @@ -69,12 +69,13 @@ func InitApp() { AttachNotifiers() CoreApp.Notifications = notifier.AllCommunications go DatabaseMaintence() + SetupMode = false } // InsertNotifierDB inject the Statping database instance to the Notifier package func InsertNotifierDB() error { if DbSession == nil { - err := Configs.Connect(false, utils.Directory) + err := CoreApp.Connect(false, utils.Directory) if err != nil { return errors.New("database connection has not been created") } @@ -159,7 +160,6 @@ func SelectCore() (*Core, error) { if db.Error != nil { return nil, db.Error } - CoreApp.DbConnection = Configs.DbConn CoreApp.Version = VERSION CoreApp.UseCdn = types.NewNullBool(os.Getenv("USE_CDN") == "true") return CoreApp, db.Error diff --git a/core/core_test.go b/core/core_test.go index 06b303b3..1461d00a 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -68,7 +68,7 @@ func TestLoadDbConfig(t *testing.T) { } func TestDbConnection(t *testing.T) { - err := Configs.Connect(false, dir) + err := CoreApp.Connect(false, dir) assert.Nil(t, err) } @@ -77,7 +77,7 @@ func TestDropDatabase(t *testing.T) { if skipNewDb { t.SkipNow() } - err := Configs.DropDatabase() + err := CoreApp.DropDatabase() assert.Nil(t, err) } @@ -86,13 +86,13 @@ func TestSeedSchemaDatabase(t *testing.T) { if skipNewDb { t.SkipNow() } - err := Configs.CreateDatabase() + err := CoreApp.CreateDatabase() assert.Nil(t, err) } func TestMigrateDatabase(t *testing.T) { t.SkipNow() - err := Configs.MigrateDatabase() + err := CoreApp.MigrateDatabase() assert.Nil(t, err) } @@ -103,9 +103,9 @@ func TestSeedDatabase(t *testing.T) { } func TestReLoadDbConfig(t *testing.T) { - err := Configs.Connect(false, dir) + err := CoreApp.Connect(false, dir) assert.Nil(t, err) - assert.Equal(t, "sqlite", Configs.DbConn) + assert.Equal(t, "sqlite", CoreApp.Config.DbConn) } func TestSelectCore(t *testing.T) { diff --git a/core/database.go b/core/database.go index 3c104545..81a27abf 100644 --- a/core/database.go +++ b/core/database.go @@ -101,7 +101,7 @@ func incidentsUpdatesDB() *gorm.DB { // HitsBetween returns the gorm database query for a collection of service hits between a time range func (s *Service) HitsBetween(t1, t2 time.Time, group string, column string) *gorm.DB { selector := Dbtimestamp(group, column) - if CoreApp.DbConnection == "postgres" { + if CoreApp.Config.DbConn == "postgres" { return hitsDB().Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME), t2.UTC().Format(types.TIME)) } else { return hitsDB().Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME_DAY), t2.UTC().Format(types.TIME_DAY)) @@ -171,24 +171,24 @@ func (u *Message) AfterFind() (err error) { } // InsertCore create the single row for the Core settings in Statping -func (db *DbConfig) InsertCore() (*Core, error) { +func (c *Core) InsertCore(db *types.DbConfig) (*Core, error) { CoreApp = &Core{Core: &types.Core{ Name: db.Project, Description: db.Description, - Config: "config.yml", + ConfigFile: "config.yml", ApiKey: utils.NewSHA1Hash(9), ApiSecret: utils.NewSHA1Hash(16), Domain: db.Domain, MigrationId: time.Now().Unix(), + Config: db, }} - CoreApp.DbConnection = db.DbConn query := coreDB().Create(&CoreApp) return CoreApp, query.Error } func findDbFile() string { - if Configs.SqlFile != "" { - return Configs.SqlFile + if CoreApp.Config.SqlFile != "" { + return CoreApp.Config.SqlFile } filename := types.SqliteFilename err := filepath.Walk(utils.Directory, func(path string, info os.FileInfo, err error) error { @@ -207,16 +207,16 @@ func findDbFile() string { } // Connect will attempt to connect to the sqlite, postgres, or mysql database -func (db *DbConfig) Connect(retry bool, location string) error { +func (c *Core) Connect(retry bool, location string) error { postgresSSL := os.Getenv("POSTGRES_SSLMODE") if DbSession != nil { return nil } var conn, dbType string var err error - dbType = Configs.DbConn - if Configs.DbPort == 0 { - Configs.DbPort = DefaultPort(dbType) + dbType = CoreApp.Config.DbConn + if CoreApp.Config.DbPort == 0 { + CoreApp.Config.DbPort = DefaultPort(dbType) } switch dbType { case "sqlite": @@ -224,27 +224,30 @@ func (db *DbConfig) Connect(retry bool, location string) error { conn = sqlFilename dbType = "sqlite3" case "mysql": - host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort) - conn = fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8&parseTime=True&loc=UTC&time_zone=%%27UTC%%27", Configs.DbUser, Configs.DbPass, host, Configs.DbData) + host := fmt.Sprintf("%v:%v", CoreApp.Config.DbHost, CoreApp.Config.DbPort) + conn = fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8&parseTime=True&loc=UTC&time_zone=%%27UTC%%27", CoreApp.Config.DbUser, CoreApp.Config.DbPass, host, CoreApp.Config.DbData) case "postgres": sslMode := "disable" if postgresSSL != "" { sslMode = postgresSSL } - conn = fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v timezone=UTC sslmode=%v", Configs.DbHost, Configs.DbPort, Configs.DbUser, Configs.DbData, Configs.DbPass, sslMode) + conn = fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v timezone=UTC sslmode=%v", CoreApp.Config.DbHost, CoreApp.Config.DbPort, CoreApp.Config.DbUser, CoreApp.Config.DbData, CoreApp.Config.DbPass, sslMode) case "mssql": - host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort) - conn = fmt.Sprintf("sqlserver://%v:%v@%v?database=%v", Configs.DbUser, Configs.DbPass, host, Configs.DbData) + host := fmt.Sprintf("%v:%v", CoreApp.Config.DbHost, CoreApp.Config.DbPort) + conn = fmt.Sprintf("sqlserver://%v:%v@%v?database=%v", CoreApp.Config.DbUser, CoreApp.Config.DbPass, host, CoreApp.Config.DbData) } + log.WithFields(utils.ToFields(c, conn)).Debugln("attempting to connect to database") dbSession, err := gorm.Open(dbType, conn) if err != nil { + log.Debugln(fmt.Sprintf("Database connection error %v", err)) if retry { - log.Infoln(fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", Configs.DbHost)) - return db.waitForDb() + log.Errorln(fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", CoreApp.Config.DbHost)) + return c.waitForDb() } else { return err } } + log.WithFields(utils.ToFields(dbSession)).Debugln("connected to database") if dbType == "sqlite3" { dbSession.DB().SetMaxOpenConns(1) } @@ -259,9 +262,9 @@ func (db *DbConfig) Connect(retry bool, location string) error { } // waitForDb will sleep for 5 seconds and try to connect to the database again -func (db *DbConfig) waitForDb() error { +func (c *Core) waitForDb() error { time.Sleep(5 * time.Second) - return db.Connect(true, utils.Directory) + return c.Connect(true, utils.Directory) } // DatabaseMaintence will automatically delete old records from 'failures' and 'hits' @@ -285,14 +288,14 @@ func DeleteAllSince(table string, date time.Time) { } // Update will save the config.yml file -func (db *DbConfig) Update() error { +func (c *Core) UpdateConfig() error { var err error config, err := os.Create(utils.Directory + "/config.yml") if err != nil { log.Errorln(err) return err } - data, err := yaml.Marshal(db) + data, err := yaml.Marshal(c.Config) if err != nil { log.Errorln(err) return err @@ -303,30 +306,33 @@ func (db *DbConfig) Update() error { } // Save will initially create the config.yml file -func (db *DbConfig) Save() (*DbConfig, error) { +func (c *Core) SaveConfig(configs *types.DbConfig) (*types.DbConfig, error) { config, err := os.Create(utils.Directory + "/config.yml") - defer config.Close() if err != nil { log.Errorln(err) return nil, err } - db.ApiKey = utils.NewSHA1Hash(16) - db.ApiSecret = utils.NewSHA1Hash(16) - data, err := yaml.Marshal(db) + defer config.Close() + log.WithFields(utils.ToFields(configs)).Debugln("saving config file at: " + utils.Directory + "/config.yml") + c.Config = configs + c.Config.ApiKey = utils.NewSHA1Hash(16) + c.Config.ApiSecret = utils.NewSHA1Hash(16) + data, err := yaml.Marshal(configs) if err != nil { log.Errorln(err) return nil, err } config.WriteString(string(data)) - return db, err + log.WithFields(utils.ToFields(configs)).Infoln("saved config file at: " + utils.Directory + "/config.yml") + return c.Config, err } // CreateCore will initialize the global variable 'CoreApp". This global variable contains most of Statping app. -func (c *DbConfig) CreateCore() *Core { +func (c *Core) CreateCore() *Core { newCore := &types.Core{ - Name: c.Project, + Name: c.Name, Description: c.Description, - Config: "config.yml", + ConfigFile: utils.Directory + "/config.yml", ApiKey: c.ApiKey, ApiSecret: c.ApiSecret, Domain: c.Domain, @@ -344,7 +350,7 @@ func (c *DbConfig) CreateCore() *Core { } // DropDatabase will DROP each table Statping created -func (db *DbConfig) DropDatabase() error { +func (c *Core) DropDatabase() error { log.Infoln("Dropping Database Tables...") err := DbSession.DropTableIfExists("checkins") err = DbSession.DropTableIfExists("checkin_hits") @@ -361,7 +367,7 @@ func (db *DbConfig) DropDatabase() error { } // CreateDatabase will CREATE TABLES for each of the Statping elements -func (db *DbConfig) CreateDatabase() error { +func (c *Core) CreateDatabase() error { var err error log.Infoln("Creating Database Tables...") for _, table := range DbModels { @@ -379,7 +385,7 @@ func (db *DbConfig) CreateDatabase() error { // MigrateDatabase will migrate the database structure to current version. // This function will NOT remove previous records, tables or columns from the database. // If this function has an issue, it will ROLLBACK to the previous state. -func (db *DbConfig) MigrateDatabase() error { +func (c *Core) MigrateDatabase() error { log.Infoln("Migrating Database Tables...") tx := DbSession.Begin() defer func() { diff --git a/core/sample.go b/core/sample.go index 70a6761c..55bd8e13 100644 --- a/core/sample.go +++ b/core/sample.go @@ -506,18 +506,18 @@ func TmpRecords(dbFile string) error { var err error CoreApp = NewCore() CoreApp.Name = "Tester" - Configs = &DbConfig{ + configs := &types.DbConfig{ DbConn: "sqlite", Project: "Tester", Location: utils.Directory, SqlFile: sqlFile, } log.Infoln("saving config.yml in: " + utils.Directory) - if Configs, err = Configs.Save(); err != nil { + if configs, err = CoreApp.SaveConfig(configs); err != nil { return err } log.Infoln("loading config.yml from: " + utils.Directory) - if Configs, err = LoadConfigFile(utils.Directory); err != nil { + if configs, err = LoadConfigFile(utils.Directory); err != nil { return err } log.Infoln("connecting to database") @@ -533,7 +533,7 @@ func TmpRecords(dbFile string) error { } log.Infoln("loading config.yml from: " + utils.Directory) - if err := Configs.Connect(false, utils.Directory); err != nil { + if err := CoreApp.Connect(false, utils.Directory); err != nil { return err } log.Infoln("selecting the Core variable") @@ -557,15 +557,15 @@ func TmpRecords(dbFile string) error { log.Infoln(tmpSqlFile + " not found, creating a new database...") - if err := Configs.Connect(false, utils.Directory); err != nil { + if err := CoreApp.Connect(false, utils.Directory); err != nil { return err } log.Infoln("creating database") - if err := Configs.CreateDatabase(); err != nil { + if err := CoreApp.CreateDatabase(); err != nil { return err } log.Infoln("migrating database") - if err := Configs.MigrateDatabase(); err != nil { + if err := CoreApp.MigrateDatabase(); err != nil { return err } log.Infoln("insert large sample data into database") diff --git a/core/services.go b/core/services.go index e26a1997..32d14eb0 100644 --- a/core/services.go +++ b/core/services.go @@ -240,7 +240,7 @@ func Dbtimestamp(group string, column string) string { default: seconds = 60 } - switch CoreApp.DbConnection { + switch CoreApp.Config.DbConn { case "mysql": return fmt.Sprintf("CONCAT(date_format(created_at, '%%Y-%%m-%%d %%H:00:00')) AS timeframe, AVG(%v) AS value", column) case "postgres": @@ -281,7 +281,7 @@ func GraphDataRaw(service types.ServiceInterface, start, end time.Time, group st var createdTime time.Time var err error rows.Scan(&createdAt, &value) - if CoreApp.DbConnection == "postgres" { + if CoreApp.Config.DbConn == "postgres" { createdTime, err = time.Parse(types.TIME_NANO, createdAt) if err != nil { log.Errorln(fmt.Errorf("issue parsing time from database: %v to %v", createdAt, types.TIME_NANO)) diff --git a/core/services_test.go b/core/services_test.go index 245a0ea3..728c2f7d 100644 --- a/core/services_test.go +++ b/core/services_test.go @@ -350,13 +350,13 @@ func TestSelectServiceLink(t *testing.T) { } func TestDbtimestamp(t *testing.T) { - CoreApp.DbConnection = "mysql" + CoreApp.Config.DbConn = "mysql" query := Dbtimestamp("minute", "latency") assert.Equal(t, "CONCAT(date_format(created_at, '%Y-%m-%d %H:00:00')) AS timeframe, AVG(latency) AS value", query) - CoreApp.DbConnection = "postgres" + CoreApp.Config.DbConn = "postgres" query = Dbtimestamp("minute", "latency") assert.Equal(t, "date_trunc('minute', created_at) AS timeframe, AVG(latency) AS value", query) - CoreApp.DbConnection = "sqlite" + CoreApp.Config.DbConn = "sqlite" query = Dbtimestamp("minute", "latency") assert.Equal(t, "datetime((strftime('%s', created_at) / 60) * 60, 'unixepoch') AS timeframe, AVG(latency) as value", query) } diff --git a/handlers/handlers.go b/handlers/handlers.go index 14e5abb9..e54bcaee 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -104,6 +104,9 @@ func RunHTTPServer(ip string, port int) error { // IsReadAuthenticated will allow Read Only authentication for some routes func IsReadAuthenticated(r *http.Request) bool { + if core.SetupMode { + return false + } var token string query := r.URL.Query() key := query.Get("api") @@ -130,6 +133,9 @@ func IsFullAuthenticated(r *http.Request) bool { if core.CoreApp == nil { return true } + if core.SetupMode { + return false + } if sessionStore == nil { return true } @@ -147,6 +153,9 @@ func IsFullAuthenticated(r *http.Request) bool { // IsAdmin returns true if the user session is an administrator func IsAdmin(r *http.Request) bool { + if core.SetupMode { + return false + } session, err := sessionStore.Get(r, cookieKey) if err != nil { return false @@ -159,6 +168,9 @@ func IsAdmin(r *http.Request) bool { // IsUser returns true if the user is registered func IsUser(r *http.Request) bool { + if core.SetupMode { + return false + } if os.Getenv("GO_ENV") == "test" { return true } diff --git a/handlers/index.go b/handlers/index.go index 1b04301d..183ebd36 100644 --- a/handlers/index.go +++ b/handlers/index.go @@ -21,7 +21,7 @@ import ( ) func indexHandler(w http.ResponseWriter, r *http.Request) { - if core.Configs == nil { + if core.CoreApp.Config == nil { http.Redirect(w, r, "/setup", http.StatusSeeOther) return } @@ -32,7 +32,7 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) { health := map[string]interface{}{ "services": len(core.Services()), "online": true, - "setup": core.Configs != nil, + "setup": core.CoreApp.Config != nil, } returnJson(health, w, r) } diff --git a/handlers/middleware.go b/handlers/middleware.go index 5bc014c3..96ad7502 100644 --- a/handlers/middleware.go +++ b/handlers/middleware.go @@ -15,6 +15,9 @@ func sendLog(handler func(w http.ResponseWriter, r *http.Request)) http.Handler t1 := utils.Now() handler(w, r) t2 := utils.Now().Sub(t1) + if r.RequestURI == "/logs/line" { + return + } log.WithFields(utils.ToFields(w, r)). WithField("url", r.RequestURI). WithField("method", r.Method). @@ -59,7 +62,7 @@ func cached(duration, contentType string, handler func(w http.ResponseWriter, r content := CacheStorage.Get(r.RequestURI) w.Header().Set("Content-Type", contentType) w.Header().Set("Access-Control-Allow-Origin", "*") - if core.Configs == nil { + if core.CoreApp.Config == nil { handler(w, r) return } diff --git a/handlers/routes.go b/handlers/routes.go index e769c9e7..276a598d 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -38,7 +38,7 @@ func Router() *mux.Router { dir := utils.Directory CacheStorage = NewStorage() r := mux.NewRouter() - r.Handle("/", http.HandlerFunc(indexHandler)) + r.Handle("/", sendLog(indexHandler)) if source.UsingAssets(dir) { indexHandler := http.FileServer(http.Dir(dir + "/assets/")) r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(http.Dir(dir+"/assets/css")))) @@ -55,9 +55,9 @@ func Router() *mux.Router { r.PathPrefix("/favicon.ico").Handler(http.FileServer(source.TmplBox.HTTPBox())) r.PathPrefix("/banner.png").Handler(http.FileServer(source.TmplBox.HTTPBox())) } - r.Handle("/charts.js", http.HandlerFunc(renderServiceChartsHandler)) - r.Handle("/setup", http.HandlerFunc(setupHandler)).Methods("GET") - r.Handle("/setup", http.HandlerFunc(processSetupHandler)).Methods("POST") + r.Handle("/charts.js", sendLog(renderServiceChartsHandler)) + r.Handle("/setup", sendLog(setupHandler)).Methods("GET") + r.Handle("/setup", sendLog(processSetupHandler)).Methods("POST") r.Handle("/dashboard", sendLog(dashboardHandler)).Methods("GET") r.Handle("/dashboard", sendLog(loginHandler)).Methods("POST") r.Handle("/logout", sendLog(logoutHandler)) diff --git a/handlers/setup.go b/handlers/setup.go index d6f4df9e..b4f94739 100644 --- a/handlers/setup.go +++ b/handlers/setup.go @@ -39,7 +39,7 @@ func setupHandler(w http.ResponseWriter, r *http.Request) { func processSetupHandler(w http.ResponseWriter, r *http.Request) { var err error - if core.Services() != nil { + if !core.SetupMode { http.Redirect(w, r, "/", http.StatusSeeOther) return } @@ -57,10 +57,9 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { domain := r.PostForm.Get("domain") email := r.PostForm.Get("email") sample := r.PostForm.Get("sample_data") == "on" - log.Warnln(sample) dir := utils.Directory - config := &core.DbConfig{ + config := &types.DbConfig{ DbConn: dbConn, DbHost: dbHost, DbUser: dbUser, @@ -77,21 +76,23 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { Location: utils.Directory, } - if core.Configs, err = config.Save(); err != nil { + log.WithFields(utils.ToFields(core.CoreApp, config)).Debugln("new configs posted") + + if _, err := core.CoreApp.SaveConfig(config); err != nil { log.Errorln(err) config.Error = err setupResponseError(w, r, config) return } - if core.Configs, err = core.LoadConfigFile(dir); err != nil { + if _, err = core.LoadConfigFile(dir); err != nil { log.Errorln(err) config.Error = err setupResponseError(w, r, config) return } - if err = core.Configs.Connect(false, dir); err != nil { + if err = core.CoreApp.Connect(false, dir); err != nil { log.Errorln(err) core.DeleteConfig() config.Error = err @@ -99,10 +100,10 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { return } - config.DropDatabase() - config.CreateDatabase() + core.CoreApp.DropDatabase() + core.CoreApp.CreateDatabase() - core.CoreApp, err = config.InsertCore() + core.CoreApp, err = core.CoreApp.InsertCore(config) if err != nil { log.Errorln(err) config.Error = err diff --git a/source/tmpl/services.gohtml b/source/tmpl/services.gohtml index 440e4e7e..bd50a7a7 100644 --- a/source/tmpl/services.gohtml +++ b/source/tmpl/services.gohtml @@ -4,6 +4,15 @@ {{template "nav"}}