db fixed - plugins

pull/10/head v0.28.9
Hunter Long 2018-07-03 14:39:56 -07:00
parent 87f493bf4e
commit 91daa01825
12 changed files with 142 additions and 72 deletions

View File

@ -18,7 +18,7 @@ services:
env: env:
global: global:
- VERSION=0.28.8 - VERSION=0.28.9
- DB_HOST=localhost - DB_HOST=localhost
- DB_USER=travis - DB_USER=travis
- DB_PASS= - DB_PASS=

View File

@ -1,6 +1,6 @@
FROM alpine:latest FROM alpine:latest
ENV VERSION=v0.28.8 ENV VERSION=v0.28.9
RUN apk --no-cache add libstdc++ ca-certificates RUN apk --no-cache add libstdc++ ca-certificates
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \ RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \

View File

@ -3,7 +3,7 @@
</p> </p>
<p align="center"> <p align="center">
<b>Statup - Web and App Status Monitoring for Any Type of Project</b><br> <b>Statup - Web and App Status Monitoring for Any Type of Project</b><br>
<a href="https://github.com/hunterlong/statup/wiki">View Wiki</a> | <a href="https://demo.statup.io">Demo</a> <br> <a href="https://github.com/hunterlong/statup/wiki/Docker">Docker</a> | <a href="https://github.com/hunterlong/statup/wiki/AWS-EC2">EC2</a> | <a href="https://github.com/hunterlong/statup/wiki/Heroku">Heroku</a> | <a href="https://github.com/hunterlong/statup/wiki/Mac">Mac</a> | <a href="https://github.com/hunterlong/statup/wiki/Linux">Linux</a> | <a href="https://github.com/hunterlong/statup/wiki/Windows">Windows</a><br> <a href="https://github.com/hunterlong/statup/wiki">View Wiki</a> | <a href="https://demo.statup.io">Demo</a> <br> <a href="https://github.com/hunterlong/statup/wiki/Docker">Docker</a> | <a href="https://github.com/hunterlong/statup/wiki/AWS-EC2">EC2</a> | <a href="https://github.com/hunterlong/statup/wiki/Heroku">Heroku</a> | <a href="https://github.com/hunterlong/statup/wiki/Mac">Mac</a> | <a href="https://github.com/hunterlong/statup/wiki/Linux">Linux</a> | <a href="https://github.com/hunterlong/statup/wiki/Windows">Windows</a> | <a href="https://github.com/hunterlong/statup/wiki/Statup-Plugins">Plugins</a>
</p> </p>
# Statup - Status Page & Monitoring Server # Statup - Status Page & Monitoring Server

View File

@ -22,7 +22,7 @@ type Core struct {
Services []*Service `json:"services,omitempty"` Services []*Service `json:"services,omitempty"`
Plugins []plugin.Info Plugins []plugin.Info
Repos []PluginJSON Repos []PluginJSON
//PluginFields []PluginSelect AllPlugins []plugin.PluginActions
Communications []*types.Communication Communications []*types.Communication
OfflineAssets bool OfflineAssets bool
} }
@ -37,7 +37,6 @@ var (
TmplBox *rice.Box TmplBox *rice.Box
EmailBox *rice.Box EmailBox *rice.Box
SetupMode bool SetupMode bool
AllPlugins []plugin.PluginActions
UsingAssets bool UsingAssets bool
) )

View File

@ -39,11 +39,13 @@ func DbConnection(dbType string) error {
if Configs.Port == "" { if Configs.Port == "" {
Configs.Port = "3306" Configs.Port = "3306"
} }
mysqlSettings = mysql.ConnectionURL{ mysqlSettings = mysql.ConnectionURL{
Database: Configs.Database, Database: Configs.Database,
Host: Configs.Host, Host: Configs.Host,
User: Configs.User, User: Configs.User,
Password: Configs.Password, Password: Configs.Password,
Options: map[string]string{"parseTime": "true", "charset": "utf8"},
} }
DbSession, err = mysql.Open(mysqlSettings) DbSession, err = mysql.Open(mysqlSettings)
if err != nil { if err != nil {
@ -67,7 +69,6 @@ func DbConnection(dbType string) error {
} }
//dbSession.SetLogging(true) //dbSession.SetLogging(true)
dbServer = dbType dbServer = dbType
OnLoad(DbSession)
return err return err
} }

View File

@ -10,19 +10,19 @@ import (
) )
func OnLoad(db sqlbuilder.Database) { func OnLoad(db sqlbuilder.Database) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnLoad(db) p.OnLoad(db)
} }
} }
func OnSuccess(s *Service) { func OnSuccess(s *Service) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnSuccess(structs.Map(s)) p.OnSuccess(structs.Map(s))
} }
} }
func OnFailure(s *Service, f FailureData) { func OnFailure(s *Service, f FailureData) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnFailure(structs.Map(s)) p.OnFailure(structs.Map(s))
} }
@ -61,37 +61,37 @@ func onFailureEmail(s *Service, f FailureData) {
} }
func OnSettingsSaved(c *Core) { func OnSettingsSaved(c *Core) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnSettingsSaved(structs.Map(c)) p.OnSettingsSaved(structs.Map(c))
} }
} }
func OnNewUser(u *User) { func OnNewUser(u *User) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnNewUser(structs.Map(u)) p.OnNewUser(structs.Map(u))
} }
} }
func OnNewService(s *Service) { func OnNewService(s *Service) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnNewService(structs.Map(s)) p.OnNewService(structs.Map(s))
} }
} }
func OnDeletedService(s *Service) { func OnDeletedService(s *Service) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnDeletedService(structs.Map(s)) p.OnDeletedService(structs.Map(s))
} }
} }
func OnUpdateService(s *Service) { func OnUpdateService(s *Service) {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnUpdatedService(structs.Map(s)) p.OnUpdatedService(structs.Map(s))
} }
} }
func SelectPlugin(name string) plugin.PluginActions { func SelectPlugin(name string) plugin.PluginActions {
for _, p := range AllPlugins { for _, p := range CoreApp.AllPlugins {
if p.GetInfo().Name == name { if p.GetInfo().Name == name {
return p return p
} }

View File

@ -17,6 +17,9 @@ func (s *Service) CreateFailure(data FailureData) (int64, error) {
s.Failures = append(s.Failures, fail) s.Failures = append(s.Failures, fail)
col := DbSession.Collection("failures") col := DbSession.Collection("failures")
uuid, err := col.Insert(fail) uuid, err := col.Insert(fail)
if err != nil {
utils.Log(3, err)
}
if uuid == nil { if uuid == nil {
return 0, err return 0, err
} }
@ -26,7 +29,10 @@ func (s *Service) CreateFailure(data FailureData) (int64, error) {
func (s *Service) SelectAllFailures() []*Failure { func (s *Service) SelectAllFailures() []*Failure {
var fails []*Failure var fails []*Failure
col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id") col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id")
col.All(&fails) err := col.All(&fails)
if err != nil {
utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err))
}
return fails return fails
} }

View File

@ -125,28 +125,33 @@ func (s *Service) SmallText() string {
} }
func (s *Service) GraphData() string { func (s *Service) GraphData() string {
var d []DateScan var d []*DateScan
increment := "minute" increment := "minute"
since := time.Now().Add(time.Hour*-12 + time.Minute*0 + time.Second*0) since := time.Now().Add(time.Hour*-24 + time.Minute*0 + time.Second*0)
// group by interval sql query for postgres, mysql and sqlite // group by interval sql query for postgres, mysql and sqlite
sql := fmt.Sprintf("SELECT date_trunc('%v', created_at), AVG(latency)*1000 AS value FROM hits WHERE service=%v AND created_at > '%v' GROUP BY 1 ORDER BY date_trunc ASC;", increment, s.Id, since.Format(time.RFC3339)) sql := fmt.Sprintf("SELECT date_trunc('%v', created_at), AVG(latency)*1000 AS value FROM hits WHERE service=%v AND created_at > '%v' GROUP BY 1 ORDER BY date_trunc ASC;", increment, s.Id, since.Format(time.RFC3339))
if dbServer == "mysql" { if dbServer == "mysql" {
sql = fmt.Sprintf("SELECT CONCAT(DATE(created_at), ' ', %v(created_at)) AS created_at, AVG(latency)*1000 AS value FROM hits WHERE service=%v AND DATE_FORMAT(created_at, 'Y-m-d H:i:s') BETWEEN DATE_FORMAT(NOW() - INTERVAL 12 HOUR, 'Y-m-d H:i:s') AND DATE_FORMAT(NOW(), 'Y-m-d H:i:s') GROUP BY created_at", increment, s.Id) sql = fmt.Sprintf("SELECT CONCAT(date_format(created_at, '%%Y-%%m-%%dT%%TZ')) AS created_at, AVG(latency)*1000 AS value FROM hits WHERE service=%v AND DATE_FORMAT(created_at, '%%Y-%%m-%%dT%%TZ') BETWEEN DATE_FORMAT(NOW() - INTERVAL 12 HOUR, '%%Y-%%m-%%dT%%TZ') AND DATE_FORMAT(NOW(), '%%Y-%%m-%%dT%%TZ') GROUP BY created_at", s.Id)
} else if dbServer == "sqlite" { } else if dbServer == "sqlite" {
sql = fmt.Sprintf("SELECT created_at, AVG(latency)*1000 as value FROM hits WHERE service=%v AND created_at >= '%v' GROUP BY strftime('%%m', created_at)", s.Id, since.Format(time.RFC3339)) sql = fmt.Sprintf("SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%SZ', created_at), AVG(latency)*1000 as value FROM hits WHERE service=%v AND created_at >= '%v' GROUP BY strftime('%%m', created_at)", s.Id, since.Format(time.RFC3339))
fmt.Println(sql)
} }
dated, err := DbSession.Query(db.Raw(sql)) dated, err := DbSession.Query(db.Raw(sql))
if err != nil { if err != nil {
utils.Log(2, err) utils.Log(2, err)
return "" return ""
} }
for dated.Next() { for dated.Next() {
var gd DateScan gd := new(DateScan)
var tt string
var ff float64 var ff float64
dated.Scan(&gd.CreatedAt, &ff) err := dated.Scan(&tt, &ff)
if err != nil {
utils.Log(2, fmt.Sprintf("Issue loading chart data for service %v, %v", s.Name, err))
}
gd.CreatedAt, err = time.Parse(time.RFC3339, tt)
if err != nil {
utils.Log(2, fmt.Sprintf("Issue parsing time %v", err))
}
gd.Value = int64(ff) gd.Value = int64(ff)
d = append(d, gd) d = append(d, gd)
} }

23
main.go
View File

@ -82,11 +82,12 @@ func ForEachPlugin() {
} }
func LoadPlugins() { func LoadPlugins() {
utils.Log(1, fmt.Sprintf("Loading any available Plugins from /plugins directory"))
if _, err := os.Stat("./plugins"); os.IsNotExist(err) { if _, err := os.Stat("./plugins"); os.IsNotExist(err) {
os.Mkdir("./plugins", os.ModePerm) os.Mkdir("./plugins", os.ModePerm)
} }
ForEachPlugin() //ForEachPlugin()
files, err := ioutil.ReadDir("./plugins") files, err := ioutil.ReadDir("./plugins")
if err != nil { if err != nil {
@ -94,33 +95,39 @@ func LoadPlugins() {
return return
} }
for _, f := range files { for _, f := range files {
utils.Log(1, fmt.Sprintf("Attempting to load plugin '%v'", f.Name()))
ext := strings.Split(f.Name(), ".") ext := strings.Split(f.Name(), ".")
if len(ext) != 2 { if len(ext) != 2 {
utils.Log(3, fmt.Sprintf("Plugin '%v' must end in .so extension", f.Name()))
continue continue
} }
if ext[1] != "so" { if ext[1] != "so" {
utils.Log(3, fmt.Sprintf("Plugin '%v' must end in .so extension", f.Name()))
continue continue
} }
plug, err := plg.Open("plugins/" + f.Name()) plug, err := plg.Open("plugins/" + f.Name())
if err != nil { if err != nil {
utils.Log(2, fmt.Sprintf("Plugin '%v' could not load correctly.\n", f.Name())) utils.Log(3, fmt.Sprintf("Plugin '%v' could not load correctly. %v", f.Name(), err))
continue continue
} }
symPlugin, err := plug.Lookup("Plugin") symPlugin, err := plug.Lookup("Plugin")
if err != nil {
utils.Log(3, fmt.Sprintf("Plugin '%v' could not load correctly. %v", f.Name(), err))
continue
}
var plugActions plugin.PluginActions var plugActions plugin.PluginActions
plugActions, ok := symPlugin.(plugin.PluginActions) plugActions, ok := symPlugin.(plugin.PluginActions)
if !ok { if !ok {
utils.Log(2, fmt.Sprintf("Plugin '%v' could not load correctly, error: %v\n", f.Name(), "unexpected type from module symbol")) utils.Log(3, fmt.Sprintf("Plugin '%v' could not load correctly, error: %v", f.Name(), err))
continue continue
} }
//allPlugins = append(allPlugins, plugActions) plugActions.OnLoad(core.DbSession)
core.CoreApp.Plugins = append(core.CoreApp.Plugins, plugActions.GetInfo()) core.CoreApp.Plugins = append(core.CoreApp.Plugins, plugActions.GetInfo())
core.CoreApp.AllPlugins = append(core.CoreApp.AllPlugins, plugActions)
} }
core.OnLoad(core.DbSession) utils.Log(1, fmt.Sprintf("Loaded %v Plugins\n", len(core.CoreApp.Plugins)))
//utils.Log(1, fmt.Sprintf("Loaded %v Plugins\n", len(allPlugins)))
ForEachPlugin()
} }

View File

@ -13,6 +13,7 @@ import (
"os" "os"
"strings" "strings"
"testing" "testing"
"time"
) )
var ( var (
@ -24,19 +25,13 @@ func RunInit(t *testing.T) {
RenderBoxes() RenderBoxes()
os.Remove("./statup.db") os.Remove("./statup.db")
os.Remove("./config.yml") os.Remove("./config.yml")
os.Remove("./index.html")
route = handlers.Router() route = handlers.Router()
LoadDotEnvs() LoadDotEnvs()
} }
var forceSequential chan bool = make(chan bool, 1) var forceSequential chan bool = make(chan bool, 1)
type databaseTest struct {
in string
out string
}
var dbTests []databaseTest
func TestRunAll(t *testing.T) { func TestRunAll(t *testing.T) {
databases := []string{"mysql", "sqlite", "postgres"} databases := []string{"mysql", "sqlite", "postgres"}
@ -63,9 +58,12 @@ func TestRunAll(t *testing.T) {
t.Run(dbt+" Select Comms", func(t *testing.T) { t.Run(dbt+" Select Comms", func(t *testing.T) {
RunSelectAllMysqlCommunications(t) RunSelectAllMysqlCommunications(t)
}) })
t.Run(dbt+" Create User", func(t *testing.T) { t.Run(dbt+" Create Users", func(t *testing.T) {
RunUser_Create(t) RunUser_Create(t)
}) })
t.Run(dbt+" Select Users", func(t *testing.T) {
RunUser_SelectAll(t)
})
t.Run(dbt+" Select Services", func(t *testing.T) { t.Run(dbt+" Select Services", func(t *testing.T) {
RunSelectAllServices(t) RunSelectAllServices(t)
}) })
@ -87,7 +85,7 @@ func TestRunAll(t *testing.T) {
t.Run(dbt+" Chart Data", func(t *testing.T) { t.Run(dbt+" Chart Data", func(t *testing.T) {
RunService_GraphData(t) RunService_GraphData(t)
}) })
t.Run(dbt+" Create Service", func(t *testing.T) { t.Run(dbt+" Create Failing Service", func(t *testing.T) {
RunBadService_Create(t) RunBadService_Create(t)
}) })
t.Run(dbt+" Check Service", func(t *testing.T) { t.Run(dbt+" Check Service", func(t *testing.T) {
@ -96,9 +94,18 @@ func TestRunAll(t *testing.T) {
t.Run(dbt+" Select Hits", func(t *testing.T) { t.Run(dbt+" Select Hits", func(t *testing.T) {
RunService_Hits(t) RunService_Hits(t)
}) })
t.Run(dbt+" Select Failures", func(t *testing.T) {
RunService_Failures(t)
})
t.Run(dbt+" Select Limited Hits", func(t *testing.T) { t.Run(dbt+" Select Limited Hits", func(t *testing.T) {
RunService_LimitedHits(t) RunService_LimitedHits(t)
}) })
t.Run(dbt+" Delete Service", func(t *testing.T) {
RunDeleteService(t)
})
t.Run(dbt+" Delete User", func(t *testing.T) {
RunUser_Delete(t)
})
t.Run(dbt+" HTTP /", func(t *testing.T) { t.Run(dbt+" HTTP /", func(t *testing.T) {
RunIndexHandler(t) RunIndexHandler(t)
}) })
@ -211,6 +218,8 @@ func RunSelectCoreMYQL(t *testing.T, db string) {
core.CoreApp, err = core.SelectCore() core.CoreApp, err = core.SelectCore()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "Testing "+db, core.CoreApp.Name) assert.Equal(t, "Testing "+db, core.CoreApp.Name)
assert.NotEmpty(t, core.CoreApp.ApiKey)
assert.NotEmpty(t, core.CoreApp.ApiSecret)
assert.Equal(t, VERSION, core.CoreApp.Version) assert.Equal(t, VERSION, core.CoreApp.Version)
} }
@ -228,6 +237,12 @@ func RunSelectAllMysqlCommunications(t *testing.T) {
assert.Equal(t, 2, len(comms)) assert.Equal(t, 2, len(comms))
} }
func RunUser_SelectAll(t *testing.T) {
users, err := core.SelectAllUsers()
assert.Nil(t, err)
assert.Equal(t, 2, len(users))
}
func RunUser_Create(t *testing.T) { func RunUser_Create(t *testing.T) {
user := &core.User{ user := &core.User{
Username: "admin", Username: "admin",
@ -236,7 +251,24 @@ func RunUser_Create(t *testing.T) {
} }
id, err := user.Create() id, err := user.Create()
assert.Nil(t, err) assert.Nil(t, err)
assert.NotZero(t, id) assert.Equal(t, int64(1), id)
user2 := &core.User{
Username: "superadmin",
Password: "admin",
Email: "info@adminer.com",
Admin: true,
}
id, err = user2.Create()
assert.Nil(t, err)
assert.Equal(t, int64(2), id)
}
func RunUser_Delete(t *testing.T) {
user, err := core.SelectUser(2)
assert.Nil(t, err)
assert.NotNil(t, user)
err = user.Delete()
assert.Nil(t, err)
} }
func RunSelectAllServices(t *testing.T) { func RunSelectAllServices(t *testing.T) {
@ -266,6 +298,7 @@ func RunService_Create(t *testing.T) {
id, err := service.Create() id, err := service.Create()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(5), id) assert.Equal(t, int64(5), id)
t.Log(service)
} }
func RunService_AvgTime(t *testing.T) { func RunService_AvgTime(t *testing.T) {
@ -286,6 +319,9 @@ func RunService_GraphData(t *testing.T) {
service := core.SelectService(1) service := core.SelectService(1)
assert.NotNil(t, service) assert.NotNil(t, service)
data := service.GraphData() data := service.GraphData()
t.Log(data)
assert.NotEqual(t, "null", data)
assert.False(t, strings.Contains(data, "0001-01-01T00:00:00Z"))
assert.NotEmpty(t, data) assert.NotEmpty(t, data)
} }
@ -310,15 +346,24 @@ func RunBadService_Check(t *testing.T) {
assert.Equal(t, "JSON API Tester", service.Name) assert.Equal(t, "JSON API Tester", service.Name)
} }
func RunDeleteService(t *testing.T) {
service := core.SelectService(4)
assert.NotNil(t, service)
assert.Equal(t, "JSON API Tester", service.Name)
err := service.Delete()
assert.Nil(t, err)
}
func RunCreateService_Hits(t *testing.T) { func RunCreateService_Hits(t *testing.T) {
services, err := core.SelectAllServices() services, err := core.SelectAllServices()
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, services) assert.NotNil(t, services)
for i := 0; i <= 2; i++ { for i := 0; i <= 10; i++ {
for _, s := range services { for _, s := range services {
service := s.Check() service := s.Check()
assert.NotNil(t, service) assert.NotNil(t, service)
} }
time.Sleep(1 * time.Second)
} }
} }
@ -330,6 +375,13 @@ func RunService_Hits(t *testing.T) {
assert.NotZero(t, len(hits)) assert.NotZero(t, len(hits))
} }
func RunService_Failures(t *testing.T) {
t.SkipNow()
service := core.SelectService(6)
assert.NotNil(t, service)
assert.NotEmpty(t, service.Failures)
}
func RunService_LimitedHits(t *testing.T) { func RunService_LimitedHits(t *testing.T) {
service := core.SelectService(1) service := core.SelectService(1)
assert.NotNil(t, service) assert.NotNil(t, service)
@ -363,7 +415,7 @@ func RunPrometheusHandler(t *testing.T) {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
route.ServeHTTP(rr, req) route.ServeHTTP(rr, req)
t.Log(rr.Body.String()) t.Log(rr.Body.String())
assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 6")) assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 5"))
} }
func RunFailingPrometheusHandler(t *testing.T) { func RunFailingPrometheusHandler(t *testing.T) {

View File

@ -17,7 +17,7 @@ CREATE TABLE users (
api_key VARCHAR(50), api_key VARCHAR(50),
api_secret VARCHAR(50), api_secret VARCHAR(50),
administrator BOOL NOT NULL DEFAULT '0', administrator BOOL NOT NULL DEFAULT '0',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX (id) INDEX (id)
); );
CREATE TABLE services ( CREATE TABLE services (
@ -32,34 +32,34 @@ CREATE TABLE services (
check_interval int(11), check_interval int(11),
post_data text, post_data text,
order_id integer, order_id integer,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX (id) INDEX (id)
); );
CREATE TABLE hits ( CREATE TABLE hits (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
service INTEGER NOT NULL, service INTEGER NOT NULL,
latency float, latency float,
created_at TIMESTAMP, created_at DATETIME,
INDEX (id, service), INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
); );
CREATE TABLE failures ( CREATE TABLE failures (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
issue text, issue text,
method text, method text,
service INTEGER NOT NULL, service INTEGER NOT NULL,
created_at TIMESTAMP, created_at DATETIME,
INDEX (id, service), INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
); );
CREATE TABLE checkins ( CREATE TABLE checkins (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
service INTEGER NOT NULL, service INTEGER NOT NULL,
check_interval integer, check_interval integer,
api text, api text,
created_at TIMESTAMP, created_at DATETIME,
INDEX (id, service), INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
); );
CREATE TABLE communication ( CREATE TABLE communication (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
@ -75,5 +75,5 @@ CREATE TABLE communication (
enabled BOOL NOT NULL DEFAULT '0', enabled BOOL NOT NULL DEFAULT '0',
removable BOOL NOT NULL DEFAULT '0', removable BOOL NOT NULL DEFAULT '0',
limits integer, limits integer,
created_at TIMESTAMP created_at DATETIME
); );

View File

@ -18,7 +18,7 @@ CREATE TABLE users (
api_key text, api_key text,
api_secret text, api_secret text,
administrator bool, administrator bool,
created_at TIMESTAMP created_at DATETIME
); );
CREATE TABLE services ( CREATE TABLE services (
@ -33,14 +33,14 @@ CREATE TABLE services (
check_interval integer, check_interval integer,
post_data text, post_data text,
order_id integer, order_id integer,
created_at TIMESTAMP created_at DATETIME
); );
CREATE TABLE hits ( CREATE TABLE hits (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE, service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
latency float, latency float,
created_at TIMESTAMP created_at DATETIME
); );
CREATE TABLE failures ( CREATE TABLE failures (
@ -48,7 +48,7 @@ CREATE TABLE failures (
issue text, issue text,
method text, method text,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE, service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
created_at TIMESTAMP created_at DATETIME
); );
CREATE TABLE checkins ( CREATE TABLE checkins (
@ -56,7 +56,7 @@ CREATE TABLE checkins (
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE, service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
check_interval integer, check_interval integer,
api text, api text,
created_at TIMESTAMP created_at DATETIME
); );
CREATE TABLE communication ( CREATE TABLE communication (
@ -73,7 +73,7 @@ CREATE TABLE communication (
enabled boolean, enabled boolean,
removable boolean, removable boolean,
limits integer, limits integer,
created_at TIMESTAMP created_at DATETIME
); );