mirror of https://github.com/statping/statping
remove API_KEY (unused code), just use API_SECRET, YAML unmarshal, services.yml services auto creation
parent
2893218ed6
commit
d9e3cabb4e
|
@ -116,7 +116,7 @@ jobs:
|
||||||
VERSION: ${{ env.VERSION }}
|
VERSION: ${{ env.VERSION }}
|
||||||
DB_CONN: sqlite3
|
DB_CONN: sqlite3
|
||||||
STATPING_DIR: ${{ github.workspace }}
|
STATPING_DIR: ${{ github.workspace }}
|
||||||
API_KEY: demopassword123
|
API_SECRET: demopassword123
|
||||||
DISABLE_LOGS: true
|
DISABLE_LOGS: true
|
||||||
ALLOW_REPORTS: true
|
ALLOW_REPORTS: true
|
||||||
PUSH_REQUEST: true
|
PUSH_REQUEST: true
|
||||||
|
@ -164,21 +164,3 @@ jobs:
|
||||||
environment: ./dev/postman_environment.json
|
environment: ./dev/postman_environment.json
|
||||||
timeoutRequest: 15000
|
timeoutRequest: 15000
|
||||||
delayRequest: 1000
|
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
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ jobs:
|
||||||
VERSION: ${{ env.VERSION }}
|
VERSION: ${{ env.VERSION }}
|
||||||
DB_CONN: sqlite3
|
DB_CONN: sqlite3
|
||||||
STATPING_DIR: ${{ github.workspace }}
|
STATPING_DIR: ${{ github.workspace }}
|
||||||
API_KEY: demopassword123
|
API_SECRET: demopassword123
|
||||||
DISABLE_LOGS: true
|
DISABLE_LOGS: true
|
||||||
ALLOW_REPORTS: true
|
ALLOW_REPORTS: true
|
||||||
COVERALLS: ${{ secrets.COVERALLS }}
|
COVERALLS: ${{ secrets.COVERALLS }}
|
||||||
|
|
|
@ -36,3 +36,4 @@ docker
|
||||||
tmp
|
tmp
|
||||||
/frontend/cypress/screenshots/
|
/frontend/cypress/screenshots/
|
||||||
/frontend/cypress/videos/
|
/frontend/cypress/videos/
|
||||||
|
services.yml
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Upcoming
|
# Upcoming
|
||||||
- Added missing information to Mail notification ([#472](https://github.com/statping/statping/issues/472))
|
- 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)
|
# 0.90.33 (04-24-2020)
|
||||||
- Fixed config loading method
|
- Fixed config loading method
|
||||||
|
|
|
@ -153,16 +153,12 @@ func sigterm() {
|
||||||
|
|
||||||
// mainProcess will initialize the Statping application and run the HTTP server
|
// mainProcess will initialize the Statping application and run the HTTP server
|
||||||
func mainProcess() error {
|
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 {
|
if err := InitApp(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
services.LoadServicesYaml()
|
||||||
|
|
||||||
if err := handlers.RunHTTPServer(ipAddress, port); err != nil {
|
if err := handlers.RunHTTPServer(ipAddress, port); err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
return errors.Wrap(err, "http server")
|
return errors.Wrap(err, "http server")
|
||||||
|
|
|
@ -27,7 +27,6 @@ services:
|
||||||
# VIRTUAL_PORT: 8888
|
# VIRTUAL_PORT: 8888
|
||||||
# GO_ENV: test
|
# GO_ENV: test
|
||||||
# DB_CONN: sqlite
|
# DB_CONN: sqlite
|
||||||
# API_KEY: exampleapikey
|
|
||||||
# API_SECRET: exampleapisecret
|
# API_SECRET: exampleapisecret
|
||||||
# NAME: Statping on SQLite
|
# NAME: Statping on SQLite
|
||||||
# DOMAIN: http://localhost:4000
|
# DOMAIN: http://localhost:4000
|
||||||
|
@ -59,7 +58,6 @@ services:
|
||||||
VIRTUAL_HOST: sqlite.dev.statping.com
|
VIRTUAL_HOST: sqlite.dev.statping.com
|
||||||
VIRTUAL_PORT: 8080
|
VIRTUAL_PORT: 8080
|
||||||
DB_CONN: sqlite
|
DB_CONN: sqlite
|
||||||
API_KEY: exampleapikey
|
|
||||||
API_SECRET: exampleapisecret
|
API_SECRET: exampleapisecret
|
||||||
NAME: Statping on SQLite
|
NAME: Statping on SQLite
|
||||||
DOMAIN: http://localhost:4000
|
DOMAIN: http://localhost:4000
|
||||||
|
@ -96,7 +94,6 @@ services:
|
||||||
DB_DATABASE: statping
|
DB_DATABASE: statping
|
||||||
DB_USER: root
|
DB_USER: root
|
||||||
DB_PASS: password123
|
DB_PASS: password123
|
||||||
API_KEY: exampleapikey
|
|
||||||
API_SECRET: exampleapisecret
|
API_SECRET: exampleapisecret
|
||||||
NAME: Statping on MySQL
|
NAME: Statping on MySQL
|
||||||
DOMAIN: http://localhost:4005
|
DOMAIN: http://localhost:4005
|
||||||
|
@ -134,7 +131,6 @@ services:
|
||||||
DB_DATABASE: statping
|
DB_DATABASE: statping
|
||||||
DB_USER: root
|
DB_USER: root
|
||||||
DB_PASS: password123
|
DB_PASS: password123
|
||||||
API_KEY: exampleapikey
|
|
||||||
API_SECRET: exampleapisecret
|
API_SECRET: exampleapisecret
|
||||||
NAME: Statping on Postgres
|
NAME: Statping on Postgres
|
||||||
DOMAIN: http://localhost:4010
|
DOMAIN: http://localhost:4010
|
||||||
|
|
|
@ -19,7 +19,6 @@ services:
|
||||||
- ./utils:/go/src/github.com/statping/statping/utils/
|
- ./utils:/go/src/github.com/statping/statping/utils/
|
||||||
environment:
|
environment:
|
||||||
DB_CONN: sqlite
|
DB_CONN: sqlite
|
||||||
API_KEY: exampleapikey
|
|
||||||
API_SECRET: exampleapisecret
|
API_SECRET: exampleapisecret
|
||||||
NAME: Statping
|
NAME: Statping
|
||||||
DOMAIN: http://localhost:8585
|
DOMAIN: http://localhost:8585
|
||||||
|
|
|
@ -7,14 +7,43 @@ services:
|
||||||
image: statping/statping
|
image: statping/statping
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
|
networks:
|
||||||
|
- backend
|
||||||
|
volumes:
|
||||||
|
- /root/statping:/app
|
||||||
environment:
|
environment:
|
||||||
PORT: 8080
|
PORT: 8080
|
||||||
SERVICES: '[{"name": "Local Statping", "type": "http", "domain": "http://localhost:8585", "interval": 30}]'
|
|
||||||
DB_CONN: sqlite
|
|
||||||
API_KEY: exampleapikey
|
|
||||||
API_SECRET: exampleapisecret
|
API_SECRET: exampleapisecret
|
||||||
NAME: Statping on SQLite
|
NAME: Statping on SQLite
|
||||||
DOMAIN: http://localhost:8080
|
DOMAIN: http://localhost:8080
|
||||||
DESCRIPTION: This is a dev environment on SQLite!
|
DESCRIPTION: This is a dev environment on SQLite!
|
||||||
ADMIN_USER: admin
|
ADMIN_USER: admin
|
||||||
ADMIN_PASS: 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:
|
||||||
|
|
|
@ -30,7 +30,6 @@ context('Notifier Tests', () => {
|
||||||
cy.visit('/dashboard/settings')
|
cy.visit('/dashboard/settings')
|
||||||
cy.get('#notifiers_tabs > a').should('have.length', 10)
|
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', '')
|
cy.get('#api_secret').should('not.have.value', '')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ context('Settings Tests', () => {
|
||||||
cy.visit('/dashboard/settings')
|
cy.visit('/dashboard/settings')
|
||||||
cy.get('#notifiers_tabs > a').should('have.length', 10)
|
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', '')
|
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('#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('#domain').should('have.value', 'http://localhost:8888')
|
||||||
cy.get('#footer').should('have.value', 'Statping Custom Footer')
|
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', '')
|
cy.get('#api_secret').should('not.have.value', '')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -67,19 +67,6 @@
|
||||||
<div class="card text-black-50 bg-white mt-3">
|
<div class="card text-black-50 bg-white mt-3">
|
||||||
<div class="card-header">API Settings</div>
|
<div class="card-header">API Settings</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-3 col-form-label">API Key</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<div class="input-group">
|
|
||||||
<input v-model="core.api_key" type="text" class="form-control" id="api_key" readonly>
|
|
||||||
<div class="input-group-append copy-btn">
|
|
||||||
<button @click.prevent="copy(core.api_key)" class="btn btn-outline-secondary" type="button">Copy</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<small class="form-text text-muted">API Key can be used for read only routes</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-3 col-form-label">API Secret</label>
|
<label class="col-sm-3 col-form-label">API Secret</label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
|
|
|
@ -80,6 +80,7 @@ func Router() *mux.Router {
|
||||||
api.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
|
api.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
|
||||||
api.Handle("/api/core", authenticated(apiCoreHandler, false)).Methods("POST")
|
api.Handle("/api/core", authenticated(apiCoreHandler, false)).Methods("POST")
|
||||||
api.Handle("/api/oauth", scoped(apiOAuthHandler)).Methods("GET")
|
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", authenticated(logsHandler, false)).Methods("GET")
|
||||||
api.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
|
api.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,6 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
c := &core.Core{
|
c := &core.Core{
|
||||||
Name: project,
|
Name: project,
|
||||||
Description: description,
|
Description: description,
|
||||||
ApiKey: utils.Params.GetString("API_KEY"),
|
|
||||||
ApiSecret: utils.Params.GetString("API_SECRET"),
|
ApiSecret: utils.Params.GetString("API_SECRET"),
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
Version: core.App.Version,
|
Version: core.App.Version,
|
||||||
|
|
|
@ -40,9 +40,7 @@ func Connect(configs *DbConfig, retry bool) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apiKey := p.GetString("API_KEY")
|
|
||||||
apiSecret := p.GetString("API_SECRET")
|
apiSecret := p.GetString("API_SECRET")
|
||||||
configs.ApiKey = apiKey
|
|
||||||
configs.ApiSecret = apiSecret
|
configs.ApiSecret = apiSecret
|
||||||
|
|
||||||
log.WithFields(utils.ToFields(dbSession)).Debugln("connected to database")
|
log.WithFields(utils.ToFields(dbSession)).Debugln("connected to database")
|
||||||
|
|
|
@ -46,9 +46,6 @@ func LoadConfigFile(directory string) (*DbConfig, error) {
|
||||||
if db.Location != "" {
|
if db.Location != "" {
|
||||||
p.Set("LOCATION", db.Location)
|
p.Set("LOCATION", db.Location)
|
||||||
}
|
}
|
||||||
if db.ApiKey != "" {
|
|
||||||
p.Set("API_KEY", db.ApiKey)
|
|
||||||
}
|
|
||||||
if db.ApiSecret != "" {
|
if db.ApiSecret != "" {
|
||||||
p.Set("API_SECRET", db.ApiSecret)
|
p.Set("API_SECRET", db.ApiSecret)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ type DbConfig struct {
|
||||||
DbPass string `yaml:"password" json:"-"`
|
DbPass string `yaml:"password" json:"-"`
|
||||||
DbData string `yaml:"database" json:"-"`
|
DbData string `yaml:"database" json:"-"`
|
||||||
DbPort int `yaml:"port" json:"-"`
|
DbPort int `yaml:"port" json:"-"`
|
||||||
ApiKey string `yaml:"api_key" json:"-"`
|
|
||||||
ApiSecret string `yaml:"api_secret" json:"-"`
|
ApiSecret string `yaml:"api_secret" json:"-"`
|
||||||
Project string `yaml:"-" json:"-"`
|
Project string `yaml:"-" json:"-"`
|
||||||
Description string `yaml:"-" json:"-"`
|
Description string `yaml:"-" json:"-"`
|
||||||
|
|
|
@ -23,7 +23,6 @@ type Core struct {
|
||||||
Name string `gorm:"not null;column:name" json:"name,omitempty"`
|
Name string `gorm:"not null;column:name" json:"name,omitempty"`
|
||||||
Description string `gorm:"not null;column:description" json:"description,omitempty"`
|
Description string `gorm:"not null;column:description" json:"description,omitempty"`
|
||||||
ConfigFile string `gorm:"column:config" json:"-"`
|
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"`
|
ApiSecret string `gorm:"column:api_secret" json:"api_secret" scope:"admin"`
|
||||||
Style string `gorm:"not null;column:style" json:"style,omitempty"`
|
Style string `gorm:"not null;column:style" json:"style,omitempty"`
|
||||||
Footer null.NullString `gorm:"column:footer" json:"footer"`
|
Footer null.NullString `gorm:"column:footer" json:"footer"`
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package null
|
package null
|
||||||
|
|
||||||
import "encoding/json"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
// MarshalJSON for NullInt64
|
// MarshalJSON for NullInt64
|
||||||
func (i NullInt64) MarshalJSON() ([]byte, error) {
|
func (i NullInt64) MarshalJSON() ([]byte, error) {
|
||||||
|
@ -33,3 +36,35 @@ func (s NullString) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
return json.Marshal(s.String)
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -29,3 +29,43 @@ func (s *NullString) UnmarshalJSON(b []byte) error {
|
||||||
s.Valid = (err == nil)
|
s.Valid = (err == nil)
|
||||||
return err
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -8,12 +8,9 @@ import (
|
||||||
"github.com/statping/statping/types"
|
"github.com/statping/statping/types"
|
||||||
"github.com/statping/statping/types/failures"
|
"github.com/statping/statping/types/failures"
|
||||||
"github.com/statping/statping/types/hits"
|
"github.com/statping/statping/types/hits"
|
||||||
"github.com/statping/statping/types/null"
|
|
||||||
"github.com/statping/statping/utils"
|
"github.com/statping/statping/utils"
|
||||||
"net/url"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -233,57 +230,6 @@ func SelectAllServices(start bool) (map[int64]*Service, error) {
|
||||||
return allServices, nil
|
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 {
|
func (s *Service) UpdateStats() *Service {
|
||||||
s.Online24Hours = s.OnlineDaysPercent(1)
|
s.Online24Hours = s.OnlineDaysPercent(1)
|
||||||
s.Online7Days = s.OnlineDaysPercent(7)
|
s.Online7Days = s.OnlineDaysPercent(7)
|
||||||
|
|
|
@ -22,56 +22,56 @@ func Services() map[int64]*Service {
|
||||||
|
|
||||||
// Service is the main struct for Services
|
// Service is the main struct for Services
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
Id int64 `gorm:"primary_key;column:id" json:"id" yaml:"id"`
|
||||||
Name string `gorm:"column:name" json:"name"`
|
Name string `gorm:"column:name" json:"name" yaml:"name"`
|
||||||
Domain string `gorm:"column:domain" json:"domain" private:"true" scope:"user,admin"`
|
Domain string `gorm:"column:domain" json:"domain" yaml:"domain" private:"true" scope:"user,admin"`
|
||||||
Expected null.NullString `gorm:"column:expected" json:"expected" 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" 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"`
|
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"`
|
Type string `gorm:"column:check_type" json:"type" scope:"user,admin" yaml:"type"`
|
||||||
Method string `gorm:"column:method" json:"method" scope:"user,admin"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
Public null.NullBool `gorm:"default:true;column:public" json:"public" yaml:"public"`
|
||||||
GroupId int `gorm:"default:0;column:group_id" json:"group_id"`
|
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"`
|
Headers null.NullString `gorm:"column:headers" json:"headers" scope:"user,admin" yaml:"headers"`
|
||||||
Permalink null.NullString `gorm:"column:permalink" json:"permalink"`
|
Permalink null.NullString `gorm:"column:permalink" json:"permalink" yaml:"permalink"`
|
||||||
Redirect null.NullBool `gorm:"default:false;column:redirect" json:"redirect" scope:"user,admin"`
|
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"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at" yaml:"-"`
|
||||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at" yaml:"-"`
|
||||||
Online bool `gorm:"-" json:"online"`
|
Online bool `gorm:"-" json:"online" yaml:"-"`
|
||||||
Latency int64 `gorm:"-" json:"latency"`
|
Latency int64 `gorm:"-" json:"latency" yaml:"-"`
|
||||||
PingTime int64 `gorm:"-" json:"ping_time"`
|
PingTime int64 `gorm:"-" json:"ping_time" yaml:"-"`
|
||||||
Online24Hours float32 `gorm:"-" json:"online_24_hours"`
|
Online24Hours float32 `gorm:"-" json:"online_24_hours" yaml:"-"`
|
||||||
Online7Days float32 `gorm:"-" json:"online_7_days"`
|
Online7Days float32 `gorm:"-" json:"online_7_days" yaml:"-"`
|
||||||
AvgResponse int64 `gorm:"-" json:"avg_response"`
|
AvgResponse int64 `gorm:"-" json:"avg_response" yaml:"-"`
|
||||||
FailuresLast24Hours int `gorm:"-" json:"failures_24_hours"`
|
FailuresLast24Hours int `gorm:"-" json:"failures_24_hours" yaml:"-"`
|
||||||
Running chan bool `gorm:"-" json:"-"`
|
Running chan bool `gorm:"-" json:"-" yaml:"-"`
|
||||||
Checkpoint time.Time `gorm:"-" json:"-"`
|
Checkpoint time.Time `gorm:"-" json:"-" yaml:"-"`
|
||||||
SleepDuration time.Duration `gorm:"-" json:"-"`
|
SleepDuration time.Duration `gorm:"-" json:"-" yaml:"-"`
|
||||||
LastResponse string `gorm:"-" json:"-"`
|
LastResponse string `gorm:"-" json:"-" yaml:"-"`
|
||||||
NotifyAfter int64 `gorm:"column:notify_after" json:"notify_after" scope:"user,admin"`
|
NotifyAfter int64 `gorm:"column:notify_after" json:"notify_after" yaml:"notify_after" scope:"user,admin"`
|
||||||
notifyAfterCount int64 `gorm:"-" json:"-"`
|
notifyAfterCount int64 `gorm:"-" json:"-" yaml:"-"`
|
||||||
AllowNotifications null.NullBool `gorm:"default:true;column:allow_notifications" json:"allow_notifications" scope:"user,admin"`
|
AllowNotifications null.NullBool `gorm:"default:true;column:allow_notifications" json:"allow_notifications" yaml:"allow_notifications" scope:"user,admin"`
|
||||||
UserNotified bool `gorm:"-" json:"-"` // True if the User was already notified about a Downtime
|
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" scope:"user,admin"` // This Variable is a simple copy of `core.CoreApp.UpdateNotify.Bool`
|
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:"-"` // Contains the current generated Downtime Text
|
DownText string `gorm:"-" json:"-" yaml:"-"` // 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
|
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"`
|
LastStatusCode int `gorm:"-" json:"status_code" yaml:"-"`
|
||||||
Failures []*failures.Failure `gorm:"-" json:"failures,omitempty" scope:"user,admin"`
|
Failures []*failures.Failure `gorm:"-" json:"failures,omitempty" yaml:"-" scope:"user,admin"`
|
||||||
AllCheckins []*checkins.Checkin `gorm:"-" json:"checkins,omitempty" scope:"user,admin"`
|
AllCheckins []*checkins.Checkin `gorm:"-" json:"checkins,omitempty" yaml:"-" scope:"user,admin"`
|
||||||
LastLookupTime int64 `gorm:"-" json:"-"`
|
LastLookupTime int64 `gorm:"-" json:"-" yaml:"-"`
|
||||||
LastLatency int64 `gorm:"-" json:"-"`
|
LastLatency int64 `gorm:"-" json:"-" yaml:"-"`
|
||||||
LastCheck time.Time `gorm:"-" json:"-"`
|
LastCheck time.Time `gorm:"-" json:"-" yaml:"-"`
|
||||||
LastOnline time.Time `gorm:"-" json:"last_success"`
|
LastOnline time.Time `gorm:"-" json:"last_success" yaml:"-"`
|
||||||
LastOffline time.Time `gorm:"-" json:"last_error"`
|
LastOffline time.Time `gorm:"-" json:"last_error" yaml:"-"`
|
||||||
Stats *Stats `gorm:"-" json:"stats,omitempty"`
|
Stats *Stats `gorm:"-" json:"stats,omitempty" yaml:"-"`
|
||||||
|
|
||||||
SecondsOnline int64 `gorm:"-" json:"-"`
|
SecondsOnline int64 `gorm:"-" json:"-" yaml:"-"`
|
||||||
SecondsOffline int64 `gorm:"-" json:"-"`
|
SecondsOffline int64 `gorm:"-" json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stats struct {
|
type Stats struct {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue