From d9e3cabb4ee6ae1625a6f7de3f80e83c192a885d Mon Sep 17 00:00:00 2001 From: hunterlong Date: Thu, 30 Apr 2020 01:35:33 -0700 Subject: [PATCH] remove API_KEY (unused code), just use API_SECRET, YAML unmarshal, services.yml services auto creation --- .github/workflows/dev.yml | 20 +--- .github/workflows/master.yml | 2 +- .gitignore | 1 + CHANGELOG.md | 2 + cmd/main.go | 8 +- dev/docker-compose.full.yml | 4 - dev/docker-compose.lite.yml | 1 - dev/pwd-stack.yml | 35 ++++++- .../cypress/integration/notifiers_spec.js | 1 - frontend/cypress/integration/settings_spec.js | 2 - frontend/src/pages/Settings.vue | 13 --- handlers/routes.go | 1 + handlers/setup.go | 1 - types/configs/connection.go | 2 - types/configs/load.go | 3 - types/configs/struct.go | 1 - types/core/struct.go | 1 - types/null/marshal.go | 37 ++++++- types/null/unmarshal.go | 40 ++++++++ types/services/env.go | 59 ----------- types/services/methods.go | 54 ---------- types/services/struct.go | 98 +++++++++---------- types/services/yaml.go | 47 +++++++++ 23 files changed, 212 insertions(+), 221 deletions(-) delete mode 100644 types/services/env.go create mode 100644 types/services/yaml.go diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 87f7e784..39a3b870 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -116,7 +116,7 @@ jobs: VERSION: ${{ env.VERSION }} DB_CONN: sqlite3 STATPING_DIR: ${{ github.workspace }} - API_KEY: demopassword123 + API_SECRET: demopassword123 DISABLE_LOGS: true ALLOW_REPORTS: true PUSH_REQUEST: true @@ -164,21 +164,3 @@ jobs: environment: ./dev/postman_environment.json timeoutRequest: 15000 delayRequest: 1000 - - pr-slack-update: - needs: [pr-test, pr-test-postman] - runs-on: ubuntu-latest - steps: - - name: Checkout Statping Repo - uses: actions/checkout@v2 - - - name: Setting ENV's - run: echo ::set-env name=VERSION::$(cat version.txt) - shell: bash - - - name: Slack Notification - uses: rtCamp/action-slack-notify@v2.0.0 - env: - SLACK_WEBHOOK: ${{ secrets.SLACK_URL }} - SLACK_CHANNEL: pull-requests - SLACK_USERNAME: StatpingDev diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 64692e9b..5ea53174 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -113,7 +113,7 @@ jobs: VERSION: ${{ env.VERSION }} DB_CONN: sqlite3 STATPING_DIR: ${{ github.workspace }} - API_KEY: demopassword123 + API_SECRET: demopassword123 DISABLE_LOGS: true ALLOW_REPORTS: true COVERALLS: ${{ secrets.COVERALLS }} diff --git a/.gitignore b/.gitignore index 05561da2..a68fd1af 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ docker tmp /frontend/cypress/screenshots/ /frontend/cypress/videos/ +services.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 421a92a0..336b1c0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Upcoming - Added missing information to Mail notification ([#472](https://github.com/statping/statping/issues/472)) +- Added service.yml file to auto create services (https://github.com/statping/statping/wiki/services.yml) +- Removed Core API_KEY, (unused code, use API_SECRET) # 0.90.33 (04-24-2020) - Fixed config loading method diff --git a/cmd/main.go b/cmd/main.go index c3fb1443..4adb1595 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -153,16 +153,12 @@ func sigterm() { // mainProcess will initialize the Statping application and run the HTTP server func mainProcess() error { - if err := services.ServicesFromEnvFile(); err != nil { - errStr := "error 'SERVICE' environment variable" - log.Errorln(errStr) - return errors.Wrap(err, errStr) - } - if err := InitApp(); err != nil { return err } + services.LoadServicesYaml() + if err := handlers.RunHTTPServer(ipAddress, port); err != nil { log.Fatalln(err) return errors.Wrap(err, "http server") diff --git a/dev/docker-compose.full.yml b/dev/docker-compose.full.yml index dd14dedf..b293b5ce 100644 --- a/dev/docker-compose.full.yml +++ b/dev/docker-compose.full.yml @@ -27,7 +27,6 @@ services: # VIRTUAL_PORT: 8888 # GO_ENV: test # DB_CONN: sqlite -# API_KEY: exampleapikey # API_SECRET: exampleapisecret # NAME: Statping on SQLite # DOMAIN: http://localhost:4000 @@ -59,7 +58,6 @@ services: VIRTUAL_HOST: sqlite.dev.statping.com VIRTUAL_PORT: 8080 DB_CONN: sqlite - API_KEY: exampleapikey API_SECRET: exampleapisecret NAME: Statping on SQLite DOMAIN: http://localhost:4000 @@ -96,7 +94,6 @@ services: DB_DATABASE: statping DB_USER: root DB_PASS: password123 - API_KEY: exampleapikey API_SECRET: exampleapisecret NAME: Statping on MySQL DOMAIN: http://localhost:4005 @@ -134,7 +131,6 @@ services: DB_DATABASE: statping DB_USER: root DB_PASS: password123 - API_KEY: exampleapikey API_SECRET: exampleapisecret NAME: Statping on Postgres DOMAIN: http://localhost:4010 diff --git a/dev/docker-compose.lite.yml b/dev/docker-compose.lite.yml index 544b1bec..65c47a68 100644 --- a/dev/docker-compose.lite.yml +++ b/dev/docker-compose.lite.yml @@ -19,7 +19,6 @@ services: - ./utils:/go/src/github.com/statping/statping/utils/ environment: DB_CONN: sqlite - API_KEY: exampleapikey API_SECRET: exampleapisecret NAME: Statping DOMAIN: http://localhost:8585 diff --git a/dev/pwd-stack.yml b/dev/pwd-stack.yml index dcbe254d..602f5612 100644 --- a/dev/pwd-stack.yml +++ b/dev/pwd-stack.yml @@ -7,14 +7,43 @@ services: image: statping/statping ports: - 8080:8080 + networks: + - backend + volumes: + - /root/statping:/app environment: PORT: 8080 - SERVICES: '[{"name": "Local Statping", "type": "http", "domain": "http://localhost:8585", "interval": 30}]' - DB_CONN: sqlite - API_KEY: exampleapikey API_SECRET: exampleapisecret NAME: Statping on SQLite DOMAIN: http://localhost:8080 DESCRIPTION: This is a dev environment on SQLite! ADMIN_USER: admin ADMIN_PASS: admin + + postgres: + hostname: postgres + image: postgres + environment: + POSTGRES_PASSWORD: password123 + POSTGRES_DB: statping + POSTGRES_USER: root + networks: + - backend + volumes: + - /root/postgres:/var/lib/postgresql/data + + mysql: + hostname: mysql + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: password123 + MYSQL_DATABASE: statping + MYSQL_USER: root + MYSQL_PASSWORD: password123 + networks: + - backend + volumes: + - /root/mysql:/var/lib/mysql + +networks: + backend: diff --git a/frontend/cypress/integration/notifiers_spec.js b/frontend/cypress/integration/notifiers_spec.js index 9f3e2074..5c20cf7e 100644 --- a/frontend/cypress/integration/notifiers_spec.js +++ b/frontend/cypress/integration/notifiers_spec.js @@ -30,7 +30,6 @@ context('Notifier Tests', () => { cy.visit('/dashboard/settings') cy.get('#notifiers_tabs > a').should('have.length', 10) - cy.get('#api_key').should('not.have.value', '') cy.get('#api_secret').should('not.have.value', '') }) diff --git a/frontend/cypress/integration/settings_spec.js b/frontend/cypress/integration/settings_spec.js index 14992041..c92fd1d2 100644 --- a/frontend/cypress/integration/settings_spec.js +++ b/frontend/cypress/integration/settings_spec.js @@ -29,7 +29,6 @@ context('Settings Tests', () => { cy.visit('/dashboard/settings') cy.get('#notifiers_tabs > a').should('have.length', 10) - cy.get('#api_key').should('not.have.value', '') cy.get('#api_secret').should('not.have.value', '') }) @@ -50,7 +49,6 @@ context('Settings Tests', () => { cy.get('#description').should('have.value', 'Statping can use Cypress e2e testing to make it more stable!') cy.get('#domain').should('have.value', 'http://localhost:8888') cy.get('#footer').should('have.value', 'Statping Custom Footer') - cy.get('#api_key').should('not.have.value', '') cy.get('#api_secret').should('not.have.value', '') }) diff --git a/frontend/src/pages/Settings.vue b/frontend/src/pages/Settings.vue index 237f709e..0c378147 100644 --- a/frontend/src/pages/Settings.vue +++ b/frontend/src/pages/Settings.vue @@ -67,19 +67,6 @@
API Settings
-
- -
-
- -
- -
-
- API Key can be used for read only routes -
-
-
diff --git a/handlers/routes.go b/handlers/routes.go index 0b46d1e9..5dca6257 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -80,6 +80,7 @@ func Router() *mux.Router { api.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false)) api.Handle("/api/core", authenticated(apiCoreHandler, false)).Methods("POST") api.Handle("/api/oauth", scoped(apiOAuthHandler)).Methods("GET") + api.Handle("/api/oauth/{provider}", http.HandlerFunc(oauthHandler)) api.Handle("/api/logs", authenticated(logsHandler, false)).Methods("GET") api.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET") diff --git a/handlers/setup.go b/handlers/setup.go index e6f11645..9edae620 100644 --- a/handlers/setup.go +++ b/handlers/setup.go @@ -78,7 +78,6 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) { c := &core.Core{ Name: project, Description: description, - ApiKey: utils.Params.GetString("API_KEY"), ApiSecret: utils.Params.GetString("API_SECRET"), Domain: domain, Version: core.App.Version, diff --git a/types/configs/connection.go b/types/configs/connection.go index 0179780d..ea5023de 100644 --- a/types/configs/connection.go +++ b/types/configs/connection.go @@ -40,9 +40,7 @@ func Connect(configs *DbConfig, retry bool) error { } } - apiKey := p.GetString("API_KEY") apiSecret := p.GetString("API_SECRET") - configs.ApiKey = apiKey configs.ApiSecret = apiSecret log.WithFields(utils.ToFields(dbSession)).Debugln("connected to database") diff --git a/types/configs/load.go b/types/configs/load.go index a10a6618..9fd8be1f 100644 --- a/types/configs/load.go +++ b/types/configs/load.go @@ -46,9 +46,6 @@ func LoadConfigFile(directory string) (*DbConfig, error) { if db.Location != "" { p.Set("LOCATION", db.Location) } - if db.ApiKey != "" { - p.Set("API_KEY", db.ApiKey) - } if db.ApiSecret != "" { p.Set("API_SECRET", db.ApiSecret) } diff --git a/types/configs/struct.go b/types/configs/struct.go index f85c72e8..6b0e14a6 100644 --- a/types/configs/struct.go +++ b/types/configs/struct.go @@ -12,7 +12,6 @@ type DbConfig struct { DbPass string `yaml:"password" json:"-"` DbData string `yaml:"database" json:"-"` DbPort int `yaml:"port" json:"-"` - ApiKey string `yaml:"api_key" json:"-"` ApiSecret string `yaml:"api_secret" json:"-"` Project string `yaml:"-" json:"-"` Description string `yaml:"-" json:"-"` diff --git a/types/core/struct.go b/types/core/struct.go index a7473356..75ad7106 100644 --- a/types/core/struct.go +++ b/types/core/struct.go @@ -23,7 +23,6 @@ type Core struct { Name string `gorm:"not null;column:name" json:"name,omitempty"` Description string `gorm:"not null;column:description" json:"description,omitempty"` ConfigFile string `gorm:"column:config" json:"-"` - ApiKey string `gorm:"column:api_key" json:"api_key" scope:"admin"` ApiSecret string `gorm:"column:api_secret" json:"api_secret" scope:"admin"` Style string `gorm:"not null;column:style" json:"style,omitempty"` Footer null.NullString `gorm:"column:footer" json:"footer"` diff --git a/types/null/marshal.go b/types/null/marshal.go index 345646cb..1b7a51eb 100644 --- a/types/null/marshal.go +++ b/types/null/marshal.go @@ -1,6 +1,9 @@ package null -import "encoding/json" +import ( + "encoding/json" + "gopkg.in/yaml.v2" +) // MarshalJSON for NullInt64 func (i NullInt64) MarshalJSON() ([]byte, error) { @@ -33,3 +36,35 @@ func (s NullString) MarshalJSON() ([]byte, error) { } return json.Marshal(s.String) } + +// MarshalJSON for NullInt64 +func (i NullInt64) MarshalYAML() (interface{}, error) { + if !i.Valid { + return 0, nil + } + return yaml.Marshal(i.Int64) +} + +// MarshalJSON for NullFloat64 +func (f NullFloat64) MarshalYAML() (interface{}, error) { + if !f.Valid { + return 0.0, nil + } + return yaml.Marshal(f.Float64) +} + +// MarshalJSON for NullBool +func (bb NullBool) MarshalYAML() (interface{}, error) { + if !bb.Valid { + return false, nil + } + return yaml.Marshal(bb.Bool) +} + +// MarshalJSON for NullString +func (s NullString) MarshalYAML() (interface{}, error) { + if !s.Valid { + return "", nil + } + return yaml.Marshal(s.String) +} diff --git a/types/null/unmarshal.go b/types/null/unmarshal.go index fdc1cff4..bdec3538 100644 --- a/types/null/unmarshal.go +++ b/types/null/unmarshal.go @@ -29,3 +29,43 @@ func (s *NullString) UnmarshalJSON(b []byte) error { s.Valid = (err == nil) return err } + +// UnmarshalYAML for NullInt64 +func (i *NullInt64) UnmarshalYAML(unmarshal func(interface{}) error) error { + var val int64 + if err := unmarshal(&val); err != nil { + return err + } + *i = NewNullInt64(val) + return nil +} + +// UnmarshalYAML for NullFloat64 +func (f *NullFloat64) UnmarshalYAML(unmarshal func(interface{}) error) error { + var val float64 + if err := unmarshal(&val); err != nil { + return err + } + *f = NewNullFloat64(val) + return nil +} + +// UnmarshalYAML for NullBool +func (bb *NullBool) UnmarshalYAML(unmarshal func(interface{}) error) error { + var val bool + if err := unmarshal(&val); err != nil { + return err + } + *bb = NewNullBool(val) + return nil +} + +// UnmarshalYAML for NullFloat64 +func (s *NullString) UnmarshalYAML(unmarshal func(interface{}) error) error { + var val string + if err := unmarshal(&val); err != nil { + return err + } + *s = NewNullString(val) + return nil +} diff --git a/types/services/env.go b/types/services/env.go deleted file mode 100644 index fdd34b76..00000000 --- a/types/services/env.go +++ /dev/null @@ -1,59 +0,0 @@ -package services - -import ( - "bufio" - "github.com/pkg/errors" - "github.com/statping/statping/utils" - "os" -) - -// findServiceByHas will return a service that matches the SHA256 hash of a service -// Service hash example: sha256(name:EXAMPLEdomain:HTTP://DOMAIN.COMport:8080type:HTTPmethod:GET) -func findServiceByHash(hash string) *Service { - for _, service := range All() { - if service.Hash() == hash { - return service - } - } - return nil -} - -func ServicesFromEnvFile() error { - servicesEnv := utils.Params.GetString("SERVICES_FILE") - if servicesEnv == "" { - return nil - } - - file, err := os.Open(servicesEnv) - if err != nil { - return errors.Wrapf(err, "error opening 'SERVICES_FILE' at: %s", servicesEnv) - } - defer file.Close() - - var serviceLines []string - scanner := bufio.NewScanner(file) - for scanner.Scan() { - serviceLines = append(serviceLines, scanner.Text()) - } - - if len(serviceLines) == 0 { - return nil - } - - for k, service := range serviceLines { - - svr, err := ValidateService(service) - if err != nil { - return errors.Wrapf(err, "invalid service at index %d in SERVICES_FILE environment variable", k) - } - if findServiceByHash(svr.Hash()) == nil { - if err := svr.Create(); err != nil { - return errors.Wrapf(err, "could not create service %s", svr.Name) - } - log.Infof("Created new service '%s'", svr.Name) - } - - } - - return nil -} diff --git a/types/services/methods.go b/types/services/methods.go index bcbcc027..a2e5e84a 100644 --- a/types/services/methods.go +++ b/types/services/methods.go @@ -8,12 +8,9 @@ import ( "github.com/statping/statping/types" "github.com/statping/statping/types/failures" "github.com/statping/statping/types/hits" - "github.com/statping/statping/types/null" "github.com/statping/statping/utils" - "net/url" "sort" "strconv" - "strings" "time" ) @@ -233,57 +230,6 @@ func SelectAllServices(start bool) (map[int64]*Service, error) { return allServices, nil } -func ValidateService(line string) (*Service, error) { - p, err := url.Parse(line) - if err != nil { - return nil, err - } - newService := new(Service) - - domain := p.Host - newService.Name = niceDomainName(domain, p.Path) - if p.Port() != "" { - newService.Port = int(utils.ToInt(p.Port())) - if p.Scheme != "http" && p.Scheme != "https" { - domain = strings.ReplaceAll(domain, ":"+p.Port(), "") - } - } - newService.Domain = domain - - switch p.Scheme { - case "http", "https": - newService.Type = "http" - newService.Method = "get" - if p.Scheme == "https" { - newService.VerifySSL = null.NewNullBool(true) - } - default: - newService.Type = p.Scheme - } - return newService, nil -} - -func niceDomainName(domain string, paths string) string { - domain = strings.ReplaceAll(domain, "www.", "") - splitPath := strings.Split(paths, "/") - if len(splitPath) == 1 { - return domain - } - var addedName []string - for k, p := range splitPath { - if k > 2 { - break - } - if len(p) > 16 { - addedName = append(addedName, p+"...") - break - } else { - addedName = append(addedName, p) - } - } - return domain + strings.Join(addedName, "/") -} - func (s *Service) UpdateStats() *Service { s.Online24Hours = s.OnlineDaysPercent(1) s.Online7Days = s.OnlineDaysPercent(7) diff --git a/types/services/struct.go b/types/services/struct.go index 522eebc0..9d72f1de 100644 --- a/types/services/struct.go +++ b/types/services/struct.go @@ -22,56 +22,56 @@ func Services() map[int64]*Service { // Service is the main struct for Services type Service struct { - Id int64 `gorm:"primary_key;column:id" json:"id"` - Name string `gorm:"column:name" json:"name"` - Domain string `gorm:"column:domain" json:"domain" private:"true" scope:"user,admin"` - Expected null.NullString `gorm:"column:expected" json:"expected" scope:"user,admin"` - ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status" scope:"user,admin"` - Interval int `gorm:"default:30;column:check_interval" json:"check_interval"` - Type string `gorm:"column:check_type" json:"type" scope:"user,admin"` - Method string `gorm:"column:method" json:"method" scope:"user,admin"` - PostData null.NullString `gorm:"column:post_data" json:"post_data" scope:"user,admin"` - Port int `gorm:"not null;column:port" json:"port" scope:"user,admin"` - Timeout int `gorm:"default:30;column:timeout" json:"timeout" scope:"user,admin"` - Order int `gorm:"default:0;column:order_id" json:"order_id"` - VerifySSL null.NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl" scope:"user,admin"` - Public null.NullBool `gorm:"default:true;column:public" json:"public"` - GroupId int `gorm:"default:0;column:group_id" json:"group_id"` - Headers null.NullString `gorm:"column:headers" json:"headers" scope:"user,admin"` - Permalink null.NullString `gorm:"column:permalink" json:"permalink"` - Redirect null.NullBool `gorm:"default:false;column:redirect" json:"redirect" scope:"user,admin"` - CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` - UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` - Online bool `gorm:"-" json:"online"` - Latency int64 `gorm:"-" json:"latency"` - PingTime int64 `gorm:"-" json:"ping_time"` - Online24Hours float32 `gorm:"-" json:"online_24_hours"` - Online7Days float32 `gorm:"-" json:"online_7_days"` - AvgResponse int64 `gorm:"-" json:"avg_response"` - FailuresLast24Hours int `gorm:"-" json:"failures_24_hours"` - Running chan bool `gorm:"-" json:"-"` - Checkpoint time.Time `gorm:"-" json:"-"` - SleepDuration time.Duration `gorm:"-" json:"-"` - LastResponse string `gorm:"-" json:"-"` - NotifyAfter int64 `gorm:"column:notify_after" json:"notify_after" scope:"user,admin"` - notifyAfterCount int64 `gorm:"-" json:"-"` - AllowNotifications null.NullBool `gorm:"default:true;column:allow_notifications" json:"allow_notifications" scope:"user,admin"` - UserNotified bool `gorm:"-" json:"-"` // True if the User was already notified about a Downtime - UpdateNotify null.NullBool `gorm:"default:true;column:notify_all_changes" json:"notify_all_changes" scope:"user,admin"` // This Variable is a simple copy of `core.CoreApp.UpdateNotify.Bool` - DownText string `gorm:"-" json:"-"` // Contains the current generated Downtime Text - SuccessNotified bool `gorm:"-" json:"-"` // Is 'true' if the user has already be informed that the Services now again available - LastStatusCode int `gorm:"-" json:"status_code"` - Failures []*failures.Failure `gorm:"-" json:"failures,omitempty" scope:"user,admin"` - AllCheckins []*checkins.Checkin `gorm:"-" json:"checkins,omitempty" scope:"user,admin"` - LastLookupTime int64 `gorm:"-" json:"-"` - LastLatency int64 `gorm:"-" json:"-"` - LastCheck time.Time `gorm:"-" json:"-"` - LastOnline time.Time `gorm:"-" json:"last_success"` - LastOffline time.Time `gorm:"-" json:"last_error"` - Stats *Stats `gorm:"-" json:"stats,omitempty"` + Id int64 `gorm:"primary_key;column:id" json:"id" yaml:"id"` + Name string `gorm:"column:name" json:"name" yaml:"name"` + Domain string `gorm:"column:domain" json:"domain" yaml:"domain" private:"true" scope:"user,admin"` + Expected null.NullString `gorm:"column:expected" json:"expected" yaml:"expected" scope:"user,admin"` + ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status" yaml:"expected_status" scope:"user,admin"` + Interval int `gorm:"default:30;column:check_interval" json:"check_interval" yaml:"check_interval"` + Type string `gorm:"column:check_type" json:"type" scope:"user,admin" yaml:"type"` + Method string `gorm:"column:method" json:"method" scope:"user,admin" yaml:"method"` + PostData null.NullString `gorm:"column:post_data" json:"post_data" scope:"user,admin" yaml:"post_data"` + Port int `gorm:"not null;column:port" json:"port" scope:"user,admin" yaml:"port"` + Timeout int `gorm:"default:30;column:timeout" json:"timeout" scope:"user,admin" yaml:"timeout"` + Order int `gorm:"default:0;column:order_id" json:"order_id" yaml:"order_id"` + VerifySSL null.NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl" scope:"user,admin" yaml:"verify_ssl"` + Public null.NullBool `gorm:"default:true;column:public" json:"public" yaml:"public"` + GroupId int `gorm:"default:0;column:group_id" json:"group_id" yaml:"group_id"` + Headers null.NullString `gorm:"column:headers" json:"headers" scope:"user,admin" yaml:"headers"` + Permalink null.NullString `gorm:"column:permalink" json:"permalink" yaml:"permalink"` + Redirect null.NullBool `gorm:"default:false;column:redirect" json:"redirect" scope:"user,admin" yaml:"redirect"` + CreatedAt time.Time `gorm:"column:created_at" json:"created_at" yaml:"-"` + UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at" yaml:"-"` + Online bool `gorm:"-" json:"online" yaml:"-"` + Latency int64 `gorm:"-" json:"latency" yaml:"-"` + PingTime int64 `gorm:"-" json:"ping_time" yaml:"-"` + Online24Hours float32 `gorm:"-" json:"online_24_hours" yaml:"-"` + Online7Days float32 `gorm:"-" json:"online_7_days" yaml:"-"` + AvgResponse int64 `gorm:"-" json:"avg_response" yaml:"-"` + FailuresLast24Hours int `gorm:"-" json:"failures_24_hours" yaml:"-"` + Running chan bool `gorm:"-" json:"-" yaml:"-"` + Checkpoint time.Time `gorm:"-" json:"-" yaml:"-"` + SleepDuration time.Duration `gorm:"-" json:"-" yaml:"-"` + LastResponse string `gorm:"-" json:"-" yaml:"-"` + NotifyAfter int64 `gorm:"column:notify_after" json:"notify_after" yaml:"notify_after" scope:"user,admin"` + notifyAfterCount int64 `gorm:"-" json:"-" yaml:"-"` + AllowNotifications null.NullBool `gorm:"default:true;column:allow_notifications" json:"allow_notifications" yaml:"allow_notifications" scope:"user,admin"` + UserNotified bool `gorm:"-" json:"-" yaml:"-"` // True if the User was already notified about a Downtime + UpdateNotify null.NullBool `gorm:"default:true;column:notify_all_changes" json:"notify_all_changes" yaml:"notify_all_changes" scope:"user,admin"` // This Variable is a simple copy of `core.CoreApp.UpdateNotify.Bool` + DownText string `gorm:"-" json:"-" yaml:"-"` // Contains the current generated Downtime Text + SuccessNotified bool `gorm:"-" json:"-" yaml:"-"` // Is 'true' if the user has already be informed that the Services now again available + LastStatusCode int `gorm:"-" json:"status_code" yaml:"-"` + Failures []*failures.Failure `gorm:"-" json:"failures,omitempty" yaml:"-" scope:"user,admin"` + AllCheckins []*checkins.Checkin `gorm:"-" json:"checkins,omitempty" yaml:"-" scope:"user,admin"` + LastLookupTime int64 `gorm:"-" json:"-" yaml:"-"` + LastLatency int64 `gorm:"-" json:"-" yaml:"-"` + LastCheck time.Time `gorm:"-" json:"-" yaml:"-"` + LastOnline time.Time `gorm:"-" json:"last_success" yaml:"-"` + LastOffline time.Time `gorm:"-" json:"last_error" yaml:"-"` + Stats *Stats `gorm:"-" json:"stats,omitempty" yaml:"-"` - SecondsOnline int64 `gorm:"-" json:"-"` - SecondsOffline int64 `gorm:"-" json:"-"` + SecondsOnline int64 `gorm:"-" json:"-" yaml:"-"` + SecondsOffline int64 `gorm:"-" json:"-" yaml:"-"` } type Stats struct { diff --git a/types/services/yaml.go b/types/services/yaml.go new file mode 100644 index 00000000..fc56878c --- /dev/null +++ b/types/services/yaml.go @@ -0,0 +1,47 @@ +package services + +import ( + "github.com/pkg/errors" + "github.com/statping/statping/utils" + "gopkg.in/yaml.v2" +) + +type ServicesYaml struct { + Services []Service `yaml:"services,flow"` +} + +// LoadServicesYaml will attempt to load the 'services.yml' file for Service Auto Creation on startup. +func LoadServicesYaml() (*ServicesYaml, error) { + f, err := utils.OpenFile("services.yml") + if err != nil { + return nil, err + } + + var svrs *ServicesYaml + if err := yaml.Unmarshal([]byte(f), &svrs); err != nil { + return nil, err + } + + for _, svr := range svrs.Services { + if findServiceByHash(svr.Hash()) == nil { + if err := svr.Create(); err != nil { + return nil, errors.Wrapf(err, "could not create service %s", svr.Name) + } + log.Infof("Automatically created service '%s' checking %s", svr.Name, svr.Domain) + } + + } + + return svrs, nil +} + +// findServiceByHas will return a service that matches the SHA256 hash of a service +// Service hash example: sha256(name:EXAMPLEdomain:HTTP://DOMAIN.COMport:8080type:HTTPmethod:GET) +func findServiceByHash(hash string) *Service { + for _, service := range All() { + if service.Hash() == hash { + return service + } + } + return nil +}