diff --git a/.travis.yml b/.travis.yml index 0366ad32..494c1c04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,6 +43,7 @@ notifications: os: - linux script: + - "make clean newman" - "if [[ \"$TRAVIS_BRANCH\" == \"dev\" && \"$TRAVIS_PULL_REQUEST\" = \"false\" ]]; then make dockerhub-dev; fi" - "travis_retry make clean test-ci" - "if [[ \"$TRAVIS_BRANCH\" == \"master\" && \"$TRAVIS_PULL_REQUEST\" = \"false\" ]]; then make coverage; fi" diff --git a/CHANGELOG.md b/CHANGELOG.md index 528abcc1..5ab7c430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.90.28 (04-16-2020) +- Fixed postgres timestamp grouping +- Added postman (newman) API testing +- Added Viper and Cobra config/env parsing package + # 0.90.27 (04-15-2020) - Fixed postgres database table creation process - Modified go build process, additional ARCHs diff --git a/Makefile b/Makefile index 951ce516..ba7ac977 100644 --- a/Makefile +++ b/Makefile @@ -291,5 +291,11 @@ snapcraft: clean compile build-bin snapcraft push statping_${VERSION}_i386.snap --release stable snapcraft push statping_${VERSION}_armhf.snap --release stable -.PHONY: all build build-all build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-bin build-win build-all +postman: clean + API_SECRET=demosecret123 statping -p=8080 > /dev/null & + sleep 3 + newman run -e dev/postman_environment.json dev/postman.json + killall statping + +.PHONY: all build build-all build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-bin build-win build-all postman .SILENT: travis_s3_creds diff --git a/cmd/cli.go b/cmd/cli.go index a5bfbdc2..8c61cf8c 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -4,7 +4,6 @@ import ( "bufio" "encoding/json" "fmt" - "github.com/joho/godotenv" "github.com/pkg/errors" "github.com/statping/statping/handlers" "github.com/statping/statping/source" @@ -18,209 +17,158 @@ import ( "time" ) -// catchCLI will run functions based on the commands sent to Statping -func catchCLI(args []string) error { +func assetsCli() error { dir := utils.Directory - runLogs := utils.InitLogs - runAssets := source.Assets + if err := utils.InitLogs(); err != nil { + return err + } + if err := source.Assets(); err != nil { + return err + } + if err := source.CreateAllAssets(dir); err != nil { + return err + } + return nil +} - switch args[0] { - case "version": - if COMMIT != "" { - fmt.Printf("%s (%s)\n", VERSION, COMMIT) - } else { - fmt.Printf("%s\n", VERSION) - } - return errors.New("end") - case "assets": - var err error - if err = runLogs(); err != nil { - return err - } - if err = runAssets(); err != nil { - return err - } - if err = source.CreateAllAssets(dir); err != nil { - return err - } - return errors.New("end") - case "sass": - if err := runLogs(); err != nil { - return err - } - if err := runAssets(); err != nil { - return err - } - if err := source.CompileSASS(source.DefaultScss...); err != nil { - return err - } - return errors.New("end") - case "update": - updateDisplay() - return errors.New("end") - case "static": - //var err error - //if err = runLogs(); err != nil { - // return err - //} - //if err = runAssets(); err != nil { - // return err - //} - //fmt.Printf("Statping v%v Exporting Static 'index.html' page...\n", VERSION) - //if _, 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 { - // log.Errorln(err) - // return err - //} - //log.Infoln("Exported Statping index page: 'index.html'") - case "help": - HelpEcho() - return errors.New("end") - case "export": - var err error - var data []byte - if err = runLogs(); err != nil { - return err - } - if err = runAssets(); err != nil { - return err - } - config, err := configs.LoadConfigs() - if err != nil { - return err - } - if err = configs.ConnectConfigs(config); err != nil { - return err - } - if _, err := services.SelectAllServices(false); err != nil { - return err - } - if data, err = handlers.ExportSettings(); err != nil { - return fmt.Errorf("could not export settings: %v", err.Error()) - } - filename := fmt.Sprintf("%s/statping-%s.json", dir, time.Now().Format("01-02-2006-1504")) - if err = utils.SaveFile(filename, data); err != nil { - return fmt.Errorf("could not write file statping-export.json: %v", err.Error()) - } - log.Infoln("Statping export file saved to ", filename) - return errors.New("end") - case "import": - var err error - var data []byte - if len(args) != 2 { - return fmt.Errorf("did not include a JSON file to import\nstatping import filename.json") - } - filename := args[1] - if data, err = ioutil.ReadFile(filename); err != nil { - return err - } - var exportData handlers.ExportData - if err = json.Unmarshal(data, &exportData); err != nil { - return err - } - log.Printf("=== %s ===\n", exportData.Core.Name) - log.Printf("Services: %d\n", len(exportData.Services)) - log.Printf("Checkins: %d\n", len(exportData.Checkins)) - log.Printf("Groups: %d\n", len(exportData.Groups)) - log.Printf("Messages: %d\n", len(exportData.Messages)) - log.Printf("Users: %d\n", len(exportData.Users)) +func exportCli(args []string) error { + filename := fmt.Sprintf("%s/statping-%s.json", utils.Directory, time.Now().Format("01-02-2006-1504")) + if len(args) == 1 { + filename = fmt.Sprintf("%s/%s", utils.Directory, args) + } + var data []byte + if err := utils.InitLogs(); err != nil { + return err + } + if err := source.Assets(); err != nil { + return err + } + config, err := configs.LoadConfigs() + if err != nil { + return err + } + if err = configs.ConnectConfigs(config); err != nil { + return err + } + if _, err := services.SelectAllServices(false); err != nil { + return err + } + if data, err = handlers.ExportSettings(); err != nil { + return fmt.Errorf("could not export settings: %v", err.Error()) + } + if err = utils.SaveFile(filename, data); err != nil { + return fmt.Errorf("could not write file statping-export.json: %v", err.Error()) + } + log.Infoln("Statping export file saved to ", filename) + return nil +} - config, err := configs.LoadConfigs() - if err != nil { - return err - } - if err = configs.ConnectConfigs(config); err != nil { - return err - } - if data, err = handlers.ExportSettings(); err != nil { - return fmt.Errorf("could not export settings: %v", err.Error()) - } +func sassCli() error { + if err := utils.InitLogs(); err != nil { + return err + } + if err := source.Assets(); err != nil { + return err + } + if err := source.CompileSASS(source.DefaultScss...); err != nil { + return err + } + return nil +} - if ask("Import Core settings?") { - c := exportData.Core - if err := c.Update(); err != nil { +func onceCli() error { + if err := utils.InitLogs(); err != nil { + return err + } + if err := source.Assets(); err != nil { + return err + } + log.Infoln("Running 1 time and saving to database...") + if err := runOnce(); err != nil { + return err + } + //core.CloseDB() + fmt.Println("Check is complete.") + return nil +} + +func importCli(args []string) error { + var err error + var data []byte + filename := args[1] + if data, err = ioutil.ReadFile(filename); err != nil { + return err + } + var exportData handlers.ExportData + if err = json.Unmarshal(data, &exportData); err != nil { + return err + } + log.Printf("=== %s ===\n", exportData.Core.Name) + log.Printf("Services: %d\n", len(exportData.Services)) + log.Printf("Checkins: %d\n", len(exportData.Checkins)) + log.Printf("Groups: %d\n", len(exportData.Groups)) + log.Printf("Messages: %d\n", len(exportData.Messages)) + log.Printf("Users: %d\n", len(exportData.Users)) + + config, err := configs.LoadConfigs() + if err != nil { + return err + } + if err = configs.ConnectConfigs(config); err != nil { + return err + } + if data, err = handlers.ExportSettings(); err != nil { + return fmt.Errorf("could not export settings: %v", err.Error()) + } + + if ask("Import Core settings?") { + c := exportData.Core + if err := c.Update(); err != nil { + return err + } + } + for _, s := range exportData.Groups { + if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) { + s.Id = 0 + if err := s.Create(); err != nil { return err } } - for _, s := range exportData.Groups { - if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) { - s.Id = 0 - if err := s.Create(); err != nil { - return err - } - } - } - for _, s := range exportData.Services { - if ask(fmt.Sprintf("Import Service '%s'?", s.Name)) { - s.Id = 0 - if err := s.Create(); err != nil { - return err - } - } - } - for _, s := range exportData.Checkins { - if ask(fmt.Sprintf("Import Checkin '%s'?", s.Name)) { - s.Id = 0 - if err := s.Create(); err != nil { - return err - } - } - } - for _, s := range exportData.Messages { - if ask(fmt.Sprintf("Import Message '%s'?", s.Title)) { - s.Id = 0 - if err := s.Create(); err != nil { - return err - } - } - } - for _, s := range exportData.Users { - if ask(fmt.Sprintf("Import User '%s'?", s.Username)) { - s.Id = 0 - if err := s.Create(); err != nil { - return err - } - } - } - log.Infof("Import complete") - return errors.New("end") - case "run": - if err := runLogs(); err != nil { - return err - } - if err := runAssets(); err != nil { - return err - } - log.Infoln("Running 1 time and saving to database...") - runOnce() - //core.CloseDB() - fmt.Println("Check is complete.") - return errors.New("end") - case "env": - fmt.Println("Statping Environment Variable") - if err := runLogs(); err != nil { - return err - } - if err := runAssets(); err != nil { - return err - } - envs, err := godotenv.Read(".env") - if err != nil { - log.Errorln("No .env file found in current directory.") - return err - } - for k, e := range envs { - fmt.Printf("%v=%v\n", k, e) - } - default: - return nil } - return errors.New("end") + for _, s := range exportData.Services { + if ask(fmt.Sprintf("Import Service '%s'?", s.Name)) { + s.Id = 0 + if err := s.Create(); err != nil { + return err + } + } + } + for _, s := range exportData.Checkins { + if ask(fmt.Sprintf("Import Checkin '%s'?", s.Name)) { + s.Id = 0 + if err := s.Create(); err != nil { + return err + } + } + } + for _, s := range exportData.Messages { + if ask(fmt.Sprintf("Import Message '%s'?", s.Title)) { + s.Id = 0 + if err := s.Create(); err != nil { + return err + } + } + } + for _, s := range exportData.Users { + if ask(fmt.Sprintf("Import User '%s'?", s.Username)) { + s.Id = 0 + if err := s.Create(); err != nil { + return err + } + } + } + log.Infof("Import complete") + return nil } func ask(format string) bool { diff --git a/cmd/cli_test.go b/cmd/cli_test.go index 343d1102..f0a05a62 100644 --- a/cmd/cli_test.go +++ b/cmd/cli_test.go @@ -1,10 +1,12 @@ package main import ( + "bytes" "github.com/rendon/testcli" "github.com/statping/statping/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "io/ioutil" "os" "os/exec" "testing" @@ -22,7 +24,6 @@ func init() { func TestStartServerCommand(t *testing.T) { t.SkipNow() - os.Setenv("DB_CONN", "sqlite") cmd := helperCommand(nil, "") var got = make(chan string) commandAndSleep(cmd, time.Duration(60*time.Second), got) @@ -116,13 +117,25 @@ func TestEnvironmentVarsCommand(t *testing.T) { } func TestVersionCLI(t *testing.T) { - run := catchCLI([]string{"version"}) - assert.EqualError(t, run, "end") + cmd := rootCmd + b := bytes.NewBufferString("") + cmd.SetOut(b) + cmd.SetArgs([]string{"version"}) + cmd.Execute() + out, err := ioutil.ReadAll(b) + assert.Nil(t, err) + assert.Contains(t, string(out), VERSION) } func TestAssetsCLI(t *testing.T) { - catchCLI([]string{"assets"}) - //assert.EqualError(t, run, "end") + cmd := rootCmd + b := bytes.NewBufferString("") + cmd.SetOut(b) + cmd.SetArgs([]string{"assets"}) + cmd.Execute() + out, err := ioutil.ReadAll(b) + assert.Nil(t, err) + assert.Contains(t, string(out), VERSION) assert.FileExists(t, dir+"/assets/css/main.css") assert.FileExists(t, dir+"/assets/css/style.css") assert.FileExists(t, dir+"/assets/css/vendor.css") @@ -132,8 +145,9 @@ func TestAssetsCLI(t *testing.T) { } func TestSassCLI(t *testing.T) { - t.SkipNow() - catchCLI([]string{"sass"}) + c := testcli.Command("statping", "assets") + c.Run() + t.Log(c.Stdout()) assert.FileExists(t, dir+"/assets/css/main.css") assert.FileExists(t, dir+"/assets/css/style.css") assert.FileExists(t, dir+"/assets/css/vendor.css") @@ -149,22 +163,6 @@ func TestUpdateCLI(t *testing.T) { assert.Contains(t, gg, "version") } -func TestHelpCLI(t *testing.T) { - run := catchCLI([]string{"help"}) - assert.EqualError(t, run, "end") -} - -func TestRunOnceCLI(t *testing.T) { - t.SkipNow() - run := catchCLI([]string{"run"}) - assert.EqualError(t, run, "end") -} - -func TestEnvCLI(t *testing.T) { - run := catchCLI([]string{"env"}) - assert.Error(t, run) -} - func commandAndSleep(cmd *exec.Cmd, duration time.Duration, out chan<- string) { go func(out chan<- string) { runCommand(cmd, out) diff --git a/cmd/commands.go b/cmd/commands.go new file mode 100644 index 00000000..a37d2523 --- /dev/null +++ b/cmd/commands.go @@ -0,0 +1,79 @@ +package main + +import ( + "fmt" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "statping", + Short: "A simple Application Status Monitor that is opensource and lightweight.", + Run: func(cmd *cobra.Command, args []string) { + start() + }, +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number of Statping", + Run: func(cmd *cobra.Command, args []string) { + if COMMIT != "" { + fmt.Printf("%s (%s)\n", VERSION, COMMIT) + } else { + fmt.Printf("%s\n", VERSION) + } + }, +} + +var assetsCmd = &cobra.Command{ + Use: "assets", + Short: "Dump all assets used locally to be edited", + RunE: func(cmd *cobra.Command, args []string) error { + return assetsCli() + }, +} + +var exportCmd = &cobra.Command{ + Use: "export", + Short: "Exports your Statping settings to a 'statping-export.json' file.", + RunE: func(cmd *cobra.Command, args []string) error { + return exportCli(args) + }, +} + +var sassCmd = &cobra.Command{ + Use: "sass", + Short: "Compile .scss files into the css directory", + RunE: func(cmd *cobra.Command, args []string) error { + return sassCli() + }, +} + +var onceCmd = &cobra.Command{ + Use: "once", + Short: "Check all services 1 time and then quit", + RunE: func(cmd *cobra.Command, args []string) error { + return onceCli() + }, +} + +var importCmd = &cobra.Command{ + Use: "import [.json file]", + Short: "Imports settings from a previously saved JSON file.", + RunE: func(cmd *cobra.Command, args []string) error { + return importCli(args) + }, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("requires input file (.json)") + } + return nil + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + exit(err) + } +} diff --git a/cmd/main.go b/cmd/main.go index 674d3fde..dcf4f3c9 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,7 +1,6 @@ package main import ( - "flag" "fmt" "github.com/pkg/errors" "github.com/statping/statping/database" @@ -31,26 +30,16 @@ var ( confgs *configs.DbConfig ) -// parseFlags will parse the application flags -// -ip = 0.0.0.0 IP address for outgoing HTTP server -// -port = 8080 Port number for outgoing HTTP server -// environment variables WILL overwrite flags -func parseFlags() { - envPort := utils.Getenv("PORT", 8080).(int) - envIpAddress := utils.Getenv("IP", "0.0.0.0").(string) - envVerbose := utils.Getenv("VERBOSE", 2).(int) - //envGrpcPort := utils.Getenv("GRPC_PORT", 0).(int) - - flag.StringVar(&ipAddress, "ip", envIpAddress, "IP address to run the Statping HTTP server") - flag.StringVar(&envFile, "env", "", "IP address to run the Statping HTTP server") - flag.IntVar(&port, "port", envPort, "Port to run the HTTP server") - //flag.IntVar(&grpcPort, "grpc", envGrpcPort, "Port to run the gRPC server") - flag.IntVar(&verboseMode, "verbose", envVerbose, "Run in verbose mode to see detailed logs (1 - 4)") - flag.Parse() -} - func init() { core.New(VERSION) + utils.InitCLI() + parseFlags(rootCmd) + rootCmd.AddCommand(versionCmd) + rootCmd.AddCommand(assetsCmd) + rootCmd.AddCommand(exportCmd) + rootCmd.AddCommand(importCmd) + rootCmd.AddCommand(sassCmd) + rootCmd.AddCommand(onceCmd) } // exit will return an error and return an exit code 1 due to this error @@ -69,11 +58,14 @@ func Close() { // main will run the Statping application func main() { + Execute() +} + +// main will run the Statping application +func start() { var err error go sigterm() - parseFlags() - if err := source.Assets(); err != nil { exit(err) } @@ -84,23 +76,11 @@ func main() { log.Errorf("Statping Log Error: %v\n", err) } - args := flag.Args() - - if len(args) >= 1 { - err := catchCLI(args) - if err != nil { - if err.Error() == "end" { - os.Exit(0) - return - } - exit(err) - } - } log.Info(fmt.Sprintf("Starting Statping v%s", VERSION)) - if err := updateDisplay(); err != nil { - log.Warnln(err) - } + //if err := updateDisplay(); err != nil { + // log.Warnln(err) + //} confgs, err = configs.LoadConfigs() if err != nil { @@ -135,7 +115,7 @@ func main() { exit(errors.Wrap(err, "error creating default admin user")) } - if utils.Getenv("SAMPLE_DATA", true).(bool) { + if utils.Params.GetBool("SAMPLE_DATA") { if err := configs.TriggerSamples(); err != nil { exit(errors.Wrap(err, "error creating database")) } diff --git a/cmd/viper.go b/cmd/viper.go new file mode 100644 index 00000000..98b1d0cf --- /dev/null +++ b/cmd/viper.go @@ -0,0 +1,17 @@ +package main + +import ( + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func parseFlags(cmd *cobra.Command) { + cmd.PersistentFlags().StringVarP(&ipAddress, "ip", "s", "0.0.0.0", "server port") + viper.BindPFlag("ip", cmd.PersistentFlags().Lookup("ip")) + + cmd.PersistentFlags().IntVarP(&port, "port", "p", 8080, "server port") + viper.BindPFlag("port", cmd.PersistentFlags().Lookup("port")) + + cmd.PersistentFlags().IntVarP(&verboseMode, "verbose", "v", 2, "server port") + viper.BindPFlag("verbose", cmd.PersistentFlags().Lookup("verbose")) +} diff --git a/database/database.go b/database/database.go index eaa17fff..84b8f2ea 100644 --- a/database/database.go +++ b/database/database.go @@ -156,7 +156,7 @@ type Db struct { // Openw is a drop-in replacement for Open() func Openw(dialect string, args ...interface{}) (db Database, err error) { gorm.NowFunc = func() time.Time { - return time.Now().UTC() + return utils.Now() } gormdb, err := gorm.Open(dialect, args...) if err != nil { @@ -167,22 +167,36 @@ func Openw(dialect string, args ...interface{}) (db Database, err error) { } func OpenTester() (Database, error) { - testDB := utils.Getenv("TEST_DB", "sqlite3").(string) - var dbParamsstring string + testDB := utils.Params.GetString("DB_CONN") + var dbString string + switch testDB { case "mysql": - dbParamsstring = fmt.Sprintf("root:password123@tcp(localhost:3306)/statping?charset=utf8&parseTime=True&loc=UTC&time_zone=%%27UTC%%27") + dbString = fmt.Sprintf("%s:%s@tcp(%s:%v)/%s?charset=utf8&parseTime=True&loc=UTC&time_zone=%%27UTC%%27", + utils.Params.GetString("DB_HOST"), + utils.Params.GetString("DB_PASS"), + utils.Params.GetString("DB_HOST"), + utils.Params.GetInt("DB_PORT"), + utils.Params.GetString("DB_DATABASE"), + ) case "postgres": - dbParamsstring = fmt.Sprintf("host=localhost port=5432 user=root dbname=statping password=password123 timezone=UTC") + dbString = fmt.Sprintf("host=%s port=%v user=%s dbname=%s password=%s sslmode=disable timezone=UTC", + utils.Params.GetString("DB_HOST"), + utils.Params.GetInt("DB_PORT"), + utils.Params.GetString("DB_USER"), + utils.Params.GetString("DB_DATABASE"), + utils.Params.GetString("DB_PASS")) default: - dbParamsstring = fmt.Sprintf("file:%s?mode=memory&cache=shared", utils.RandomString(12)) + dbString = fmt.Sprintf("file:%s?mode=memory&cache=shared", utils.RandomString(12)) } - fmt.Println(testDB, dbParamsstring) - newDb, err := Openw(testDB, dbParamsstring) + newDb, err := Openw(testDB, dbString) if err != nil { return nil, err } newDb.DB().SetMaxOpenConns(1) + if testDB != "sqlite3" { + newDb.DB().SetMaxOpenConns(25) + } return newDb, err } diff --git a/database/grouping.go b/database/grouping.go index 6c76b821..54544870 100644 --- a/database/grouping.go +++ b/database/grouping.go @@ -74,7 +74,7 @@ func (g *GroupQuery) GraphData(by By) ([]*TimeValue, error) { dbQuery := g.db.MultipleSelects( g.db.SelectByTime(g.Group), by.String(), - ).Group("timeframe") + ).Group("timeframe").Order("timeframe", true) g.db = dbQuery diff --git a/database/time.go b/database/time.go index 3b25755c..ea41f77d 100644 --- a/database/time.go +++ b/database/time.go @@ -36,7 +36,7 @@ func (it *Db) SelectByTime(increment time.Duration) string { case "mysql": return fmt.Sprintf("FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(created_at) / %d) * %d) AS timeframe", seconds, seconds) case "postgres": - return fmt.Sprintf("date_trunc('%s', created_at) AS timeframe", increment) + return fmt.Sprintf("date_trunc('minute', created_at) - (CAST(EXTRACT(MINUTE FROM created_at) AS integer) %% %d) * interval '1 minute' AS timeframe", seconds) default: return fmt.Sprintf("datetime((strftime('%%s', created_at) / %d) * %d, 'unixepoch') as timeframe", seconds, seconds) } diff --git a/dev/postman.json b/dev/postman.json index 7b0f400e..40dc0dda 100644 --- a/dev/postman.json +++ b/dev/postman.json @@ -2,10 +2,268 @@ "info": { "_postman_id": "94807b85-ef65-4370-9144-b1a74e04cb0e", "name": "Statping", - "description": "Statping API Documentation for all endpoints to manage your services, users, groups, notifiers, messages, and more. \n\n## API Requirements\n\n- `endpoint` variable should be the URL of your Statping instance.\n- `api_key` variable is the API Secret key from the Settings page and is used for the Authorization Bearer token.\n\n", + "description": "Statping API Requests", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ + { + "name": "Miscellaneous", + "item": [ + { + "name": "Statping Setup", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Check Core API Route\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.config.connection).to.eql(\"sqlite3\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "db_host", + "value": "localhost", + "type": "text" + }, + { + "key": "db_user", + "value": "root", + "type": "text" + }, + { + "key": "db_password", + "value": "password123", + "type": "text" + }, + { + "key": "db_database", + "value": "statping", + "type": "text" + }, + { + "key": "db_connection", + "value": "sqlite", + "type": "text" + }, + { + "key": "db_port", + "value": "3306", + "type": "text" + }, + { + "key": "project", + "value": "Statping Monitoring Sample Data", + "type": "text" + }, + { + "key": "description", + "value": "View All Example Services", + "type": "text" + }, + { + "key": "username", + "value": "admin", + "type": "text" + }, + { + "key": "password", + "value": "admin", + "type": "text" + }, + { + "key": "domain", + "value": "http://localhost:8080", + "type": "text" + }, + { + "key": "email", + "value": "info@domain.com", + "type": "text" + }, + { + "key": "sample_data", + "value": "true", + "type": "text" + } + ], + "options": { + "urlencoded": {} + } + }, + "url": { + "raw": "{{endpoint}}/api/setup", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "setup" + ] + }, + "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." + }, + "response": [] + }, + { + "name": "Statping Details", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Check Core API Route\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.name).to.eql(\"Statping Monitoring Sample Data\");", + " pm.expect(jsonData.using_cdn).to.eql(false);", + " pm.expect(jsonData.admin).to.eql(false);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{endpoint}}/api", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api" + ] + }, + "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." + }, + "response": [] + }, + { + "name": "Statping Clear Cache", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{endpoint}}/api/clear_cache", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "clear_cache" + ] + }, + "description": "This endpoint will clear all the cache files in your Statping instance. This includes chart data and service views." + }, + "response": [] + } + ], + "description": "This is for Statping's miscellaneous API endpoints that aren't a part of another category.", + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "id": "883519e8-7c7d-49c0-9812-d988d0179907", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "7a0738e6-2fc4-45cb-9f1a-1cd57fb76b66", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, { "name": "Services", "item": [ @@ -72,8 +330,6 @@ "pm.test(\"View Service\", function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData.name).to.eql(\"Google\");", - " pm.expect(jsonData.status_code).to.eql(200);", - " pm.expect(jsonData.type).to.eql(\"http\");", "});" ], "type": "text/javascript" @@ -197,7 +453,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/hits_data?start=0&end=1973064434&group=day", + "raw": "{{endpoint}}/api/services/1/hits_data?start=0&end=5973064434&group=12h", "host": [ "{{endpoint}}" ], @@ -215,12 +471,12 @@ }, { "key": "end", - "value": "1973064434", + "value": "5973064434", "description": "End on time (unix timestamp)" }, { "key": "group", - "value": "day", + "value": "12h", "description": "Increment grouping (minute, hour, day)" } ] @@ -266,7 +522,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/ping?start=0&end=1973064434&group=hour", + "raw": "{{endpoint}}/api/services/1/ping_data?start=0&end=9973064434&group=12h", "host": [ "{{endpoint}}" ], @@ -274,7 +530,7 @@ "api", "services", "1", - "ping" + "ping_data" ], "query": [ { @@ -284,12 +540,12 @@ }, { "key": "end", - "value": "1973064434", + "value": "9973064434", "description": "End on time (unix timestamp)" }, { "key": "group", - "value": "hour", + "value": "12h", "description": "Increment grouping (minute, hour, day)" } ] @@ -335,7 +591,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/failure_data?start=0&end=1973064434&group=day", + "raw": "{{endpoint}}/api/services/1/failure_data?start=0&end=2973064434&group=12h", "host": [ "{{endpoint}}" ], @@ -352,11 +608,11 @@ }, { "key": "end", - "value": "1973064434" + "value": "2973064434" }, { "key": "group", - "value": "day" + "value": "12h" } ] }, @@ -401,7 +657,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/failures", + "raw": "{{endpoint}}/api/services/1/failures?start=0&end=99999999999", "host": [ "{{endpoint}}" ], @@ -410,6 +666,16 @@ "services", "1", "failures" + ], + "query": [ + { + "key": "start", + "value": "0" + }, + { + "key": "end", + "value": "99999999999" + } ] }, "description": "Returns an array of failures for this service. It includes the error message, http status code, and the ping response time." @@ -458,7 +724,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/hits", + "raw": "{{endpoint}}/api/services/1/hits?start=0&end=99999999999", "host": [ "{{endpoint}}" ], @@ -467,6 +733,16 @@ "services", "1", "hits" + ], + "query": [ + { + "key": "start", + "value": "0" + }, + { + "key": "end", + "value": "99999999999" + } ] }, "description": "Returns on array of all the successful hits for this service." @@ -509,17 +785,20 @@ ], "body": { "mode": "raw", - "raw": "[{\"service\":1,\"order\":1},{\"service\":2,\"order\":3},{\"service\":3,\"order\":4},{\"service\":4,\"order\":5}]" + "raw": "[{\"service\":1,\"order\":1},{\"service\":2,\"order\":3},{\"service\":3,\"order\":4},{\"service\":4,\"order\":5}]", + "options": { + "raw": {} + } }, "url": { - "raw": "{{endpoint}}/api/services/reorder", + "raw": "{{endpoint}}/api/reorder/services", "host": [ "{{endpoint}}" ], "path": [ "api", - "services", - "reorder" + "reorder", + "services" ] }, "description": "Reorder services in a specific order for the index page." @@ -695,8 +974,8 @@ "", "pm.test(\"Update Service\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.output.name).to.eql(\"Updated New Service\");", - " pm.expect(jsonData.output.domain).to.eql(\"https://google.com\");", + " pm.expect(jsonData.output.name).to.eql(\"Brand New Service\");", + " pm.expect(jsonData.output.domain).to.eql(\"https://google.net\");", " pm.expect(jsonData.output.type).to.eql(\"http\");", " pm.expect(jsonData.output.method).to.eql(\"GET\");", " pm.expect(jsonData.output.expected_status).to.eql(200);", @@ -726,7 +1005,10 @@ ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"Brand New Service\",\n \"domain\": \"https://google.net\",\n \"expected\": \"heyyyy\",\n \"expected_status\": 200,\n \"check_interval\": 20,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0\n}" + "raw": "{\n \"name\": \"Brand New Service\",\n \"domain\": \"https://google.net\",\n \"expected\": \"heyyyy\",\n \"expected_status\": 200,\n \"check_interval\": 20,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0\n}", + "options": { + "raw": {} + } }, "url": { "raw": "{{endpoint}}/api/services/{{service_id}}", @@ -790,6 +1072,55 @@ } ] }, + { + "name": "Delete Service Failures", + "event": [ + { + "listen": "test", + "script": { + "id": "dd4d721d-d874-448b-abc9-59c1afceb58e", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/services/{{service_id}}/failures", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "services", + "{{service_id}}", + "failures" + ] + }, + "description": "Delete all the service failures." + }, + "response": [] + }, { "name": "Delete Service", "event": [ @@ -886,55 +1217,6 @@ "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"delete\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": true,\n \"latency\": 0.203382878,\n \"ping_time\": 0.001664491,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:55.455091-08:00\"\n }\n}" } ] - }, - { - "name": "Delete Service Failures", - "event": [ - { - "listen": "test", - "script": { - "id": "dd4d721d-d874-448b-abc9-59c1afceb58e", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "DELETE", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "{{endpoint}}/api/services/{{service_id}}/failures", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "services", - "{{service_id}}", - "failures" - ] - }, - "description": "Delete all the service failures." - }, - "response": [] } ], "description": "With the Statping API, you can add, remove, edit all your services fields from the API directly. This includes viewing Service chart data for latency/up-time, and even viewing a log of failures. ", @@ -969,8 +1251,7 @@ ] } } - ], - "protocolProfileBehavior": {} + ] }, { "name": "Groups", @@ -983,13 +1264,9 @@ "script": { "id": "d87f8a4e-7640-45b8-9d45-4f6e6f2463ee", "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", "pm.test(\"View All Groups\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.length).to.eql(3);", + " pm.expect(jsonData.length).to.eql(2);", "});" ], "type": "text/javascript" @@ -1304,14 +1581,14 @@ "raw": "[{\"group\":1,\"order\":1},{\"group\":2,\"order\":2}]" }, "url": { - "raw": "{{endpoint}}/api/groups/reorder", + "raw": "{{endpoint}}/api/reorder/groups", "host": [ "{{endpoint}}" ], "path": [ "api", - "groups", - "reorder" + "reorder", + "groups" ] }, "description": "Reorder services in a specific order for the index page." @@ -1448,8 +1725,7 @@ ] } } - ], - "protocolProfileBehavior": {} + ] }, { "name": "Users", @@ -1508,7 +1784,10 @@ "value": "admin", "type": "text" } - ] + ], + "options": { + "urlencoded": {} + } }, "url": { "raw": "{{endpoint}}/api/login", @@ -2002,8 +2281,7 @@ ] } } - ], - "protocolProfileBehavior": {} + ] }, { "name": "Notifiers", @@ -2022,7 +2300,7 @@ "", "pm.test(\"View All Notifiers\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.length).to.eql(9);", + " pm.expect(jsonData.length).to.eql(10);", "});" ], "type": "text/javascript" @@ -2035,7 +2313,7 @@ "bearer": [ { "key": "token", - "value": "e351393306ea245de5f9588cbe8627c74db007c6", + "value": "R1T2Cyugjjzw63km", "type": "string" } ] @@ -2086,14 +2364,14 @@ "method": "GET", "header": [], "url": { - "raw": "{{endpoint}}/api/notifier/mobile", + "raw": "{{endpoint}}/api/notifier/slack", "host": [ "{{endpoint}}" ], "path": [ "api", "notifier", - "mobile" + "slack" ] }, "description": "View a specific notifier and it's details." @@ -2108,16 +2386,10 @@ "script": { "id": "d714d71d-4d6a-4b2e-a6ea-16c34dec3041", "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", "pm.test(\"Update Notifier\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.output.method).to.eql(\"mobile\");", - " pm.expect(jsonData.output.enabled).to.eql(true);", - " pm.expect(jsonData.output.limits).to.eql(55);", - " pm.expect(jsonData.output.removeable).to.eql(false);", + " pm.expect(jsonData.status).to.eql(\"success\");", + " pm.expect(jsonData.output).to.eql(\"slack\");", "});" ], "type": "text/javascript" @@ -2146,17 +2418,17 @@ ], "body": { "mode": "raw", - "raw": "{\n \"method\": \"mobile\",\n \"var1\": \"ExponentPushToken[ToBadIWillError123456]\",\n \"enabled\": true,\n \"limits\": 55\n}" + "raw": "{\n \"method\": \"slack\",\n \"host\": \"https://hooks.slack.com/services/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\",\n \"enabled\": true,\n \"limits\": 55\n}" }, "url": { - "raw": "{{endpoint}}/api/notifier/mobile", + "raw": "{{endpoint}}/api/notifier/slack", "host": [ "{{endpoint}}" ], "path": [ "api", "notifier", - "mobile" + "slack" ] }, "description": "Update a notifier to change it's values." @@ -2164,7 +2436,7 @@ "response": [] } ], - "description": "Statping contains multiple notifiers that will send you a notification whenever a service become offline, or online. You can create your own 3rd party notifier by reading more on the [Notifiers Wiki](https://github.com/statping/statping/wiki/Notifiers) on the Github repo.", + "description": "Statping contains multiple notifiers that will send you a notification whenever a service become offline, or online. You can create your own 3rd party notifier by reading more on the [Notifiers Wiki](https://github.com/hunterlong/statping/wiki/Notifiers) on the Github repo.", "auth": { "type": "bearer", "bearer": [ @@ -2196,8 +2468,7 @@ ] } } - ], - "protocolProfileBehavior": {} + ] }, { "name": "Messages", @@ -2674,115 +2945,11 @@ ] } } - ], - "protocolProfileBehavior": {} + ] }, { "name": "Checkins", "item": [ - { - "name": "Create Checkin", - "event": [ - { - "listen": "test", - "script": { - "id": "af07a95b-1bf5-42c7-bd3f-a32f3ab2a264", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Create Checkin\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.status).to.eql(\"success\");", - " pm.expect(jsonData.type).to.eql(\"checkin\");", - " pm.expect(jsonData.output.name).to.eql(\"Server Checkin\");", - " pm.expect(jsonData.output.grace).to.eql(60);", - " pm.expect(jsonData.output.interval).to.eql(900);", - " var id = jsonData.output.api_key;", - " pm.globals.set(\"checkin_id\", id);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" - }, - "url": { - "raw": "{{endpoint}}/api/checkin", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "checkin" - ] - }, - "description": "Create a new Checkin." - }, - "response": [ - { - "name": "Create Checkin", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" - }, - "url": { - "raw": "{{endpoint}}/api/checkin", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "checkin" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Date", - "value": "Mon, 10 Dec 2018 19:34:10 GMT" - }, - { - "key": "Content-Length", - "value": "330" - } - ], - "cookie": [], - "body": "{\n \"status\": \"success\",\n \"type\": \"checkin\",\n \"method\": \"create\",\n \"id\": 5,\n \"output\": {\n \"id\": 5,\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60,\n \"api_key\": \"1emn9ha\",\n \"created_at\": \"2018-12-10T19:34:10.991372Z\",\n \"updated_at\": \"2018-12-10T19:34:10.991372Z\",\n \"failing\": false,\n \"last_hit\": \"0001-01-01T00:00:00Z\",\n \"hits\": null,\n \"failures\": null\n }\n}" - } - ] - }, { "name": "View All Checkin's", "event": [ @@ -2799,10 +2966,9 @@ " var jsonData = pm.response.json();", " var first = jsonData[0];", " var id = pm.globals.get(\"checkin_id\");", - " pm.expect(first.name).to.eql(\"Server Checkin\");", - " pm.expect(first.api_key).to.eql(id);", - " pm.expect(first.grace).to.eql(60);", - " pm.expect(first.interval).to.eql(900);", + " pm.expect(first.name).to.eql(\"Demo Checkin 1\");", + " pm.expect(first.grace).to.eql(300);", + " pm.expect(first.interval).to.eql(300);", "});" ], "type": "text/javascript" @@ -2863,6 +3029,119 @@ } ] }, + { + "name": "Create Checkin", + "event": [ + { + "listen": "test", + "script": { + "id": "af07a95b-1bf5-42c7-bd3f-a32f3ab2a264", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Create Checkin\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.status).to.eql(\"success\");", + " pm.expect(jsonData.type).to.eql(\"checkin\");", + " pm.expect(jsonData.output.name).to.eql(\"Server Checkin\");", + " pm.expect(jsonData.output.grace).to.eql(60);", + " pm.expect(jsonData.output.interval).to.eql(900);", + " var id = jsonData.output.api_key;", + " pm.globals.set(\"checkin_id\", id);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" + }, + "url": { + "raw": "{{endpoint}}/api/checkins", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "checkins" + ] + }, + "description": "Create a new Checkin." + }, + "response": [ + { + "name": "Create Checkin", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" + }, + "url": { + "raw": "{{endpoint}}/api/checkin", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "checkin" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Mon, 10 Dec 2018 19:34:10 GMT" + }, + { + "key": "Content-Length", + "value": "330" + } + ], + "cookie": [], + "body": "{\n \"status\": \"success\",\n \"type\": \"checkin\",\n \"method\": \"create\",\n \"id\": 5,\n \"output\": {\n \"id\": 5,\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60,\n \"api_key\": \"1emn9ha\",\n \"created_at\": \"2018-12-10T19:34:10.991372Z\",\n \"updated_at\": \"2018-12-10T19:34:10.991372Z\",\n \"failing\": false,\n \"last_hit\": \"0001-01-01T00:00:00Z\",\n \"hits\": null,\n \"failures\": null\n }\n}" + } + ] + }, { "name": "Run Checkin", "event": [ @@ -2878,7 +3157,6 @@ "pm.test(\"Hit the Checkin API Endpoint\", function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData.status).to.eql(\"success\");", - " pm.expect(jsonData.type).to.eql(\"checkin_hit\");", " pm.expect(jsonData.method).to.eql(\"update\");", "});" ], @@ -2969,13 +3247,13 @@ "method": "GET", "header": [], "url": { - "raw": "{{endpoint}}/api/checkin/{{checkin_id}}", + "raw": "{{endpoint}}/api/checkins/{{checkin_id}}", "host": [ "{{endpoint}}" ], "path": [ "api", - "checkin", + "checkins", "{{checkin_id}}" ] }, @@ -3047,6 +3325,16 @@ } ], "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, "method": "DELETE", "header": [], "body": { @@ -3054,13 +3342,13 @@ "raw": "" }, "url": { - "raw": "{{endpoint}}/api/checkin/{{checkin_id}}", + "raw": "{{endpoint}}/api/checkins/{{checkin_id}}", "host": [ "{{endpoint}}" ], "path": [ "api", - "checkin", + "checkins", "{{checkin_id}}" ] }, @@ -3133,342 +3421,7 @@ ] } } - ], - "protocolProfileBehavior": {} - }, - { - "name": "Miscellaneous", - "item": [ - { - "name": "Statping Setup", - "event": [ - { - "listen": "test", - "script": { - "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check Core API Route\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.description).to.eql(\"Statping Monitoring Sample Data\");", - " pm.expect(jsonData.using_cdn).to.eql(false);", - " pm.expect(jsonData.config.connection).to.eql(\"sqlite\");", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/x-www-form-urlencoded", - "type": "text" - } - ], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "db_host", - "value": "localhost", - "type": "text" - }, - { - "key": "db_user", - "value": "root", - "type": "text" - }, - { - "key": "db_password", - "value": "password123", - "type": "text" - }, - { - "key": "db_database", - "value": "statping", - "type": "text" - }, - { - "key": "db_connection", - "value": "sqlite", - "type": "text" - }, - { - "key": "db_port", - "value": "3306", - "type": "text" - }, - { - "key": "project", - "value": "Statping Demo", - "type": "text" - }, - { - "key": "description", - "value": "Statping setup from POST", - "type": "text" - }, - { - "key": "username", - "value": "admin", - "type": "text" - }, - { - "key": "password", - "value": "admin", - "type": "text" - }, - { - "key": "domain", - "value": "http://localhost:8080", - "type": "text" - }, - { - "key": "email", - "value": "info@domain.com", - "type": "text" - }, - { - "key": "sample_data", - "value": "true", - "type": "text" - } - ] - }, - "url": { - "raw": "{{endpoint}}/api/setup", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "setup" - ] - }, - "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." - }, - "response": [] - }, - { - "name": "Statping Details", - "event": [ - { - "listen": "test", - "script": { - "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check Core API Route\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.description).to.eql(\"Statping Monitoring Sample Data\");", - " pm.expect(jsonData.using_cdn).to.eql(false);", - " pm.expect(jsonData.config.connection).to.eql(\"sqlite\");", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{endpoint}}/api", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api" - ] - }, - "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." - }, - "response": [] - }, - { - "name": "Statping Clear Cache", - "event": [ - { - "listen": "test", - "script": { - "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{endpoint}}/api/clear_cache", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "clear_cache" - ] - }, - "description": "This endpoint will clear all the cache files in your Statping instance. This includes chart data and service views." - }, - "response": [] - }, - { - "name": "Statping Reset API Tokens", - "event": [ - { - "listen": "test", - "script": { - "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{endpoint}}/api/renew", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "renew" - ] - }, - "description": "Reset your root API Key and Secret values to brand new values." - }, - "response": [] - } - ], - "description": "This is for Statping's miscellaneous API endpoints that aren't a part of another category.", - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "event": [ - { - "listen": "prerequest", - "script": { - "id": "883519e8-7c7d-49c0-9812-d988d0179907", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "7a0738e6-2fc4-45cb-9f1a-1cd57fb76b66", - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "protocolProfileBehavior": {} + ] } - ], - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "event": [ - { - "listen": "prerequest", - "script": { - "id": "4eb22861-cca3-4592-a1a4-4d01bc62ee74", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "cac1a6f2-2dc3-4b09-9849-3d5aab919244", - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ], - "protocolProfileBehavior": {} + ] } diff --git a/dev/postman_environment.json b/dev/postman_environment.json index 66f82a87..ad4333ca 100644 --- a/dev/postman_environment.json +++ b/dev/postman_environment.json @@ -7,9 +7,15 @@ "value": "http://127.0.0.1:8080", "description": "", "enabled": true + }, + { + "key": "api_key", + "value": "demosecret123", + "description": "", + "enabled": true } ], "_postman_variable_scope": "environment", "_postman_exported_at": "2018-11-17T16:55:15.031Z", "_postman_exported_using": "Postman/6.5.2" -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 7856b69b..c859090b 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/fatih/structs v1.1.0 + github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/getsentry/sentry-go v0.5.1 github.com/go-mail/mail v2.3.1+incompatible github.com/gogo/protobuf v1.3.1 // indirect @@ -18,18 +19,30 @@ require ( github.com/joho/godotenv v1.3.0 github.com/kataras/iris/v12 v12.0.1 github.com/mattn/go-sqlite3 v2.0.1+incompatible + github.com/mitchellh/mapstructure v1.2.2 // indirect + github.com/pelletier/go-toml v1.7.0 // indirect github.com/pkg/errors v0.9.1 github.com/prometheus/common v0.9.1 github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f github.com/russross/blackfriday/v2 v2.0.1 github.com/sirupsen/logrus v1.4.2 + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect + github.com/spf13/afero v1.2.2 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/cobra v1.0.0 + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.6.3 github.com/stretchr/testify v1.5.1 github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e golang.org/x/crypto v0.0.0-20200320181102-891825fb96df golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be + golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect + golang.org/x/text v0.3.2 // indirect golang.org/x/tools v0.0.0-20200321014904-268ba720d32c // indirect google.golang.org/grpc v1.28.0 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/ini.v1 v1.55.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.2.8 diff --git a/go.sum b/go.sum index 112d58f9..934094a9 100755 --- a/go.sum +++ b/go.sum @@ -11,6 +11,7 @@ github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voi github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= @@ -29,13 +30,19 @@ github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -47,6 +54,7 @@ github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6ps github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -59,10 +67,14 @@ github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/getsentry/sentry-go v0.5.1 h1:MIPe7ScHADsrK2vznqmhksIUFxq7m0JfTh+ZIMkI+VQ= github.com/getsentry/sentry-go v0.5.1/go.mod h1:B8H7x8TYDPkeWPRzGpIiFO97LZP6rL8A3hEt8lUItMw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= @@ -83,11 +95,13 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -97,10 +111,12 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -109,10 +125,15 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+ github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= @@ -131,8 +152,10 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= @@ -146,6 +169,7 @@ github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/l github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -163,6 +187,8 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -175,10 +201,16 @@ github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go. github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= @@ -188,10 +220,14 @@ github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -201,18 +237,24 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f h1:onGP+qmYmjKs7pkmi9j0mwyr97/D5wki80e74aKIOxg= github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f/go.mod h1:cq57a4l475CeMvE7RRpSui1MEqCmhirIt1E7kl8BC2Q= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= @@ -224,14 +266,36 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -239,8 +303,11 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls= github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e/go.mod h1:B4+Kq1u5FlULTjFSM707Q6e/cOHFv0z/6QRoxubDIQ8= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -255,12 +322,17 @@ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -285,6 +357,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= @@ -301,6 +374,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -310,8 +384,16 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= +golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -334,6 +416,7 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= @@ -344,15 +427,22 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gG gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= +gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/handlers/api_test.go b/handlers/api_test.go index 9fc5025e..27ee5383 100644 --- a/handlers/api_test.go +++ b/handlers/api_test.go @@ -48,12 +48,12 @@ func TestFailedHTTPServer(t *testing.T) { func TestSetupRoutes(t *testing.T) { form := url.Values{} - form.Add("db_host", "") - form.Add("db_user", "") - form.Add("db_password", "") - form.Add("db_database", "") - form.Add("db_connection", "sqlite") - form.Add("db_port", "") + form.Add("db_host", utils.Params.GetString("DB_HOST")) + form.Add("db_user", utils.Params.GetString("DB_USER")) + form.Add("db_password", utils.Params.GetString("DB_PASS")) + form.Add("db_database", utils.Params.GetString("DB_DATABASE")) + form.Add("db_connection", utils.Params.GetString("DB_CONN")) + form.Add("db_port", utils.Params.GetString("DB_PORT")) form.Add("project", "Tester") form.Add("username", "admin") form.Add("password", "password123") @@ -82,7 +82,7 @@ func TestSetupRoutes(t *testing.T) { Body: form.Encode(), ExpectedStatus: 200, HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"}, - ExpectedFiles: []string{dir + "/config.yml", dir + "/" + "statping.db"}, + ExpectedFiles: []string{utils.Directory + "/config.yml"}, FuncTest: func(t *testing.T) error { if !core.App.Setup { return errors.New("core has not been setup") diff --git a/handlers/handlers.go b/handlers/handlers.go index c27cfab2..ac837c79 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -44,7 +44,7 @@ func RunHTTPServer(ip string, port int) error { log.Infoln(fmt.Sprintf("Statping Secure HTTPS Server running on https://%v:%v", ip, 443)) usingSSL = true } else { - log.Infoln("Statping HTTP Server running on http://" + host) + log.Infoln("Statping HTTP Server running on http://" + host + basePath) } router = Router() @@ -172,7 +172,7 @@ func IsAdmin(r *http.Request) bool { if !core.App.Setup { return false } - if utils.Getenv("GO_ENV", false).(bool) { + if utils.Params.GetString("GO_ENV") == "test" { return true } claim, err := getJwtToken(r) diff --git a/handlers/routes.go b/handlers/routes.go index 346a2aaf..c7d40a92 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -26,14 +26,14 @@ func Router() *mux.Router { CacheStorage = NewStorage() r := mux.NewRouter().StrictSlash(true) - authUser := utils.Getenv("AUTH_USERNAME", "").(string) - authPass := utils.Getenv("AUTH_PASSWORD", "").(string) + authUser := utils.Params.GetString("AUTH_USERNAME") + authPass := utils.Params.GetString("AUTH_PASSWORD") if authUser != "" && authPass != "" { r.Use(basicAuthHandler) } - bPath := utils.Getenv("BASE_PATH", "").(string) + bPath := utils.Params.GetString("BASE_PATH") sentryHandler := sentryhttp.New(sentryhttp.Options{}) if bPath != "" { diff --git a/handlers/services_test.go b/handlers/services_test.go index 1e9df2f4..0f42597a 100644 --- a/handlers/services_test.go +++ b/handlers/services_test.go @@ -77,7 +77,7 @@ func TestApiServiceRoutes(t *testing.T) { Name: "Statping Service Failures", URL: "/api/services/1/failures", Method: "GET", - ResponseLen: 125, + ResponseLen: 126, ExpectedStatus: 200, }, { @@ -123,7 +123,7 @@ func TestApiServiceRoutes(t *testing.T) { Name: "Statping Service 1 Failure Data - 15 Minute", URL: "/api/services/1/failure_data" + startEndQuery + "&group=15m", Method: "GET", - ResponseLen: 124, + ResponseLen: 125, ExpectedStatus: 200, }, { diff --git a/handlers/setup.go b/handlers/setup.go index de5061ed..feb34ba5 100644 --- a/handlers/setup.go +++ b/handlers/setup.go @@ -83,14 +83,14 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { c := &core.Core{ Name: project, Description: description, - //ApiKey: apiKey.(string), - //ApiSecret: apiSecret.(string), - Domain: domain, - Version: core.App.Version, - Started: utils.Now(), - CreatedAt: utils.Now(), - UseCdn: null.NewNullBool(false), - Footer: null.NewNullString(""), + ApiKey: utils.Params.GetString("API_KEY"), + ApiSecret: utils.Params.GetString("API_SECRET"), + Domain: domain, + Version: core.App.Version, + Started: utils.Now(), + CreatedAt: utils.Now(), + UseCdn: null.NewNullBool(false), + Footer: null.NewNullString(""), } log.Infoln("Creating new Core") diff --git a/notifiers/discord_test.go b/notifiers/discord_test.go index 584a9152..61d5c92d 100644 --- a/notifiers/discord_test.go +++ b/notifiers/discord_test.go @@ -4,6 +4,7 @@ import ( "github.com/statping/statping/database" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/null" + "github.com/statping/statping/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "os" @@ -12,7 +13,7 @@ import ( ) var ( - DISCORD_URL = os.Getenv("DISCORD_URL") + DISCORD_URL = utils.Params.GetString("DISCORD_URL") discordMessage = `{"content": "The discord notifier on Statping has been tested!"}` ) diff --git a/notifiers/email_test.go b/notifiers/email_test.go index 3237dbf5..ea9f5345 100644 --- a/notifiers/email_test.go +++ b/notifiers/email_test.go @@ -8,7 +8,6 @@ import ( "github.com/statping/statping/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "os" "testing" "time" ) @@ -25,12 +24,12 @@ var ( var testEmail *emailOutgoing func init() { - EMAIL_HOST = os.Getenv("EMAIL_HOST") - EMAIL_USER = os.Getenv("EMAIL_USER") - EMAIL_PASS = os.Getenv("EMAIL_PASS") - EMAIL_OUTGOING = os.Getenv("EMAIL_OUTGOING") - EMAIL_SEND_TO = os.Getenv("EMAIL_SEND_TO") - EMAIL_PORT = utils.ToInt(os.Getenv("EMAIL_PORT")) + EMAIL_HOST = utils.Params.GetString("EMAIL_HOST") + EMAIL_USER = utils.Params.GetString("EMAIL_USER") + EMAIL_PASS = utils.Params.GetString("EMAIL_PASS") + EMAIL_OUTGOING = utils.Params.GetString("EMAIL_OUTGOING") + EMAIL_SEND_TO = utils.Params.GetString("EMAIL_SEND_TO") + EMAIL_PORT = utils.ToInt(utils.Params.GetString("EMAIL_PORT")) } func TestEmailNotifier(t *testing.T) { diff --git a/notifiers/slack_test.go b/notifiers/slack_test.go index 7e9b82bf..7cf8f20d 100644 --- a/notifiers/slack_test.go +++ b/notifiers/slack_test.go @@ -4,9 +4,9 @@ import ( "github.com/statping/statping/database" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/null" + "github.com/statping/statping/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "os" "testing" "time" ) @@ -21,7 +21,7 @@ func TestSlackNotifier(t *testing.T) { db.AutoMigrate(¬ifications.Notification{}) notifications.SetDB(db) - SLACK_URL = os.Getenv("SLACK_URL") + SLACK_URL = utils.Params.GetString("SLACK_URL") slacker.Host = SLACK_URL slacker.Enabled = null.NewNullBool(true) diff --git a/source/tmpl/postman.json b/source/tmpl/postman.json index 2a15ac82..59087759 100644 --- a/source/tmpl/postman.json +++ b/source/tmpl/postman.json @@ -2,10 +2,311 @@ "info": { "_postman_id": "94807b85-ef65-4370-9144-b1a74e04cb0e", "name": "Statping", - "description": "Statping API Documentation for all endpoints to manage your services, users, groups, notifiers, messages, and more. \n\n## API Requirements\n\n- `endpoint` variable should be the URL of your Statping instance.\n- `api_key` variable is the API Secret key from the Settings page and is used for the Authorization Bearer token.\n\n", + "description": "Statup API Requests", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ + { + "name": "Miscellaneous", + "item": [ + { + "name": "Statping Setup", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Check Core API Route\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.config.connection).to.eql(\"sqlite3\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "db_host", + "value": "localhost", + "type": "text" + }, + { + "key": "db_user", + "value": "root", + "type": "text" + }, + { + "key": "db_password", + "value": "password123", + "type": "text" + }, + { + "key": "db_database", + "value": "statping", + "type": "text" + }, + { + "key": "db_connection", + "value": "sqlite", + "type": "text" + }, + { + "key": "db_port", + "value": "3306", + "type": "text" + }, + { + "key": "project", + "value": "Statping Monitoring Sample Data", + "type": "text" + }, + { + "key": "description", + "value": "View All Example Services", + "type": "text" + }, + { + "key": "username", + "value": "admin", + "type": "text" + }, + { + "key": "password", + "value": "admin", + "type": "text" + }, + { + "key": "domain", + "value": "http://localhost:8080", + "type": "text" + }, + { + "key": "email", + "value": "info@domain.com", + "type": "text" + }, + { + "key": "sample_data", + "value": "true", + "type": "text" + } + ], + "options": { + "urlencoded": {} + } + }, + "url": { + "raw": "{{endpoint}}/api/setup", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "setup" + ] + }, + "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." + }, + "response": [] + }, + { + "name": "Statping Details", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Check Core API Route\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.name).to.eql(\"Statping Monitoring Sample Data\");", + " pm.expect(jsonData.using_cdn).to.eql(false);", + " pm.expect(jsonData.admin).to.eql(false);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{endpoint}}/api", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api" + ] + }, + "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." + }, + "response": [] + }, + { + "name": "Statping Clear Cache", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{endpoint}}/api/clear_cache", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "clear_cache" + ] + }, + "description": "This endpoint will clear all the cache files in your Statping instance. This includes chart data and service views." + }, + "response": [] + }, + { + "name": "Statping Reset API Tokens", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{endpoint}}/api/renew", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "renew" + ] + }, + "description": "Reset your root API Key and Secret values to brand new values." + }, + "response": [] + } + ], + "description": "This is for Statping's miscellaneous API endpoints that aren't a part of another category.", + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "id": "883519e8-7c7d-49c0-9812-d988d0179907", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "7a0738e6-2fc4-45cb-9f1a-1cd57fb76b66", + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, { "name": "Services", "item": [ @@ -197,7 +498,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/data?start=0&end=1973064434&group=hour", + "raw": "{{endpoint}}/api/services/1/hits_data?start=0&end=5973064434&group=12h", "host": [ "{{endpoint}}" ], @@ -205,7 +506,7 @@ "api", "services", "1", - "data" + "hits_data" ], "query": [ { @@ -215,12 +516,12 @@ }, { "key": "end", - "value": "1973064434", + "value": "5973064434", "description": "End on time (unix timestamp)" }, { "key": "group", - "value": "hour", + "value": "12h", "description": "Increment grouping (minute, hour, day)" } ] @@ -266,7 +567,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/ping?start=0&end=1973064434&group=hour", + "raw": "{{endpoint}}/api/services/1/ping_data?start=0&end=9973064434&group=12h", "host": [ "{{endpoint}}" ], @@ -274,7 +575,7 @@ "api", "services", "1", - "ping" + "ping_data" ], "query": [ { @@ -284,12 +585,12 @@ }, { "key": "end", - "value": "1973064434", + "value": "9973064434", "description": "End on time (unix timestamp)" }, { "key": "group", - "value": "hour", + "value": "12h", "description": "Increment grouping (minute, hour, day)" } ] @@ -299,7 +600,7 @@ "response": [] }, { - "name": "View Service Heatmap Data", + "name": "View Service Failure Data", "event": [ { "listen": "test", @@ -335,7 +636,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/heatmap", + "raw": "{{endpoint}}/api/services/1/failure_data?start=0&end=2973064434&group=12h", "host": [ "{{endpoint}}" ], @@ -343,7 +644,21 @@ "api", "services", "1", - "heatmap" + "failure_data" + ], + "query": [ + { + "key": "start", + "value": "0" + }, + { + "key": "end", + "value": "2973064434" + }, + { + "key": "group", + "value": "12h" + } ] }, "description": "View the data service failures in a heatmap. The field `x` is the day of the month, and `y` is the amount of failures the service had." @@ -387,7 +702,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/failures", + "raw": "{{endpoint}}/api/services/1/failures?start=0&end=99999999999", "host": [ "{{endpoint}}" ], @@ -396,6 +711,16 @@ "services", "1", "failures" + ], + "query": [ + { + "key": "start", + "value": "0" + }, + { + "key": "end", + "value": "99999999999" + } ] }, "description": "Returns an array of failures for this service. It includes the error message, http status code, and the ping response time." @@ -444,7 +769,7 @@ } ], "url": { - "raw": "{{endpoint}}/api/services/1/hits", + "raw": "{{endpoint}}/api/services/1/hits?start=0&end=99999999999", "host": [ "{{endpoint}}" ], @@ -453,6 +778,16 @@ "services", "1", "hits" + ], + "query": [ + { + "key": "start", + "value": "0" + }, + { + "key": "end", + "value": "99999999999" + } ] }, "description": "Returns on array of all the successful hits for this service." @@ -495,17 +830,20 @@ ], "body": { "mode": "raw", - "raw": "[{\"service\":1,\"order\":1},{\"service\":5,\"order\":2},{\"service\":2,\"order\":3},{\"service\":3,\"order\":4},{\"service\":4,\"order\":5}]" + "raw": "[{\"service\":1,\"order\":1},{\"service\":2,\"order\":3},{\"service\":3,\"order\":4},{\"service\":4,\"order\":5}]", + "options": { + "raw": {} + } }, "url": { - "raw": "{{endpoint}}/api/services/reorder", + "raw": "{{endpoint}}/api/reorder/services", "host": [ "{{endpoint}}" ], "path": [ "api", - "services", - "reorder" + "reorder", + "services" ] }, "description": "Reorder services in a specific order for the index page." @@ -681,8 +1019,8 @@ "", "pm.test(\"Update Service\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.output.name).to.eql(\"Updated New Service\");", - " pm.expect(jsonData.output.domain).to.eql(\"https://google.com\");", + " pm.expect(jsonData.output.name).to.eql(\"Brand New Service\");", + " pm.expect(jsonData.output.domain).to.eql(\"https://google.net\");", " pm.expect(jsonData.output.type).to.eql(\"http\");", " pm.expect(jsonData.output.method).to.eql(\"GET\");", " pm.expect(jsonData.output.expected_status).to.eql(200);", @@ -712,7 +1050,10 @@ ], "body": { "mode": "raw", - "raw": "{\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0\n}" + "raw": "{\n \"name\": \"Brand New Service\",\n \"domain\": \"https://google.net\",\n \"expected\": \"heyyyy\",\n \"expected_status\": 200,\n \"check_interval\": 20,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0\n}", + "options": { + "raw": {} + } }, "url": { "raw": "{{endpoint}}/api/services/{{service_id}}", @@ -776,6 +1117,55 @@ } ] }, + { + "name": "Delete Service Failures", + "event": [ + { + "listen": "test", + "script": { + "id": "dd4d721d-d874-448b-abc9-59c1afceb58e", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{endpoint}}/api/services/{{service_id}}/failures", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "services", + "{{service_id}}", + "failures" + ] + }, + "description": "Delete all the service failures." + }, + "response": [] + }, { "name": "Delete Service", "event": [ @@ -872,55 +1262,6 @@ "body": "{\n \"status\": \"success\",\n \"type\": \"service\",\n \"method\": \"delete\",\n \"id\": 10,\n \"output\": {\n \"id\": 10,\n \"name\": \"Updated New Service\",\n \"domain\": \"https://google.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 60,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 10,\n \"order_id\": 0,\n \"allow_notifications\": false,\n \"created_at\": \"2018-12-10T11:31:47.535086-08:00\",\n \"updated_at\": \"2018-12-10T11:31:47.535184-08:00\",\n \"online\": true,\n \"latency\": 0.203382878,\n \"ping_time\": 0.001664491,\n \"online_24_hours\": 0,\n \"avg_response\": \"\",\n \"status_code\": 200,\n \"last_success\": \"2018-12-10T11:31:55.455091-08:00\"\n }\n}" } ] - }, - { - "name": "Delete Service Failures", - "event": [ - { - "listen": "test", - "script": { - "id": "dd4d721d-d874-448b-abc9-59c1afceb58e", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "DELETE", - "header": [], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "{{endpoint}}/api/services/{{service_id}}/failures", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "services", - "{{service_id}}", - "failures" - ] - }, - "description": "Delete all the service failures." - }, - "response": [] } ], "description": "With the Statping API, you can add, remove, edit all your services fields from the API directly. This includes viewing Service chart data for latency/up-time, and even viewing a log of failures. ", @@ -1289,14 +1630,14 @@ "raw": "[{\"group\":1,\"order\":1},{\"group\":2,\"order\":2}]" }, "url": { - "raw": "{{endpoint}}/api/groups/reorder", + "raw": "{{endpoint}}/api/reorder/groups", "host": [ "{{endpoint}}" ], "path": [ "api", - "groups", - "reorder" + "reorder", + "groups" ] }, "description": "Reorder services in a specific order for the index page." @@ -1438,6 +1779,79 @@ { "name": "Users", "item": [ + { + "name": "Statping Login", + "event": [ + { + "listen": "test", + "script": { + "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Check Login JWT Token\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.have.property('token');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/x-www-form-urlencoded" + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "username", + "value": "admin", + "type": "text" + }, + { + "key": "password", + "value": "admin", + "type": "text" + } + ], + "options": { + "urlencoded": {} + } + }, + "url": { + "raw": "{{endpoint}}/api/login", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "login" + ] + }, + "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." + }, + "response": [] + }, { "name": "View All Users", "event": [ @@ -1935,7 +2349,7 @@ "", "pm.test(\"View All Notifiers\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.length).to.eql(9);", + " pm.expect(jsonData.length).to.eql(10);", "});" ], "type": "text/javascript" @@ -1948,7 +2362,7 @@ "bearer": [ { "key": "token", - "value": "e351393306ea245de5f9588cbe8627c74db007c6", + "value": "R1T2Cyugjjzw63km", "type": "string" } ] @@ -1999,14 +2413,14 @@ "method": "GET", "header": [], "url": { - "raw": "{{endpoint}}/api/notifier/mobile", + "raw": "{{endpoint}}/api/notifier/slack", "host": [ "{{endpoint}}" ], "path": [ "api", "notifier", - "mobile" + "slack" ] }, "description": "View a specific notifier and it's details." @@ -2021,16 +2435,10 @@ "script": { "id": "d714d71d-4d6a-4b2e-a6ea-16c34dec3041", "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", "pm.test(\"Update Notifier\", function () {", " var jsonData = pm.response.json();", - " pm.expect(jsonData.output.method).to.eql(\"mobile\");", - " pm.expect(jsonData.output.enabled).to.eql(true);", - " pm.expect(jsonData.output.limits).to.eql(55);", - " pm.expect(jsonData.output.removeable).to.eql(false);", + " pm.expect(jsonData.status).to.eql(\"success\");", + " pm.expect(jsonData.output).to.eql(\"slack\");", "});" ], "type": "text/javascript" @@ -2059,17 +2467,17 @@ ], "body": { "mode": "raw", - "raw": "{\n \"method\": \"mobile\",\n \"var1\": \"ExponentPushToken[ToBadIWillError123456]\",\n \"enabled\": true,\n \"limits\": 55\n}" + "raw": "{\n \"method\": \"slack\",\n \"host\": \"https://hooks.slack.com/services/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\",\n \"enabled\": true,\n \"limits\": 55\n}" }, "url": { - "raw": "{{endpoint}}/api/notifier/mobile", + "raw": "{{endpoint}}/api/notifier/slack", "host": [ "{{endpoint}}" ], "path": [ "api", "notifier", - "mobile" + "slack" ] }, "description": "Update a notifier to change it's values." @@ -2077,7 +2485,7 @@ "response": [] } ], - "description": "Statping contains multiple notifiers that will send you a notification whenever a service become offline, or online. You can create your own 3rd party notifier by reading more on the [Notifiers Wiki](https://github.com/statping/statping/wiki/Notifiers) on the Github repo.", + "description": "Statping contains multiple notifiers that will send you a notification whenever a service become offline, or online. You can create your own 3rd party notifier by reading more on the [Notifiers Wiki](https://github.com/hunterlong/statping/wiki/Notifiers) on the Github repo.", "auth": { "type": "bearer", "bearer": [ @@ -2591,109 +2999,6 @@ { "name": "Checkins", "item": [ - { - "name": "Create Checkin", - "event": [ - { - "listen": "test", - "script": { - "id": "af07a95b-1bf5-42c7-bd3f-a32f3ab2a264", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Create Checkin\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.status).to.eql(\"success\");", - " pm.expect(jsonData.type).to.eql(\"checkin\");", - " pm.expect(jsonData.output.name).to.eql(\"Server Checkin\");", - " pm.expect(jsonData.output.grace).to.eql(60);", - " pm.expect(jsonData.output.interval).to.eql(900);", - " var id = jsonData.output.api_key;", - " pm.globals.set(\"checkin_id\", id);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" - }, - "url": { - "raw": "{{endpoint}}/api/checkin", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "checkin" - ] - }, - "description": "Create a new Checkin." - }, - "response": [ - { - "name": "Create Checkin", - "originalRequest": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "name": "Content-Type", - "value": "application/json", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" - }, - "url": { - "raw": "{{endpoint}}/api/checkin", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "checkin" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Date", - "value": "Mon, 10 Dec 2018 19:34:10 GMT" - }, - { - "key": "Content-Length", - "value": "330" - } - ], - "cookie": [], - "body": "{\n \"status\": \"success\",\n \"type\": \"checkin\",\n \"method\": \"create\",\n \"id\": 5,\n \"output\": {\n \"id\": 5,\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60,\n \"api_key\": \"1emn9ha\",\n \"created_at\": \"2018-12-10T19:34:10.991372Z\",\n \"updated_at\": \"2018-12-10T19:34:10.991372Z\",\n \"failing\": false,\n \"last_hit\": \"0001-01-01T00:00:00Z\",\n \"hits\": null,\n \"failures\": null\n }\n}" - } - ] - }, { "name": "View All Checkin's", "event": [ @@ -2710,10 +3015,9 @@ " var jsonData = pm.response.json();", " var first = jsonData[0];", " var id = pm.globals.get(\"checkin_id\");", - " pm.expect(first.name).to.eql(\"Server Checkin\");", - " pm.expect(first.api_key).to.eql(id);", - " pm.expect(first.grace).to.eql(60);", - " pm.expect(first.interval).to.eql(900);", + " pm.expect(first.name).to.eql(\"Demo Checkin 1\");", + " pm.expect(first.grace).to.eql(300);", + " pm.expect(first.interval).to.eql(300);", "});" ], "type": "text/javascript" @@ -2774,6 +3078,119 @@ } ] }, + { + "name": "Create Checkin", + "event": [ + { + "listen": "test", + "script": { + "id": "af07a95b-1bf5-42c7-bd3f-a32f3ab2a264", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Create Checkin\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.status).to.eql(\"success\");", + " pm.expect(jsonData.type).to.eql(\"checkin\");", + " pm.expect(jsonData.output.name).to.eql(\"Server Checkin\");", + " pm.expect(jsonData.output.grace).to.eql(60);", + " pm.expect(jsonData.output.interval).to.eql(900);", + " var id = jsonData.output.api_key;", + " pm.globals.set(\"checkin_id\", id);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" + }, + "url": { + "raw": "{{endpoint}}/api/checkins", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "checkins" + ] + }, + "description": "Create a new Checkin." + }, + "response": [ + { + "name": "Create Checkin", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60\n}" + }, + "url": { + "raw": "{{endpoint}}/api/checkin", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "checkin" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Mon, 10 Dec 2018 19:34:10 GMT" + }, + { + "key": "Content-Length", + "value": "330" + } + ], + "cookie": [], + "body": "{\n \"status\": \"success\",\n \"type\": \"checkin\",\n \"method\": \"create\",\n \"id\": 5,\n \"output\": {\n \"id\": 5,\n \"service_id\": 2,\n \"name\": \"Server Checkin\",\n \"interval\": 900,\n \"grace\": 60,\n \"api_key\": \"1emn9ha\",\n \"created_at\": \"2018-12-10T19:34:10.991372Z\",\n \"updated_at\": \"2018-12-10T19:34:10.991372Z\",\n \"failing\": false,\n \"last_hit\": \"0001-01-01T00:00:00Z\",\n \"hits\": null,\n \"failures\": null\n }\n}" + } + ] + }, { "name": "Run Checkin", "event": [ @@ -2789,7 +3206,6 @@ "pm.test(\"Hit the Checkin API Endpoint\", function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData.status).to.eql(\"success\");", - " pm.expect(jsonData.type).to.eql(\"checkin_hit\");", " pm.expect(jsonData.method).to.eql(\"update\");", "});" ], @@ -2880,13 +3296,13 @@ "method": "GET", "header": [], "url": { - "raw": "{{endpoint}}/api/checkin/{{checkin_id}}", + "raw": "{{endpoint}}/api/checkins/{{checkin_id}}", "host": [ "{{endpoint}}" ], "path": [ "api", - "checkin", + "checkins", "{{checkin_id}}" ] }, @@ -2958,6 +3374,16 @@ } ], "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, "method": "DELETE", "header": [], "body": { @@ -2965,13 +3391,13 @@ "raw": "" }, "url": { - "raw": "{{endpoint}}/api/checkin/{{checkin_id}}", + "raw": "{{endpoint}}/api/checkins/{{checkin_id}}", "host": [ "{{endpoint}}" ], "path": [ "api", - "checkin", + "checkins", "{{checkin_id}}" ] }, @@ -3045,211 +3471,6 @@ } } ] - }, - { - "name": "Miscellaneous", - "item": [ - { - "name": "Statping Details", - "event": [ - { - "listen": "test", - "script": { - "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check Core API Route\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.description).to.eql(\"Statping Monitoring Sample Data\");", - " pm.expect(jsonData.using_cdn).to.eql(false);", - " pm.expect(jsonData.config.connection).to.eql(\"sqlite\");", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{endpoint}}/api", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api" - ] - }, - "description": "The root API endpoint to view basic Statping configuration including Name, URL, database type, and other useful fields." - }, - "response": [] - }, - { - "name": "Statping Clear Cache", - "event": [ - { - "listen": "test", - "script": { - "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{endpoint}}/api/clear_cache", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "clear_cache" - ] - }, - "description": "This endpoint will clear all the cache files in your Statping instance. This includes chart data and service views." - }, - "response": [] - }, - { - "name": "Statping Reset API Tokens", - "event": [ - { - "listen": "test", - "script": { - "id": "08b8f487-2318-44b9-bdb8-f1f1041e9462", - "exec": [ - "pm.test(\"Response is ok\", function () {", - " pm.response.to.have.status(200);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{endpoint}}/api/renew", - "host": [ - "{{endpoint}}" - ], - "path": [ - "api", - "renew" - ] - }, - "description": "Reset your root API Key and Secret values to brand new values." - }, - "response": [] - } - ], - "description": "This is for Statping's miscellaneous API endpoints that aren't a part of another category.", - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{api_key}}", - "type": "string" - } - ] - }, - "event": [ - { - "listen": "prerequest", - "script": { - "id": "883519e8-7c7d-49c0-9812-d988d0179907", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "7a0738e6-2fc4-45cb-9f1a-1cd57fb76b66", - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ] - } - ], - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "event": [ - { - "listen": "prerequest", - "script": { - "id": "4eb22861-cca3-4592-a1a4-4d01bc62ee74", - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "id": "cac1a6f2-2dc3-4b09-9849-3d5aab919244", - "type": "text/javascript", - "exec": [ - "" - ] - } } ] -} +} \ No newline at end of file diff --git a/types/configs/configs_env.go b/types/configs/configs_env.go index 8ea74433..5a659825 100644 --- a/types/configs/configs_env.go +++ b/types/configs/configs_env.go @@ -1,78 +1,59 @@ package configs import ( - "github.com/joho/godotenv" - "github.com/pkg/errors" + "fmt" "github.com/statping/statping/utils" ) +func (d *DbConfig) ConnectionString() string { + var conn string + postgresSSL := utils.Params.GetString("POSTGRES_SSLMODE") + + switch d.DbConn { + case "sqlite", "sqlite3", "memory": + if d.DbConn == "memory" { + conn = "sqlite3" + d.DbConn = ":memory:" + return d.DbConn + } else { + conn, err := findDbFile(d) + if err != nil { + log.Errorln(err) + } + d.SqlFile = conn + log.Infof("SQL database file at: %s", d.SqlFile) + d.DbConn = "sqlite3" + return d.SqlFile + } + case "mysql": + host := fmt.Sprintf("%v:%v", d.DbHost, d.DbPort) + conn = fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8&parseTime=True&loc=UTC&time_zone=%%27UTC%%27", d.DbUser, d.DbPass, host, d.DbData) + return conn + case "postgres": + conn = fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v timezone=UTC sslmode=%v", d.DbHost, d.DbPort, d.DbUser, d.DbData, d.DbPass, postgresSSL) + return conn + } + return conn +} + func loadConfigEnvs() (*DbConfig, error) { - var err error - log.Infof("Loading configs from environment variables") - - loadDotEnvs() - - dbConn := utils.Getenv("DB_CONN", "").(string) - dbHost := utils.Getenv("DB_HOST", "").(string) - dbUser := utils.Getenv("DB_USER", "").(string) - dbPass := utils.Getenv("DB_PASS", "").(string) - dbData := utils.Getenv("DB_DATABASE", "").(string) - dbPort := utils.Getenv("DB_PORT", defaultPort(dbConn)).(int) - name := utils.Getenv("NAME", "Statping").(string) - desc := utils.Getenv("DESCRIPTION", "Statping Monitoring Sample Data").(string) - user := utils.Getenv("ADMIN_USER", "admin").(string) - password := utils.Getenv("ADMIN_PASS", "admin").(string) - domain := utils.Getenv("DOMAIN", "").(string) - sqlFile := utils.Getenv("SQL_FILE", "").(string) - - if dbConn != "" && dbConn != "sqlite" { - if dbHost == "" { - return nil, errors.New("Missing DB_HOST environment variable") - } - if dbPort == 0 { - return nil, errors.New("Missing DB_PORT environment variable") - } - if dbUser == "" { - return nil, errors.New("Missing DB_USER environment variable") - } - if dbPass == "" { - return nil, errors.New("Missing DB_PASS environment variable") - } - if dbData == "" { - return nil, errors.New("Missing DB_DATABASE environment variable") - } - } - + p := utils.Params config := &DbConfig{ - DbConn: dbConn, - DbHost: dbHost, - DbUser: dbUser, - DbPass: dbPass, - DbData: dbData, - DbPort: dbPort, - Project: name, - Description: desc, - Domain: domain, - Email: "", - Username: user, - Password: password, - Error: nil, + DbConn: p.GetString("DB_CONN"), + DbHost: p.GetString("DB_HOST"), + DbUser: p.GetString("DB_USER"), + DbPass: p.GetString("DB_PASS"), + DbData: p.GetString("DB_DATABASE"), + DbPort: p.GetInt("DB_PORT"), + Project: p.GetString("NAME"), + Description: p.GetString("DESCRIPTION"), + Domain: p.GetString("DOMAIN"), + Email: p.GetString("EMAIL"), + Username: p.GetString("ADMIN_USER"), + Password: p.GetString("ADMIN_PASS"), Location: utils.Directory, - SqlFile: sqlFile, - } - return config, err -} - -// loadDotEnvs attempts to load database configs from a '.env' file in root directory -func loadDotEnvs() { - err := godotenv.Overload(utils.Directory + "/" + ".env") - if err == nil { - log.Warnln("Environment file '.env' found") - envs, _ := godotenv.Read(utils.Directory + "/" + ".env") - for k, e := range envs { - log.Infof("Overwriting %s=%s\n", k, e) - } - log.Warnln("These environment variables will overwrite any existing") + SqlFile: p.GetString("SQL_FILE"), } + return config, nil } diff --git a/types/configs/configs_file.go b/types/configs/configs_file.go index e833f845..2b81a376 100644 --- a/types/configs/configs_file.go +++ b/types/configs/configs_file.go @@ -9,7 +9,6 @@ import ( func LoadConfigFile(directory string) (*DbConfig, error) { var configs *DbConfig - log.Infof("Attempting to read config file at: %s/config.yml ", directory) file, err := utils.OpenFile(directory + "/config.yml") if err != nil { diff --git a/types/configs/configs_form.go b/types/configs/configs_form.go index 893b35b9..0ac7525d 100644 --- a/types/configs/configs_form.go +++ b/types/configs/configs_form.go @@ -28,6 +28,8 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) { return nil, err } + p := utils.Params + confg := &DbConfig{ DbConn: dbConn, DbHost: dbHost, @@ -41,10 +43,18 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) { Username: username, Password: password, Email: email, - Error: nil, Location: utils.Directory, } + p.Set("DB_CONN", dbConn) + p.Set("DB_HOST", dbHost) + p.Set("DB_USER", dbUser) + p.Set("DB_PORT", dbPort) + p.Set("DB_PASS", dbPass) + p.Set("DB_DATABASE", dbDatabase) + p.Set("NAME", project) + p.Set("DESCRIPTION", description) + return confg, nil } diff --git a/types/configs/connection.go b/types/configs/connection.go index 29c5eaf4..84ae3bb3 100644 --- a/types/configs/connection.go +++ b/types/configs/connection.go @@ -17,45 +17,19 @@ import ( "github.com/statping/statping/types/services" "github.com/statping/statping/types/users" "github.com/statping/statping/utils" - "os" "time" ) // Connect will attempt to connect to the sqlite, postgres, or mysql database func Connect(configs *DbConfig, retry bool) error { - postgresSSL := os.Getenv("POSTGRES_SSLMODE") - var conn string + conn := configs.ConnectionString() var err error - switch configs.DbConn { - case "sqlite", "sqlite3", "memory": - if configs.DbConn == "memory" { - conn = "sqlite3" - configs.DbConn = ":memory:" - } else { - conn = findDbFile(configs) - configs.SqlFile = conn - log.Infof("SQL database file at: %s", configs.SqlFile) - configs.DbConn = "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) - 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) - 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) - } log.WithFields(utils.ToFields(configs, conn)).Debugln("attempting to connect to database") dbSession, err := database.Openw(configs.DbConn, conn) if err != nil { - log.Debugln(fmt.Sprintf("Database connection error %s", err)) + log.Errorf(fmt.Sprintf("Database connection error %s", err)) if retry { log.Warnln(fmt.Sprintf("Database %s connection to '%s' is not available, trying again in 5 seconds...", configs.DbConn, configs.DbHost)) time.Sleep(5 * time.Second) @@ -65,20 +39,20 @@ func Connect(configs *DbConfig, retry bool) error { } } - apiKey := utils.Getenv("API_KEY", utils.RandomString(16)).(string) - apiSecret := utils.Getenv("API_SECRET", utils.RandomString(16)).(string) + apiKey := utils.Getenv("API_KEY", utils.RandomString(24)).(string) + apiSecret := utils.Getenv("API_SECRET", utils.RandomString(24)).(string) configs.ApiKey = apiKey configs.ApiSecret = apiSecret log.WithFields(utils.ToFields(dbSession)).Debugln("connected to database") - maxOpenConn := utils.Getenv("MAX_OPEN_CONN", 25) - maxIdleConn := utils.Getenv("MAX_IDLE_CONN", 25) - maxLifeConn := utils.Getenv("MAX_LIFE_CONN", 5*time.Minute) + maxOpenConn := utils.Params.GetInt("MAX_OPEN_CONN") + maxIdleConn := utils.Params.GetInt("MAX_IDLE_CONN") + maxLifeConn := utils.Params.GetDuration("MAX_LIFE_CONN") - dbSession.DB().SetMaxOpenConns(maxOpenConn.(int)) - dbSession.DB().SetMaxIdleConns(maxIdleConn.(int)) - dbSession.DB().SetConnMaxLifetime(maxLifeConn.(time.Duration)) + dbSession.DB().SetMaxOpenConns(maxOpenConn) + dbSession.DB().SetMaxIdleConns(maxIdleConn) + dbSession.DB().SetConnMaxLifetime(maxLifeConn) if dbSession.DB().Ping() == nil { if utils.VerboseMode >= 4 { diff --git a/types/configs/database.go b/types/configs/database.go index 60d81eaf..74abbe96 100644 --- a/types/configs/database.go +++ b/types/configs/database.go @@ -102,10 +102,12 @@ func (d *DbConfig) CreateDatabase() error { log.Infoln("Creating Database Tables...") for _, table := range DbModels { + log.Infof("Creating table '%T'", table) if err := d.Db.CreateTable(table); err.Error() != nil { return errors.Wrap(err.Error(), fmt.Sprintf("error creating '%T' table", table)) } } + log.Infof("Creating table 'core'") if err := d.Db.Table("core").CreateTable(&core.Core{}); err.Error() != nil { return errors.Wrap(err.Error(), fmt.Sprintf("error creating 'core' table")) } diff --git a/types/configs/file.go b/types/configs/file.go index 366c3085..4f3f7e9c 100644 --- a/types/configs/file.go +++ b/types/configs/file.go @@ -1,11 +1,11 @@ package configs import ( - "fmt" "github.com/pkg/errors" "github.com/statping/statping/utils" "os" "path/filepath" + "strings" ) var log = utils.Log @@ -18,7 +18,6 @@ func ConnectConfigs(configs *DbConfig) error { if err := configs.Save(utils.Directory); err != nil { return errors.Wrap(err, "error saving configuration") } - return nil } @@ -31,8 +30,7 @@ func LoadConfigs() (*DbConfig, error) { return nil, errors.Errorf("Directory %s is not writable!", utils.Directory) } - dbConn := utils.Getenv("DB_CONN", "").(string) - if dbConn != "" { + if utils.Params.GetString("DB_CONN") != "" { configs, err := loadConfigEnvs() if err != nil { return LoadConfigFile(utils.Directory) @@ -43,30 +41,39 @@ func LoadConfigs() (*DbConfig, error) { return LoadConfigFile(utils.Directory) } -func findDbFile(configs *DbConfig) string { +func findDbFile(configs *DbConfig) (string, error) { + location := utils.Directory + "/" + SqliteFilename if configs == nil { - return findSQLin(utils.Directory) + file, err := findSQLin(utils.Directory) + if err != nil { + return "", err + } + location = file } - if configs.SqlFile != "" { - return configs.SqlFile + if configs != nil && configs.SqlFile != "" { + return configs.SqlFile, nil } - return utils.Directory + "/" + SqliteFilename + return location, nil } -func findSQLin(path string) string { +func findSQLin(path string) (string, error) { filename := SqliteFilename + var found []string err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } if filepath.Ext(path) == ".db" { - fmt.Println("DB file is now: ", info.Name()) filename = info.Name() + found = append(found, filename) } return nil }) if err != nil { - log.Error(err) + return filename, err } - return filename + if len(found) > 1 { + return filename, errors.Errorf("found multiple database files: %s", strings.Join(found, ", ")) + } + return filename, nil } diff --git a/types/configs/latest_sql.go b/types/configs/latest_sql.go index b179bcd8..7ae6f02b 100644 --- a/types/configs/latest_sql.go +++ b/types/configs/latest_sql.go @@ -12,58 +12,58 @@ func init() { os.Setenv("MIGRATION_ID", utils.ToString(latestMigration)) } -func (c *DbConfig) genericMigration(alterStr string, isPostgres bool) error { +func (d *DbConfig) genericMigration(alterStr string, isPostgres bool) error { var extra string extraType := "UNSIGNED INTEGER" if isPostgres { extra = " TYPE" extraType = "bigint" } - if err := c.Db.Exec(fmt.Sprintf("ALTER TABLE hits %s COLUMN latency%s BIGINT;", alterStr, extra)).Error(); err != nil { + if err := d.Db.Exec(fmt.Sprintf("ALTER TABLE hits %s COLUMN latency%s BIGINT;", alterStr, extra)).Error(); err != nil { return err } - if err := c.Db.Exec(fmt.Sprintf("ALTER TABLE hits %s COLUMN ping_time%s BIGINT;", alterStr, extra)).Error(); err != nil { + if err := d.Db.Exec(fmt.Sprintf("ALTER TABLE hits %s COLUMN ping_time%s BIGINT;", alterStr, extra)).Error(); err != nil { return err } - if err := c.Db.Exec(fmt.Sprintf("ALTER TABLE failures %s COLUMN ping_time%s BIGINT;", alterStr, extra)).Error(); err != nil { + if err := d.Db.Exec(fmt.Sprintf("ALTER TABLE failures %s COLUMN ping_time%s BIGINT;", alterStr, extra)).Error(); err != nil { return err } - if err := c.Db.Exec(fmt.Sprintf("UPDATE hits SET latency = CAST(latency * 1000000 AS %s);", extraType)).Error(); err != nil { + if err := d.Db.Exec(fmt.Sprintf("UPDATE hits SET latency = CAST(latency * 1000000 AS %s);", extraType)).Error(); err != nil { return err } - if err := c.Db.Exec(fmt.Sprintf("UPDATE hits SET ping_time = CAST(ping_time * 1000000 AS %s);", extraType)).Error(); err != nil { + if err := d.Db.Exec(fmt.Sprintf("UPDATE hits SET ping_time = CAST(ping_time * 1000000 AS %s);", extraType)).Error(); err != nil { return err } - if err := c.Db.Exec(fmt.Sprintf("UPDATE failures SET ping_time = CAST(ping_time * 1000000 AS %s);", extraType)).Error(); err != nil { + if err := d.Db.Exec(fmt.Sprintf("UPDATE failures SET ping_time = CAST(ping_time * 1000000 AS %s);", extraType)).Error(); err != nil { return err } return nil } -func (c *DbConfig) sqliteMigration() error { - if err := c.Db.Exec(`ALTER TABLE hits RENAME TO hits_backup;`).Error(); err != nil { +func (d *DbConfig) sqliteMigration() error { + if err := d.Db.Exec(`ALTER TABLE hits RENAME TO hits_backup;`).Error(); err != nil { return err } - if err := c.Db.Exec(`CREATE TABLE hits (id INTEGER PRIMARY KEY AUTOINCREMENT, service bigint, latency bigint, ping_time bigint, created_at datetime);`).Error(); err != nil { + if err := d.Db.Exec(`CREATE TABLE hits (id INTEGER PRIMARY KEY AUTOINCREMENT, service bigint, latency bigint, ping_time bigint, created_at datetime);`).Error(); err != nil { return err } - if err := c.Db.Exec(`INSERT INTO hits (id, service, latency, ping_time, created_at) SELECT id, service, CAST(latency * 1000000 AS bigint), CAST(ping_time * 1000000 AS bigint), created_at FROM hits_backup;`).Error(); err != nil { + if err := d.Db.Exec(`INSERT INTO hits (id, service, latency, ping_time, created_at) SELECT id, service, CAST(latency * 1000000 AS bigint), CAST(ping_time * 1000000 AS bigint), created_at FROM hits_backup;`).Error(); err != nil { return err } // failures table - if err := c.Db.Exec(`ALTER TABLE failures RENAME TO failures_backup;`).Error(); err != nil { + if err := d.Db.Exec(`ALTER TABLE failures RENAME TO failures_backup;`).Error(); err != nil { return err } - if err := c.Db.Exec(`CREATE TABLE failures (id INTEGER PRIMARY KEY AUTOINCREMENT, issue varchar(255), method varchar(255), method_id bigint, service bigint, ping_time bigint, checkin bigint, error_code bigint, created_at datetime);`).Error(); err != nil { + if err := d.Db.Exec(`CREATE TABLE failures (id INTEGER PRIMARY KEY AUTOINCREMENT, issue varchar(255), method varchar(255), method_id bigint, service bigint, ping_time bigint, checkin bigint, error_code bigint, created_at datetime);`).Error(); err != nil { return err } - if err := c.Db.Exec(`INSERT INTO failures (id, issue, method, method_id, service, ping_time, checkin, created_at) SELECT id, issue, method, method_id, service, CAST(ping_time * 1000000 AS bigint), checkin, created_at FROM failures_backup;`).Error(); err != nil { + if err := d.Db.Exec(`INSERT INTO failures (id, issue, method, method_id, service, ping_time, checkin, created_at) SELECT id, issue, method, method_id, service, CAST(ping_time * 1000000 AS bigint), checkin, created_at FROM failures_backup;`).Error(); err != nil { return err } - if err := c.Db.Exec(`DROP TABLE hits_backup;`).Error(); err != nil { + if err := d.Db.Exec(`DROP TABLE hits_backup;`).Error(); err != nil { return err } - if err := c.Db.Exec(`DROP TABLE failures_backup;`).Error(); err != nil { + if err := d.Db.Exec(`DROP TABLE failures_backup;`).Error(); err != nil { return err } return nil diff --git a/types/configs/methods.go b/types/configs/methods.go index 7bb4e9d2..bb910685 100644 --- a/types/configs/methods.go +++ b/types/configs/methods.go @@ -1,21 +1,12 @@ package configs -import ( - "gopkg.in/yaml.v2" - "io/ioutil" - "os" -) +import "github.com/statping/statping/utils" // Save will initially create the config.yml file func (d *DbConfig) Save(directory string) error { - data, err := yaml.Marshal(d) - if err != nil { - return err + if err := utils.Params.SafeWriteConfigAs(directory + "/config.yml"); err != nil { + return nil } - if err := ioutil.WriteFile(directory+"/config.yml", data, os.ModePerm); err != nil { - return err - } - d.filename = directory + "/config.yml" return nil } diff --git a/types/configs/migration.go b/types/configs/migration.go index 361305e5..def9c29f 100644 --- a/types/configs/migration.go +++ b/types/configs/migration.go @@ -20,33 +20,33 @@ import ( "github.com/statping/statping/types/users" ) -func (c *DbConfig) DatabaseChanges() error { +func (d *DbConfig) DatabaseChanges() error { var cr core.Core - c.Db.Model(&core.Core{}).Find(&cr) + d.Db.Model(&core.Core{}).Find(&cr) if latestMigration > cr.MigrationId { log.Infof("Statping database is out of date, migrating to: %d", latestMigration) - switch c.Db.DbType() { + switch d.Db.DbType() { case "mysql": - if err := c.genericMigration("MODIFY", false); err != nil { + if err := d.genericMigration("MODIFY", false); err != nil { return err } case "postgres": - if err := c.genericMigration("ALTER", true); err != nil { + if err := d.genericMigration("ALTER", true); err != nil { return err } default: - if err := c.sqliteMigration(); err != nil { + if err := d.sqliteMigration(); err != nil { return err } } - if err := c.Db.Exec(fmt.Sprintf("UPDATE core SET migration_id = %d", latestMigration)).Error(); err != nil { + if err := d.Db.Exec(fmt.Sprintf("UPDATE core SET migration_id = %d", latestMigration)).Error(); err != nil { return err } - if err := c.BackupAssets(); err != nil { + if err := d.BackupAssets(); err != nil { return err } } @@ -55,7 +55,7 @@ func (c *DbConfig) DatabaseChanges() error { // BackupAssets is a temporary function (to version 0.90.*) to backup your customized theme // to a new folder called 'assets_backup'. -func (c *DbConfig) BackupAssets() error { +func (d *DbConfig) BackupAssets() error { if source.UsingAssets(utils.Directory) { log.Infof("Backing up 'assets' folder to 'assets_backup'") if err := utils.RenameDirectory(utils.Directory+"/assets", utils.Directory+"/assets_backup"); err != nil { @@ -69,12 +69,12 @@ func (c *DbConfig) BackupAssets() 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 (c *DbConfig) MigrateDatabase() error { +func (d *DbConfig) MigrateDatabase() error { var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}} log.Infoln("Migrating Database Tables...") - tx := c.Db.Begin() + tx := d.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() @@ -99,27 +99,27 @@ func (c *DbConfig) MigrateDatabase() error { return err } - c.Db.Table("core").Model(&core.Core{}).Update("version", core.App.Version) + d.Db.Table("core").Model(&core.Core{}).Update("version", core.App.Version) log.Infoln("Statping Database Tables Migrated") - if err := c.Db.Model(&hits.Hit{}).AddIndex("idx_service_hit", "service").Error(); err != nil { + if err := d.Db.Model(&hits.Hit{}).AddIndex("idx_service_hit", "service").Error(); err != nil { log.Errorln(err) } - if err := c.Db.Model(&hits.Hit{}).AddIndex("hit_created_at", "created_at").Error(); err != nil { + if err := d.Db.Model(&hits.Hit{}).AddIndex("hit_created_at", "created_at").Error(); err != nil { log.Errorln(err) } - if err := c.Db.Model(&failures.Failure{}).AddIndex("fail_created_at", "created_at").Error(); err != nil { + if err := d.Db.Model(&failures.Failure{}).AddIndex("fail_created_at", "created_at").Error(); err != nil { log.Errorln(err) } - if err := c.Db.Model(&failures.Failure{}).AddIndex("idx_service_fail", "service").Error(); err != nil { + if err := d.Db.Model(&failures.Failure{}).AddIndex("idx_service_fail", "service").Error(); err != nil { log.Errorln(err) } - if err := c.Db.Model(&failures.Failure{}).AddIndex("idx_checkin_fail", "checkin").Error(); err != nil { + if err := d.Db.Model(&failures.Failure{}).AddIndex("idx_checkin_fail", "checkin").Error(); err != nil { log.Errorln(err) } log.Infoln("Database Indexes Created") diff --git a/types/core/database.go b/types/core/database.go index 1bac64db..a07b98d5 100644 --- a/types/core/database.go +++ b/types/core/database.go @@ -5,8 +5,6 @@ import ( "github.com/statping/statping/database" "github.com/statping/statping/types/null" "github.com/statping/statping/utils" - "os" - "time" ) var db database.Database @@ -31,32 +29,25 @@ func Select() (*Core, error) { } App = &c - if os.Getenv("USE_CDN") == "true" { + if utils.Params.GetBool("USE_CDN") { App.UseCdn = null.NewNullBool(true) } - if os.Getenv("ALLOW_REPORTS") == "true" { + if utils.Params.GetBool("ALLOW_REPORTS") { App.AllowReports = null.NewNullBool(true) } return App, q.Error() } func (c *Core) Create() error { - apiKey := utils.Getenv("API_KEY", utils.NewSHA256Hash()).(string) - apiSecret := utils.Getenv("API_SECRET", utils.NewSHA256Hash()).(string) - - if c.ApiKey == "" || c.ApiSecret == "" { - c.ApiSecret = apiSecret - c.ApiKey = apiKey - } newCore := &Core{ Name: c.Name, Description: c.Description, ConfigFile: utils.Directory + "/config.yml", - ApiKey: c.ApiKey, - ApiSecret: c.ApiSecret, + ApiKey: utils.Params.GetString("API_KEY"), + ApiSecret: utils.Params.GetString("API_SECRET"), Version: App.Version, Domain: c.Domain, - MigrationId: time.Now().Unix(), + MigrationId: utils.Now().Unix(), } q := db.Create(&newCore) return q.Error() diff --git a/types/failures/samples.go b/types/failures/samples.go index d1535b77..06e53297 100644 --- a/types/failures/samples.go +++ b/types/failures/samples.go @@ -34,7 +34,6 @@ func Samples() error { log.Infoln(fmt.Sprintf("Adding %v Failure records to service", 400)) for fi := 0.; fi <= float64(400); fi++ { - createdAt = createdAt.Add(35 * time.Minute) failure := &Failure{ Service: i, Issue: "testing right here", @@ -42,6 +41,7 @@ func Samples() error { } tx = tx.Create(&failure) + createdAt = createdAt.Add(35 * time.Minute) } if err := tx.Commit().Error(); err != nil { log.Error(err) diff --git a/types/hits/samples.go b/types/hits/samples.go index 25363ffd..4ad8d820 100644 --- a/types/hits/samples.go +++ b/types/hits/samples.go @@ -2,46 +2,40 @@ package hits import ( "fmt" - "github.com/statping/statping/database" - "github.com/statping/statping/types" - "github.com/statping/statping/utils" - "sync" - "time" - _ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/postgres" _ "github.com/mattn/go-sqlite3" + "github.com/statping/statping/database" + "github.com/statping/statping/types" + "github.com/statping/statping/utils" + "time" ) var SampleHits = 99900. func Samples() error { - tx := db.Begin() - sg := new(sync.WaitGroup) - for i := int64(1); i <= 5; i++ { - err := createHitsAt(tx, i, sg) - if err != nil { + tx := db.Begin() + tx = createHitsAt(tx, i) + + if err := tx.Commit().Error(); err != nil { log.Error(err) + return err } - tx = db.Begin() } - return tx.Error() + return nil } -func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) error { - log.Infoln(fmt.Sprintf("Adding sample hit records to service #%d", serviceID)) +func createHitsAt(db database.Database, serviceID int64) database.Database { + log.Infoln(fmt.Sprintf("Adding Sample records to service #%d", serviceID)) createdAt := utils.Now().Add(-3 * types.Day) p := utils.NewPerlin(2, 2, 5, utils.Now().UnixNano()) - i := 0 for hi := 0.; hi <= SampleHits; hi++ { latency := p.Noise1D(hi / 500) - createdAt = createdAt.Add(30 * time.Second) - hit := &Hit{ Service: serviceID, Latency: int64(latency * 10000000), @@ -50,15 +44,12 @@ func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) err } db = db.Create(&hit) - if err := db.Error(); err != nil { - return err - } - i++ if createdAt.After(utils.Now()) { break } + createdAt = createdAt.Add(30 * time.Second) } - return db.Commit().Error() + return db } diff --git a/utils/configs.go b/utils/configs.go new file mode 100644 index 00000000..3bc7b136 --- /dev/null +++ b/utils/configs.go @@ -0,0 +1,70 @@ +package utils + +import ( + "github.com/prometheus/common/log" + "github.com/spf13/viper" + "os" + "time" +) + +var ( + Params *viper.Viper +) + +func InitCLI() { + Params = viper.New() + setDefaults() + Params.SetConfigName("config") + Params.SetConfigType("yml") + Params.AddConfigPath(".") + err := Params.ReadInConfig() + if err != nil { + log.Debugf("config.yml Fatal error config file: %s", err) + } + + Params.AddConfigPath(".") + Params.SetConfigFile(".env") + err = Params.ReadInConfig() + if err != nil { + log.Debugf(".env Fatal error config file: %s", err) + } + + Params.AutomaticEnv() + if err != nil { + log.Debugf("No environment variables found: %s", err) + } +} + +func setDefaults() { + defaultDir, err := os.Getwd() + if err != nil { + defaultDir = "." + } + Params.SetDefault("STATPING_DIR", defaultDir) + Directory = Params.GetString("STATPING_DIR") + Params.SetDefault("GO_ENV", "") + Params.SetDefault("DISABLE_LOGS", false) + Params.SetDefault("BASE_PATH", "") + Params.SetDefault("MAX_OPEN_CONN", 25) + Params.SetDefault("MAX_IDLE_CONN", 25) + Params.SetDefault("MAX_LIFE_CONN", 5*time.Minute) + Params.SetDefault("API_KEY", RandomString(32)) + Params.SetDefault("API_SECRET", RandomString(32)) + Params.SetDefault("SAMPLE_DATA", true) + Params.SetDefault("USE_CDN", false) + Params.SetDefault("ALLOW_REPORTS", false) + Params.SetDefault("AUTH_USERNAME", "") + Params.SetDefault("AUTH_PASSWORD", "") + Params.SetDefault("POSTGRES_SSLMODE", "disable") + + dbConn := Params.GetString("DB_CONN") + dbInt := Params.GetInt("DB_PORT") + if dbInt == 0 && dbConn != "sqlite" && dbConn != "sqlite3" { + if dbConn == "postgres" { + Params.SetDefault("DB_PORT", 5432) + } + if dbConn == "mysql" { + Params.SetDefault("DB_PORT", 3306) + } + } +} diff --git a/utils/utils.go b/utils/utils.go index 65ec0b73..a2b682ac 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -25,15 +25,9 @@ var ( // init will set the utils.Directory to the current running directory, or STATPING_DIR if it is set func init() { - defaultDir, err := os.Getwd() - if err != nil { - defaultDir = "." - } - - Directory = Getenv("STATPING_DIR", defaultDir).(string) - + InitCLI() // check if logs are disabled - disableLogs = Getenv("DISABLE_LOGS", false).(bool) + disableLogs = Params.GetBool("DISABLE_LOGS") if disableLogs { Log.Out = ioutil.Discard } @@ -63,28 +57,20 @@ func (e *env) Duration() time.Duration { } func Getenv(key string, defaultValue interface{}) interface{} { - if val, ok := os.LookupEnv(key); ok { - if val != "" { - switch d := defaultValue.(type) { - - case int, int64: - return int(ToInt(val)) - - case time.Duration: - dur, err := time.ParseDuration(val) - if err != nil { - return d - } - return dur - case bool: - ok, err := strconv.ParseBool(val) - if err != nil { - return d - } - return ok - default: - return val - } + if defaultValue != nil { + Params.SetDefault(key, defaultValue) + } + val := Params.Get(key) + if val != nil { + switch val.(type) { + case int, int64: + return Params.GetInt(key) + case time.Duration: + return Params.GetDuration(key) + case bool: + return Params.GetBool(key) + default: + return val } } return defaultValue diff --git a/version.txt b/version.txt index 708a7d94..adcbed07 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.90.27 +0.90.28