mirror of https://github.com/statping/statping
core updates
parent
8a8101cb96
commit
b38c6cb670
|
@ -8,5 +8,8 @@
|
||||||
"DB_PASS": "password123",
|
"DB_PASS": "password123",
|
||||||
"GO_ENV": "production"
|
"GO_ENV": "production"
|
||||||
},
|
},
|
||||||
"chromeWebSecurity": false
|
"chromeWebSecurity": false,
|
||||||
|
"defaultCommandTimeout": 5000,
|
||||||
|
"requestTimeout": 5000,
|
||||||
|
"watchForFileChanges": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ context('Setup Process', () => {
|
||||||
cy.get('input[name="email"]').clear().type('info@domain.com')
|
cy.get('input[name="email"]').clear().type('info@domain.com')
|
||||||
cy.get('input[name="password"]').clear().type('admin')
|
cy.get('input[name="password"]').clear().type('admin')
|
||||||
cy.scrollTo('bottom')
|
cy.scrollTo('bottom')
|
||||||
cy.get('#setup_button').click().wait(10000)
|
cy.get('#setup_button').click()
|
||||||
cy.get('.header-title').should('contain', 'Demo Tester')
|
cy.get('.header-title').should('contain', 'Demo Tester')
|
||||||
cy.get('.header-desc').should('contain', 'This is a test from Crypress!')
|
cy.get('.header-desc').should('contain', 'This is a test from Crypress!')
|
||||||
cy.scrollTo('bottom')
|
cy.scrollTo('bottom')
|
||||||
|
|
|
@ -21,7 +21,7 @@ context('Asset Tests', () => {
|
||||||
}})
|
}})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should check css file', () => {
|
it('should confirm sass variable in css', () => {
|
||||||
cy.request('http://localhost:8080/css/base.css').its('body').should('contain', '.test-var')
|
cy.request('http://localhost:8080/css/base.css').its('body').should('contain', '.test-var')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -13,21 +13,85 @@ context('Service Tests', () => {
|
||||||
cy.title().should('eq', 'Statup | Services')
|
cy.title().should('eq', 'Statup | Services')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should create services', () => {
|
it('should create HTTP GET service', () => {
|
||||||
cy.visit('http://localhost:8080/services')
|
cy.visit('http://localhost:8080/services')
|
||||||
cy.get('input[name="name"]').type('Google.com')
|
cy.get('select[name="method"]').select('GET')
|
||||||
cy.get('input[name="domain"]').type('https://google.com')
|
cy.get('input[name="name"]').clear().type('Google.com')
|
||||||
cy.get('input[name="interval"]').type('30')
|
cy.get('select[name="check_type"]').select('http')
|
||||||
|
cy.get('input[name="domain"]').clear().type('https://google.com')
|
||||||
|
cy.get('input[name="expected_status"]').clear().type('200')
|
||||||
|
cy.get('input[name="interval"]').clear().type('25')
|
||||||
|
cy.get('input[name="timeout"]').clear().type('30')
|
||||||
cy.get('form').submit()
|
cy.get('form').submit()
|
||||||
cy.title().should('eq', 'Statup | Services')
|
cy.title().should('eq', 'Statup | Services')
|
||||||
cy.get('tr').should('have.length', 7)
|
cy.get('tr').should('have.length', 7)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should create HTTP POST service', () => {
|
||||||
|
cy.visit('http://localhost:8080/services')
|
||||||
|
cy.get('select[name="method"]').select('POST')
|
||||||
|
cy.get('input[name="name"]').clear().type('JSON Regex Test')
|
||||||
|
cy.get('select[name="check_type"]').select('http')
|
||||||
|
cy.get('input[name="domain"]').clear().type('https://jsonplaceholder.typicode.com/posts')
|
||||||
|
cy.get('textarea[name="post_data"]').clear().type(`(title)": "((\\"|[statup])*)"`)
|
||||||
|
cy.get('input[name="expected_status"]').clear().type('201')
|
||||||
|
cy.get('input[name="interval"]').clear().type('15')
|
||||||
|
cy.get('input[name="timeout"]').clear().type('45')
|
||||||
|
cy.get('form').submit()
|
||||||
|
cy.title().should('eq', 'Statup | Services')
|
||||||
|
cy.get('tr').should('have.length', 8)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should create TCP service', () => {
|
||||||
|
cy.visit('http://localhost:8080/services')
|
||||||
|
cy.get('select[name="check_type"]').select('tcp')
|
||||||
|
cy.get('input[name="name"]').clear().type('Google DNS')
|
||||||
|
cy.get('input[name="domain"]').clear().type('8.8.8.8')
|
||||||
|
cy.get('input[name="port"]').clear().type('53')
|
||||||
|
cy.get('input[name="interval"]').clear().type('25')
|
||||||
|
cy.get('input[name="timeout"]').clear().type('15')
|
||||||
|
cy.get('form').submit()
|
||||||
|
cy.title().should('eq', 'Statup | Services')
|
||||||
|
cy.get('tr').should('have.length', 9)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should view HTTP GET service', () => {
|
||||||
|
cy.visit('http://localhost:8080/service/6')
|
||||||
|
cy.title().should('eq', 'Statup | Google.com Service')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should view HTTP POST service', () => {
|
||||||
|
cy.visit('http://localhost:8080/service/7')
|
||||||
|
cy.title().should('eq', 'Statup | JSON Regex Test Service')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should view TCP service', () => {
|
||||||
|
cy.visit('http://localhost:8080/service/8')
|
||||||
|
cy.title().should('eq', 'Statup | Google DNS Service')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should update HTTP service', () => {
|
||||||
|
cy.visit('http://localhost:8080/service/6')
|
||||||
|
cy.title().should('eq', 'Statup | Google.com Service')
|
||||||
|
cy.get('#service_name').clear().type('Google Updated')
|
||||||
|
cy.get('#service_interval').clear().type('60')
|
||||||
|
cy.get(':nth-child(3) > form').submit()
|
||||||
|
cy.title().should('eq', 'Statup | Google Updated Service')
|
||||||
|
cy.get('#service_name').should('have.value', 'Google Updated')
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check the updated service', () => {
|
||||||
|
cy.visit('http://localhost:8080/service/6')
|
||||||
|
cy.title().should('eq', 'Statup | Google Updated Service')
|
||||||
|
cy.get('#service_name').should('have.value', 'Google Updated')
|
||||||
|
cy.get('#service_interval').should('have.value', '60')
|
||||||
|
})
|
||||||
|
|
||||||
it('should delete a service', () => {
|
it('should delete a service', () => {
|
||||||
cy.visit('http://localhost:8080/services')
|
cy.visit('http://localhost:8080/services')
|
||||||
cy.get(':nth-child(5) > .text-right > .btn-group > .btn-danger').click()
|
cy.get(':nth-child(5) > .text-right > .btn-group > .btn-danger').click()
|
||||||
cy.title().should('eq', 'Statup | Services')
|
cy.title().should('eq', 'Statup | Services')
|
||||||
cy.get('tr').should('have.length', 6)
|
cy.get('tr').should('have.length', 8)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,5 +21,11 @@ context('Settings Forms', () => {
|
||||||
cy.get('.footer').should('contain', 'This is a custom footer')
|
cy.get('.footer').should('contain', 'This is a custom footer')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// it('should check index page for changes', () => {
|
||||||
|
// cy.visit('http://localhost:8080/')
|
||||||
|
// cy.title().should('eq', 'Project Updated Status')
|
||||||
|
// cy.get('.header-title').should('contain', 'Project Updated')
|
||||||
|
// cy.get('.header-desc').should('contain', 'This is an awesome page')
|
||||||
|
// })
|
||||||
|
|
||||||
});
|
});
|
|
@ -23,6 +23,26 @@ context('User Testing', () => {
|
||||||
cy.get('tr').should('have.length', 3)
|
cy.get('tr').should('have.length', 3)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should create a edit user', () => {
|
||||||
|
cy.visit('http://localhost:8080/user/2')
|
||||||
|
cy.get('input[name="password"]').type('password567')
|
||||||
|
cy.get('input[name="password_confirm"]').type('password567')
|
||||||
|
cy.get('form').submit()
|
||||||
|
cy.get('tr').should('have.length', 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
// it('should logout and login with new password', () => {
|
||||||
|
// cy.visit('http://localhost:8080/logout')
|
||||||
|
// cy.title().should('eq', 'Statup | Users')
|
||||||
|
// cy.get('#user_2 > .btn-group > .btn-danger').click()
|
||||||
|
// cy.get('tr').should('have.length', 2)
|
||||||
|
// cy.visit('http://localhost:8080/login')
|
||||||
|
// cy.get('input[name="username"]').type('hunterlong')
|
||||||
|
// cy.get('input[name="password"]').type('password567')
|
||||||
|
// cy.get('form').submit()
|
||||||
|
// cy.title().should('eq', 'Project Updated Status')
|
||||||
|
// })
|
||||||
|
|
||||||
it('should delete a user', () => {
|
it('should delete a user', () => {
|
||||||
cy.visit('http://localhost:8080/users')
|
cy.visit('http://localhost:8080/users')
|
||||||
cy.get('#user_2 > .btn-group > .btn-danger').click()
|
cy.get('#user_2 > .btn-group > .btn-danger').click()
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -1,4 +1,4 @@
|
||||||
VERSION=0.45
|
VERSION=0.46
|
||||||
BINARY_NAME=statup
|
BINARY_NAME=statup
|
||||||
GOPATH:=$(GOPATH)
|
GOPATH:=$(GOPATH)
|
||||||
GOCMD=go
|
GOCMD=go
|
||||||
|
@ -69,10 +69,13 @@ docker:
|
||||||
docker-run: docker
|
docker-run: docker
|
||||||
docker run -t -p 8080:8080 hunterlong/statup:latest
|
docker run -t -p 8080:8080 hunterlong/statup:latest
|
||||||
|
|
||||||
docker-dev:
|
docker-dev: clean
|
||||||
docker build -t hunterlong/statup:dev -f Dockerfile-dev .
|
docker build -t hunterlong/statup:dev -f .dev/Dockerfile .
|
||||||
|
|
||||||
docker-run-dev: clean docker-dev
|
docker-push-dev: docker-dev
|
||||||
|
docker push hunterlong/statup:dev
|
||||||
|
|
||||||
|
docker-run-dev: docker-dev
|
||||||
docker run -t -p 8080:8080 hunterlong/statup:dev
|
docker run -t -p 8080:8080 hunterlong/statup:dev
|
||||||
|
|
||||||
docker-test: docker-dev
|
docker-test: docker-dev
|
||||||
|
|
20
cmd/cli.go
20
cmd/cli.go
|
@ -145,7 +145,7 @@ func RunOnce() {
|
||||||
utils.Log(4, err)
|
utils.Log(4, err)
|
||||||
}
|
}
|
||||||
for _, s := range core.CoreApp.Services {
|
for _, s := range core.CoreApp.Services {
|
||||||
out := core.ServiceCheck(s.ToService())
|
out := core.ServiceCheck(s, true)
|
||||||
fmt.Printf(" Service %v | URL: %v | Latency: %0.0fms | Online: %v\n", out.Name, out.Domain, (out.Latency * 1000), out.Online)
|
fmt.Printf(" Service %v | URL: %v | Latency: %0.0fms | Online: %v\n", out.Name, out.Domain, (out.Latency * 1000), out.Online)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,33 +191,33 @@ func TestPlugin(plug types.PluginActions) {
|
||||||
core.OnLoad(core.DbSession)
|
core.OnLoad(core.DbSession)
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
fmt.Println(POINT + "Sending 'OnSuccess(Service)'")
|
fmt.Println(POINT + "Sending 'OnSuccess(Service)'")
|
||||||
core.OnSuccess(core.SelectService(1).ToService())
|
core.OnSuccess(core.SelectService(1))
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
fmt.Println(POINT + "Sending 'OnFailure(Service, FailureData)'")
|
fmt.Println(POINT + "Sending 'OnFailure(Service, FailureData)'")
|
||||||
fakeFailD := core.FailureData{
|
fakeFailD := core.FailureData{
|
||||||
Issue: "No issue, just testing this plugin. This would include HTTP failure information though",
|
Issue: "No issue, just testing this plugin. This would include HTTP failure information though",
|
||||||
}
|
}
|
||||||
core.OnFailure(core.SelectService(1).ToService(), fakeFailD)
|
core.OnFailure(core.SelectService(1), fakeFailD)
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
fmt.Println(POINT + "Sending 'OnSettingsSaved(Core)'")
|
fmt.Println(POINT + "Sending 'OnSettingsSaved(Core)'")
|
||||||
fmt.Println(BRAKER)
|
fmt.Println(BRAKER)
|
||||||
core.OnSettingsSaved(core.CoreApp.ToCore())
|
core.OnSettingsSaved(core.CoreApp.ToCore())
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
fmt.Println(POINT + "Sending 'OnNewService(Service)'")
|
fmt.Println(POINT + "Sending 'OnNewService(Service)'")
|
||||||
core.OnNewService(core.SelectService(2).ToService())
|
core.OnNewService(core.SelectService(2))
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
fmt.Println(POINT + "Sending 'OnNewUser(User)'")
|
fmt.Println(POINT + "Sending 'OnNewUser(User)'")
|
||||||
user, _ := core.SelectUser(1)
|
user, _ := core.SelectUser(1)
|
||||||
core.OnNewUser(user)
|
core.OnNewUser(user)
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
fmt.Println(POINT + "Sending 'OnUpdateService(Service)'")
|
fmt.Println(POINT + "Sending 'OnUpdateService(Service)'")
|
||||||
srv := core.SelectService(2).ToService()
|
srv := core.SelectService(2)
|
||||||
srv.Type = "http"
|
srv.Type = "http"
|
||||||
srv.Domain = "https://yahoo.com"
|
srv.Domain = "https://yahoo.com"
|
||||||
core.OnUpdateService(srv)
|
core.OnUpdateService(srv)
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
fmt.Println(POINT + "Sending 'OnDeletedService(Service)'")
|
fmt.Println(POINT + "Sending 'OnDeletedService(Service)'")
|
||||||
core.OnDeletedService(core.SelectService(1).ToService())
|
core.OnDeletedService(core.SelectService(1))
|
||||||
fmt.Println("\n" + BRAKER)
|
fmt.Println("\n" + BRAKER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,18 +255,18 @@ func FakeSeed(plug types.PluginActions) {
|
||||||
core.CoreApp.ApiSecret = "0x0x0x0x0"
|
core.CoreApp.ApiSecret = "0x0x0x0x0"
|
||||||
core.CoreApp.ApiKey = "abcdefg12345"
|
core.CoreApp.ApiKey = "abcdefg12345"
|
||||||
|
|
||||||
fakeSrv := &types.Service{
|
fakeSrv := &core.Service{Service: &types.Service{
|
||||||
Name: "Test Plugin Service",
|
Name: "Test Plugin Service",
|
||||||
Domain: "https://google.com",
|
Domain: "https://google.com",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
}
|
}}
|
||||||
core.CreateService(fakeSrv)
|
core.CreateService(fakeSrv)
|
||||||
|
|
||||||
fakeSrv2 := &types.Service{
|
fakeSrv2 := &core.Service{Service: &types.Service{
|
||||||
Name: "Awesome Plugin Service",
|
Name: "Awesome Plugin Service",
|
||||||
Domain: "https://netflix.com",
|
Domain: "https://netflix.com",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
}
|
}}
|
||||||
core.CreateService(fakeSrv2)
|
core.CreateService(fakeSrv2)
|
||||||
|
|
||||||
fakeUser := &types.User{
|
fakeUser := &types.User{
|
||||||
|
|
|
@ -335,11 +335,11 @@ func RunOneService_Check(t *testing.T) {
|
||||||
service := core.SelectService(1)
|
service := core.SelectService(1)
|
||||||
assert.NotNil(t, service)
|
assert.NotNil(t, service)
|
||||||
t.Log(service)
|
t.Log(service)
|
||||||
assert.Equal(t, "Google", service.ToService().Name)
|
assert.Equal(t, "Google", service.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunService_Create(t *testing.T) {
|
func RunService_Create(t *testing.T) {
|
||||||
service := &types.Service{
|
service := &core.Service{Service: &types.Service{
|
||||||
Name: "test service",
|
Name: "test service",
|
||||||
Domain: "https://google.com",
|
Domain: "https://google.com",
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
|
@ -348,7 +348,7 @@ func RunService_Create(t *testing.T) {
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timeout: 30,
|
Timeout: 30,
|
||||||
}
|
}}
|
||||||
id, err := core.CreateService(service)
|
id, err := core.CreateService(service)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(6), id)
|
assert.Equal(t, int64(6), id)
|
||||||
|
@ -380,7 +380,7 @@ func RunService_GraphData(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunBadService_Create(t *testing.T) {
|
func RunBadService_Create(t *testing.T) {
|
||||||
service := &types.Service{
|
service := &core.Service{Service: &types.Service{
|
||||||
Name: "Bad Service",
|
Name: "Bad Service",
|
||||||
Domain: "https://9839f83h72gey2g29278hd2od2d.com",
|
Domain: "https://9839f83h72gey2g29278hd2od2d.com",
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
|
@ -389,7 +389,7 @@ func RunBadService_Create(t *testing.T) {
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timeout: 30,
|
Timeout: 30,
|
||||||
}
|
}}
|
||||||
id, err := core.CreateService(service)
|
id, err := core.CreateService(service)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(7), id)
|
assert.Equal(t, int64(7), id)
|
||||||
|
@ -398,14 +398,19 @@ func RunBadService_Create(t *testing.T) {
|
||||||
func RunBadService_Check(t *testing.T) {
|
func RunBadService_Check(t *testing.T) {
|
||||||
service := core.SelectService(4)
|
service := core.SelectService(4)
|
||||||
assert.NotNil(t, service)
|
assert.NotNil(t, service)
|
||||||
assert.Equal(t, "JSON API Tester", service.ToService().Name)
|
assert.Equal(t, "JSON API Tester", service.Name)
|
||||||
|
assert.True(t, service.IsRunning())
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunDeleteService(t *testing.T) {
|
func RunDeleteService(t *testing.T) {
|
||||||
service := core.SelectService(4)
|
service := core.SelectService(4)
|
||||||
assert.NotNil(t, service)
|
assert.NotNil(t, service)
|
||||||
assert.Equal(t, "JSON API Tester", service.ToService().Name)
|
assert.Equal(t, "JSON API Tester", service.Name)
|
||||||
err := core.DeleteService(service.ToService())
|
assert.True(t, service.IsRunning())
|
||||||
|
t.Log(service.Running)
|
||||||
|
err := core.DeleteService(service)
|
||||||
|
t.Log(service.Running)
|
||||||
|
assert.False(t, service.IsRunning())
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,11 +420,11 @@ func RunCreateService_Hits(t *testing.T) {
|
||||||
assert.NotNil(t, services)
|
assert.NotNil(t, services)
|
||||||
for i := 0; i <= 10; i++ {
|
for i := 0; i <= 10; i++ {
|
||||||
for _, s := range services {
|
for _, s := range services {
|
||||||
var service *types.Service
|
var service *core.Service
|
||||||
if s.ToService().Type == "http" {
|
if s.Type == "http" {
|
||||||
service = core.ServiceHTTPCheck(s.ToService())
|
service = core.ServiceHTTPCheck(s, true)
|
||||||
} else {
|
} else {
|
||||||
service = core.ServiceTCPCheck(s.ToService())
|
service = core.ServiceTCPCheck(s, true)
|
||||||
}
|
}
|
||||||
assert.NotNil(t, service)
|
assert.NotNil(t, service)
|
||||||
}
|
}
|
||||||
|
@ -438,7 +443,7 @@ func RunService_Failures(t *testing.T) {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
service := core.SelectService(6)
|
service := core.SelectService(6)
|
||||||
assert.NotNil(t, service)
|
assert.NotNil(t, service)
|
||||||
assert.NotEmpty(t, service.ToService().Failures)
|
assert.NotEmpty(t, service.Failures)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunService_LimitedHits(t *testing.T) {
|
func RunService_LimitedHits(t *testing.T) {
|
||||||
|
|
|
@ -33,28 +33,29 @@ type FailureData types.FailureData
|
||||||
func CheckServices() {
|
func CheckServices() {
|
||||||
CoreApp.Services, _ = SelectAllServices()
|
CoreApp.Services, _ = SelectAllServices()
|
||||||
utils.Log(1, fmt.Sprintf("Starting monitoring process for %v Services", len(CoreApp.Services)))
|
utils.Log(1, fmt.Sprintf("Starting monitoring process for %v Services", len(CoreApp.Services)))
|
||||||
for _, ser := range CoreApp.Services {
|
for _, s := range CoreApp.Services {
|
||||||
s := ser.ToService()
|
|
||||||
//go obj.StartCheckins()
|
//go obj.StartCheckins()
|
||||||
s.Start()
|
go CheckQueue(s, true)
|
||||||
go CheckQueue(s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckQueue(s *types.Service) {
|
func CheckQueue(s *Service, record bool) {
|
||||||
|
CheckLoop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.StopRoutine:
|
case <-s.Running:
|
||||||
return
|
utils.Log(1, fmt.Sprintf("Stopping service: %v", s.Name))
|
||||||
|
break CheckLoop
|
||||||
default:
|
default:
|
||||||
s = SelectService(s.Id).ToService()
|
utils.Log(1, fmt.Sprintf("Checking service: %v", s.Name))
|
||||||
ServiceCheck(s)
|
ServiceCheck(s, record)
|
||||||
}
|
|
||||||
time.Sleep(time.Duration(s.Interval) * time.Second)
|
time.Sleep(time.Duration(s.Interval) * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DNSCheck(s *types.Service) (float64, error) {
|
func DNSCheck(s *Service) (float64, error) {
|
||||||
t1 := time.Now()
|
t1 := time.Now()
|
||||||
url, err := url.Parse(s.Domain)
|
url, err := url.Parse(s.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,7 +70,7 @@ func DNSCheck(s *types.Service) (float64, error) {
|
||||||
return subTime, err
|
return subTime, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServiceTCPCheck(s *types.Service) *types.Service {
|
func ServiceTCPCheck(s *Service, record bool) *Service {
|
||||||
t1 := time.Now()
|
t1 := time.Now()
|
||||||
domain := fmt.Sprintf("%v", s.Domain)
|
domain := fmt.Sprintf("%v", s.Domain)
|
||||||
if s.Port != 0 {
|
if s.Port != 0 {
|
||||||
|
@ -77,34 +78,42 @@ func ServiceTCPCheck(s *types.Service) *types.Service {
|
||||||
}
|
}
|
||||||
conn, err := net.DialTimeout("tcp", domain, time.Duration(s.Timeout)*time.Second)
|
conn, err := net.DialTimeout("tcp", domain, time.Duration(s.Timeout)*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if record {
|
||||||
RecordFailure(s, fmt.Sprintf("TCP Dial Error %v", err))
|
RecordFailure(s, fmt.Sprintf("TCP Dial Error %v", err))
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
if err := conn.Close(); err != nil {
|
if err := conn.Close(); err != nil {
|
||||||
|
if record {
|
||||||
RecordFailure(s, fmt.Sprintf("TCP Socket Close Error %v", err))
|
RecordFailure(s, fmt.Sprintf("TCP Socket Close Error %v", err))
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
t2 := time.Now()
|
t2 := time.Now()
|
||||||
s.Latency = t2.Sub(t1).Seconds()
|
s.Latency = t2.Sub(t1).Seconds()
|
||||||
s.LastResponse = ""
|
s.LastResponse = ""
|
||||||
|
if record {
|
||||||
RecordSuccess(s)
|
RecordSuccess(s)
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServiceCheck(s *types.Service) *types.Service {
|
|
||||||
switch s.Type {
|
|
||||||
case "http":
|
|
||||||
ServiceHTTPCheck(s)
|
|
||||||
case "tcp":
|
|
||||||
ServiceTCPCheck(s)
|
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServiceHTTPCheck(s *types.Service) *types.Service {
|
func ServiceCheck(s *Service, record bool) *Service {
|
||||||
|
switch s.Type {
|
||||||
|
case "http":
|
||||||
|
ServiceHTTPCheck(s, record)
|
||||||
|
case "tcp":
|
||||||
|
ServiceTCPCheck(s, record)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func ServiceHTTPCheck(s *Service, record bool) *Service {
|
||||||
dnsLookup, err := DNSCheck(s)
|
dnsLookup, err := DNSCheck(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if record {
|
||||||
RecordFailure(s, fmt.Sprintf("Could not get IP address for domain %v, %v", s.Domain, err))
|
RecordFailure(s, fmt.Sprintf("Could not get IP address for domain %v, %v", s.Domain, err))
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
s.DnsLookup = dnsLookup
|
s.DnsLookup = dnsLookup
|
||||||
|
@ -121,7 +130,9 @@ func ServiceHTTPCheck(s *types.Service) *types.Service {
|
||||||
response, err = client.Get(s.Domain)
|
response, err = client.Get(s.Domain)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if record {
|
||||||
RecordFailure(s, fmt.Sprintf("HTTP Error %v", err))
|
RecordFailure(s, fmt.Sprintf("HTTP Error %v", err))
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
response.Header.Set("Connection", "close")
|
response.Header.Set("Connection", "close")
|
||||||
|
@ -129,7 +140,9 @@ func ServiceHTTPCheck(s *types.Service) *types.Service {
|
||||||
t2 := time.Now()
|
t2 := time.Now()
|
||||||
s.Latency = t2.Sub(t1).Seconds()
|
s.Latency = t2.Sub(t1).Seconds()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if record {
|
||||||
RecordFailure(s, fmt.Sprintf("HTTP Error %v", err))
|
RecordFailure(s, fmt.Sprintf("HTTP Error %v", err))
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
@ -145,20 +158,26 @@ func ServiceHTTPCheck(s *types.Service) *types.Service {
|
||||||
if !match {
|
if !match {
|
||||||
s.LastResponse = string(contents)
|
s.LastResponse = string(contents)
|
||||||
s.LastStatusCode = response.StatusCode
|
s.LastStatusCode = response.StatusCode
|
||||||
|
if record {
|
||||||
RecordFailure(s, fmt.Sprintf("HTTP Response Body did not match '%v'", s.Expected))
|
RecordFailure(s, fmt.Sprintf("HTTP Response Body did not match '%v'", s.Expected))
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.ExpectedStatus != response.StatusCode {
|
if s.ExpectedStatus != response.StatusCode {
|
||||||
s.LastResponse = string(contents)
|
s.LastResponse = string(contents)
|
||||||
s.LastStatusCode = response.StatusCode
|
s.LastStatusCode = response.StatusCode
|
||||||
|
if record {
|
||||||
RecordFailure(s, fmt.Sprintf("HTTP Status Code %v did not match %v", response.StatusCode, s.ExpectedStatus))
|
RecordFailure(s, fmt.Sprintf("HTTP Status Code %v did not match %v", response.StatusCode, s.ExpectedStatus))
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
s.LastResponse = string(contents)
|
s.LastResponse = string(contents)
|
||||||
s.LastStatusCode = response.StatusCode
|
s.LastStatusCode = response.StatusCode
|
||||||
s.Online = true
|
s.Online = true
|
||||||
|
if record {
|
||||||
RecordSuccess(s)
|
RecordSuccess(s)
|
||||||
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +185,7 @@ type HitData struct {
|
||||||
Latency float64
|
Latency float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func RecordSuccess(s *types.Service) {
|
func RecordSuccess(s *Service) {
|
||||||
s.Online = true
|
s.Online = true
|
||||||
s.LastOnline = time.Now()
|
s.LastOnline = time.Now()
|
||||||
data := HitData{
|
data := HitData{
|
||||||
|
@ -177,7 +196,7 @@ func RecordSuccess(s *types.Service) {
|
||||||
OnSuccess(s)
|
OnSuccess(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RecordFailure(s *types.Service, issue string) {
|
func RecordFailure(s *Service, issue string) {
|
||||||
s.Online = false
|
s.Online = false
|
||||||
data := FailureData{
|
data := FailureData{
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
|
|
|
@ -31,7 +31,7 @@ func (c *Checkin) String() string {
|
||||||
|
|
||||||
func FindCheckin(api string) *types.Checkin {
|
func FindCheckin(api string) *types.Checkin {
|
||||||
for _, ser := range CoreApp.Services {
|
for _, ser := range CoreApp.Services {
|
||||||
for _, c := range ser.ToService().Checkins {
|
for _, c := range ser.Checkins {
|
||||||
if c.Api == api {
|
if c.Api == api {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,8 +113,7 @@ func (c Core) MobileSASS() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Core) AllOnline() bool {
|
func (c Core) AllOnline() bool {
|
||||||
for _, ser := range CoreApp.Services {
|
for _, s := range CoreApp.Services {
|
||||||
s := ser.ToService()
|
|
||||||
if !s.Online {
|
if !s.Online {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/fatih/structs"
|
"github.com/fatih/structs"
|
||||||
"github.com/hunterlong/statup/notifiers"
|
|
||||||
"github.com/hunterlong/statup/types"
|
"github.com/hunterlong/statup/types"
|
||||||
"upper.io/db.v3/lib/sqlbuilder"
|
"upper.io/db.v3/lib/sqlbuilder"
|
||||||
)
|
)
|
||||||
|
@ -28,18 +27,20 @@ func OnLoad(db sqlbuilder.Database) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnSuccess(s *types.Service) {
|
func OnSuccess(s *Service) {
|
||||||
for _, p := range CoreApp.AllPlugins {
|
for _, p := range CoreApp.AllPlugins {
|
||||||
p.OnSuccess(structs.Map(s))
|
p.OnSuccess(structs.Map(s))
|
||||||
}
|
}
|
||||||
notifiers.OnSuccess(s)
|
//notifiers.OnSuccess(s)
|
||||||
|
// TODO convert notifiers to correct type
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnFailure(s *types.Service, f FailureData) {
|
func OnFailure(s *Service, f FailureData) {
|
||||||
for _, p := range CoreApp.AllPlugins {
|
for _, p := range CoreApp.AllPlugins {
|
||||||
p.OnFailure(structs.Map(s))
|
p.OnFailure(structs.Map(s))
|
||||||
}
|
}
|
||||||
notifiers.OnFailure(s)
|
//notifiers.OnFailure(s)
|
||||||
|
// TODO convert notifiers to correct type
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnSettingsSaved(c *types.Core) {
|
func OnSettingsSaved(c *types.Core) {
|
||||||
|
@ -54,19 +55,19 @@ func OnNewUser(u *types.User) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnNewService(s *types.Service) {
|
func OnNewService(s *Service) {
|
||||||
for _, p := range CoreApp.AllPlugins {
|
for _, p := range CoreApp.AllPlugins {
|
||||||
p.OnNewService(structs.Map(s))
|
p.OnNewService(structs.Map(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnDeletedService(s *types.Service) {
|
func OnDeletedService(s *Service) {
|
||||||
for _, p := range CoreApp.AllPlugins {
|
for _, p := range CoreApp.AllPlugins {
|
||||||
p.OnDeletedService(structs.Map(s))
|
p.OnDeletedService(structs.Map(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnUpdateService(s *types.Service) {
|
func OnUpdateService(s *Service) {
|
||||||
for _, p := range CoreApp.AllPlugins {
|
for _, p := range CoreApp.AllPlugins {
|
||||||
p.OnUpdatedService(structs.Map(s))
|
p.OnUpdatedService(structs.Map(s))
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateServiceFailure(s *types.Service, data FailureData) (int64, error) {
|
func CreateServiceFailure(s *Service, data FailureData) (int64, error) {
|
||||||
fail := &types.Failure{
|
fail := &types.Failure{
|
||||||
Issue: data.Issue,
|
Issue: data.Issue,
|
||||||
Service: s.Id,
|
Service: s.Id,
|
||||||
|
@ -52,7 +52,7 @@ func SelectAllFailures(s *types.Service) []*types.Failure {
|
||||||
return fails
|
return fails
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteFailures(u *types.Service) {
|
func DeleteFailures(u *Service) {
|
||||||
var fails []*Failure
|
var fails []*Failure
|
||||||
col := DbSession.Collection("failures")
|
col := DbSession.Collection("failures")
|
||||||
col.Find("service", u.Id).All(&fails)
|
col.Find("service", u.Id).All(&fails)
|
||||||
|
@ -61,8 +61,7 @@ func DeleteFailures(u *types.Service) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) LimitedFailures() []*Failure {
|
func (s *Service) LimitedFailures() []*Failure {
|
||||||
s := ser.ToService()
|
|
||||||
var fails []*types.Failure
|
var fails []*types.Failure
|
||||||
var failArr []*Failure
|
var failArr []*Failure
|
||||||
col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id").Limit(10)
|
col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id").Limit(10)
|
||||||
|
@ -102,15 +101,13 @@ func CountFailures() uint64 {
|
||||||
return amount
|
return amount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) TotalFailures() (uint64, error) {
|
func (s *Service) TotalFailures() (uint64, error) {
|
||||||
s := ser.ToService()
|
|
||||||
col := DbSession.Collection("failures").Find("service", s.Id)
|
col := DbSession.Collection("failures").Find("service", s.Id)
|
||||||
amount, err := col.Count()
|
amount, err := col.Count()
|
||||||
return amount, err
|
return amount, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) TotalFailures24Hours() (uint64, error) {
|
func (s *Service) TotalFailures24Hours() (uint64, error) {
|
||||||
s := ser.ToService()
|
|
||||||
col := DbSession.Collection("failures").Find("service", s.Id)
|
col := DbSession.Collection("failures").Find("service", s.Id)
|
||||||
amount, err := col.Count()
|
amount, err := col.Count()
|
||||||
return amount, err
|
return amount, err
|
||||||
|
|
14
core/hits.go
14
core/hits.go
|
@ -28,7 +28,7 @@ func hitCol() db.Collection {
|
||||||
return DbSession.Collection("hits")
|
return DbSession.Collection("hits")
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateServiceHit(s *types.Service, d HitData) (int64, error) {
|
func CreateServiceHit(s *Service, d HitData) (int64, error) {
|
||||||
h := Hit{
|
h := Hit{
|
||||||
Service: s.Id,
|
Service: s.Id,
|
||||||
Latency: d.Latency,
|
Latency: d.Latency,
|
||||||
|
@ -42,16 +42,14 @@ func CreateServiceHit(s *types.Service, d HitData) (int64, error) {
|
||||||
return uuid.(int64), err
|
return uuid.(int64), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) Hits() ([]Hit, error) {
|
func (s *Service) Hits() ([]Hit, error) {
|
||||||
s := ser.ToService()
|
|
||||||
var hits []Hit
|
var hits []Hit
|
||||||
col := hitCol().Find("service", s.Id).OrderBy("-id")
|
col := hitCol().Find("service", s.Id).OrderBy("-id")
|
||||||
err := col.All(&hits)
|
err := col.All(&hits)
|
||||||
return hits, err
|
return hits, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) LimitedHits() ([]*Hit, error) {
|
func (s *Service) LimitedHits() ([]*Hit, error) {
|
||||||
s := ser.ToService()
|
|
||||||
var hits []*Hit
|
var hits []*Hit
|
||||||
col := hitCol().Find("service", s.Id).OrderBy("-id").Limit(1024)
|
col := hitCol().Find("service", s.Id).OrderBy("-id").Limit(1024)
|
||||||
err := col.All(&hits)
|
err := col.All(&hits)
|
||||||
|
@ -65,16 +63,14 @@ func reverseHits(input []*Hit) []*Hit {
|
||||||
return append(reverseHits(input[1:]), input[0])
|
return append(reverseHits(input[1:]), input[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) SelectHitsGroupBy(group string) ([]Hit, error) {
|
func (s *Service) SelectHitsGroupBy(group string) ([]Hit, error) {
|
||||||
s := ser.ToService()
|
|
||||||
var hits []Hit
|
var hits []Hit
|
||||||
col := hitCol().Find("service", s.Id)
|
col := hitCol().Find("service", s.Id)
|
||||||
err := col.All(&hits)
|
err := col.All(&hits)
|
||||||
return hits, err
|
return hits, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) TotalHits() (uint64, error) {
|
func (s *Service) TotalHits() (uint64, error) {
|
||||||
s := ser.ToService()
|
|
||||||
col := hitCol().Find("service", s.Id)
|
col := hitCol().Find("service", s.Id)
|
||||||
amount, err := col.Count()
|
amount, err := col.Count()
|
||||||
return amount, err
|
return amount, err
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
s *types.Service
|
*types.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
type Failure struct {
|
type Failure struct {
|
||||||
|
@ -39,9 +39,8 @@ func serviceCol() db.Collection {
|
||||||
|
|
||||||
func SelectService(id int64) *Service {
|
func SelectService(id int64) *Service {
|
||||||
for _, s := range CoreApp.Services {
|
for _, s := range CoreApp.Services {
|
||||||
ser := s.ToService()
|
if s.Id == id {
|
||||||
if ser.Id == id {
|
return s
|
||||||
return &Service{ser}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -58,9 +57,10 @@ func SelectAllServices() ([]*Service, error) {
|
||||||
}
|
}
|
||||||
for _, s := range services {
|
for _, s := range services {
|
||||||
ser := NewService(s)
|
ser := NewService(s)
|
||||||
|
ser.Start()
|
||||||
|
ser.Checkins = SelectAllCheckins(s)
|
||||||
|
ser.Failures = SelectAllFailures(s)
|
||||||
sers = append(sers, ser)
|
sers = append(sers, ser)
|
||||||
s.Checkins = SelectAllCheckins(s)
|
|
||||||
s.Failures = SelectAllFailures(s)
|
|
||||||
}
|
}
|
||||||
CoreApp.Services = sers
|
CoreApp.Services = sers
|
||||||
return sers, err
|
return sers, err
|
||||||
|
@ -78,10 +78,9 @@ func (s *Service) AvgTime() float64 {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) Online24() float32 {
|
func (s *Service) Online24() float32 {
|
||||||
s := ser.ToService()
|
total, _ := s.TotalHits()
|
||||||
total, _ := ser.TotalHits()
|
failed, _ := s.TotalFailures24Hours()
|
||||||
failed, _ := ser.TotalFailures24Hours()
|
|
||||||
if failed == 0 {
|
if failed == 0 {
|
||||||
s.Online24Hours = 100.00
|
s.Online24Hours = 100.00
|
||||||
return s.Online24Hours
|
return s.Online24Hours
|
||||||
|
@ -105,18 +104,13 @@ type DateScan struct {
|
||||||
Value int64 `json:"y"`
|
Value int64 `json:"y"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ToService() *types.Service {
|
|
||||||
return s.s
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(s *types.Service) *Service {
|
func NewService(s *types.Service) *Service {
|
||||||
return &Service{s}
|
return &Service{s}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) SmallText() string {
|
func (s *Service) SmallText() string {
|
||||||
s := ser.ToService()
|
last := s.LimitedFailures()
|
||||||
last := ser.LimitedFailures()
|
hits, _ := s.LimitedHits()
|
||||||
hits, _ := ser.LimitedHits()
|
|
||||||
if !s.Online {
|
if !s.Online {
|
||||||
if len(last) > 0 {
|
if len(last) > 0 {
|
||||||
lastFailure := MakeFailure(last[0].ToFailure())
|
lastFailure := MakeFailure(last[0].ToFailure())
|
||||||
|
@ -147,8 +141,7 @@ func GroupDataBy(column string, id int64, tm time.Time, increment string) string
|
||||||
return sql
|
return sql
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) GraphData() string {
|
func (s *Service) GraphData() string {
|
||||||
s := ser.ToService()
|
|
||||||
var d []*DateScan
|
var d []*DateScan
|
||||||
since := time.Now().Add(time.Hour*-24 + time.Minute*0 + time.Second*0)
|
since := time.Now().Add(time.Hour*-24 + time.Minute*0 + time.Second*0)
|
||||||
|
|
||||||
|
@ -182,10 +175,9 @@ func (ser *Service) GraphData() string {
|
||||||
return string(data)
|
return string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ser *Service) AvgUptime() string {
|
func (s *Service) AvgUptime() string {
|
||||||
s := ser.ToService()
|
failed, _ := s.TotalFailures()
|
||||||
failed, _ := ser.TotalFailures()
|
total, _ := s.TotalHits()
|
||||||
total, _ := ser.TotalHits()
|
|
||||||
if failed == 0 {
|
if failed == 0 {
|
||||||
s.TotalUptime = "100"
|
s.TotalUptime = "100"
|
||||||
return s.TotalUptime
|
return s.TotalUptime
|
||||||
|
@ -206,11 +198,10 @@ func (ser *Service) AvgUptime() string {
|
||||||
return s.TotalUptime
|
return s.TotalUptime
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveArray(u *types.Service) []*Service {
|
func RemoveArray(u *Service) []*Service {
|
||||||
var srvcs []*Service
|
var srvcs []*Service
|
||||||
for _, s := range CoreApp.Services {
|
for _, s := range CoreApp.Services {
|
||||||
ser := s.ToService()
|
if s.Id != u.Id {
|
||||||
if ser.Id != u.Id {
|
|
||||||
srvcs = append(srvcs, s)
|
srvcs = append(srvcs, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,24 +209,20 @@ func RemoveArray(u *types.Service) []*Service {
|
||||||
return srvcs
|
return srvcs
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteService(u *types.Service) error {
|
func DeleteService(u *Service) error {
|
||||||
res := serviceCol().Find("id", u.Id)
|
res := serviceCol().Find("id", u.Id)
|
||||||
err := res.Delete()
|
err := res.Delete()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err))
|
utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
utils.Log(1, fmt.Sprintf("Stopping %v Monitoring...", u.Name))
|
u.Close()
|
||||||
if u.StopRoutine != nil {
|
|
||||||
close(u.StopRoutine)
|
|
||||||
}
|
|
||||||
utils.Log(1, fmt.Sprintf("Stopped %v Monitoring Service", u.Name))
|
|
||||||
RemoveArray(u)
|
RemoveArray(u)
|
||||||
OnDeletedService(u)
|
OnDeletedService(u)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateService(service *types.Service) *types.Service {
|
func UpdateService(service *Service) *Service {
|
||||||
service.CreatedAt = time.Now()
|
service.CreatedAt = time.Now()
|
||||||
res := serviceCol().Find("id", service.Id)
|
res := serviceCol().Find("id", service.Id)
|
||||||
err := res.Update(service)
|
err := res.Update(service)
|
||||||
|
@ -243,23 +230,28 @@ func UpdateService(service *types.Service) *types.Service {
|
||||||
utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", service.Name, err))
|
utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", service.Name, err))
|
||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
CoreApp.Services, _ = SelectAllServices()
|
updateService(service)
|
||||||
|
CoreApp.Services, err = SelectAllServices()
|
||||||
|
if err != nil {
|
||||||
|
utils.Log(3, fmt.Sprintf("error selecting all services: %v", err))
|
||||||
|
return service
|
||||||
|
}
|
||||||
OnUpdateService(service)
|
OnUpdateService(service)
|
||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateService(u *types.Service) {
|
func updateService(new *Service) {
|
||||||
var services []*Service
|
var services []*Service
|
||||||
for _, s := range CoreApp.Services {
|
for _, s := range CoreApp.Services {
|
||||||
if s.s.Id == u.Id {
|
if s.Id == new.Id {
|
||||||
s.s = u
|
s = new
|
||||||
}
|
}
|
||||||
services = append(services, s)
|
services = append(services, s)
|
||||||
}
|
}
|
||||||
CoreApp.Services = services
|
CoreApp.Services = services
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateService(u *types.Service) (int64, error) {
|
func CreateService(u *Service) (int64, error) {
|
||||||
u.CreatedAt = time.Now()
|
u.CreatedAt = time.Now()
|
||||||
uuid, err := serviceCol().Insert(u)
|
uuid, err := serviceCol().Insert(u)
|
||||||
if uuid == nil {
|
if uuid == nil {
|
||||||
|
@ -267,16 +259,15 @@ func CreateService(u *types.Service) (int64, error) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
u.Id = uuid.(int64)
|
u.Id = uuid.(int64)
|
||||||
u.StopRoutine = make(chan bool)
|
u.Start()
|
||||||
CoreApp.Services = append(CoreApp.Services, &Service{u})
|
CoreApp.Services = append(CoreApp.Services, u)
|
||||||
return uuid.(int64), err
|
return uuid.(int64), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func CountOnline() int {
|
func CountOnline() int {
|
||||||
amount := 0
|
amount := 0
|
||||||
for _, s := range CoreApp.Services {
|
for _, s := range CoreApp.Services {
|
||||||
ser := s.ToService()
|
if s.Online {
|
||||||
if ser.Online {
|
|
||||||
amount++
|
amount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/hunterlong/statup/types"
|
"github.com/hunterlong/statup/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -33,35 +34,47 @@ func TestSelectAllServices(t *testing.T) {
|
||||||
|
|
||||||
func TestSelectHTTPService(t *testing.T) {
|
func TestSelectHTTPService(t *testing.T) {
|
||||||
service := SelectService(1)
|
service := SelectService(1)
|
||||||
assert.Equal(t, "Google", service.ToService().Name)
|
assert.Equal(t, "Google", service.Name)
|
||||||
assert.Equal(t, "http", service.ToService().Type)
|
assert.Equal(t, "http", service.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectTCPService(t *testing.T) {
|
func TestSelectTCPService(t *testing.T) {
|
||||||
service := SelectService(5)
|
service := SelectService(5)
|
||||||
assert.Equal(t, "Google DNS", service.ToService().Name)
|
assert.Equal(t, "Google DNS", service.Name)
|
||||||
assert.Equal(t, "tcp", service.ToService().Type)
|
assert.Equal(t, "tcp", service.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateService(t *testing.T) {
|
func TestUpdateService(t *testing.T) {
|
||||||
service := SelectService(1)
|
service := SelectService(1)
|
||||||
assert.Equal(t, "Google", service.ToService().Name)
|
assert.Equal(t, "Google", service.Name)
|
||||||
srv := service.ToService()
|
srv := service
|
||||||
srv.Name = "Updated Google"
|
srv.Name = "Updated Google"
|
||||||
newService := UpdateService(srv)
|
newService := UpdateService(srv)
|
||||||
assert.Equal(t, "Updated Google", newService.Name)
|
assert.Equal(t, "Updated Google", newService.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateAllServices(t *testing.T) {
|
||||||
|
services, err := SelectAllServices()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
for k, s := range services {
|
||||||
|
srv := s
|
||||||
|
srv.Name = "Changed " + srv.Name
|
||||||
|
srv.Interval = k + 3
|
||||||
|
newService := UpdateService(srv)
|
||||||
|
assert.Contains(t, newService.Name, "Changed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestServiceHTTPCheck(t *testing.T) {
|
func TestServiceHTTPCheck(t *testing.T) {
|
||||||
service := SelectService(1)
|
service := SelectService(1)
|
||||||
checked := ServiceCheck(service.ToService())
|
checked := ServiceCheck(service, true)
|
||||||
assert.Equal(t, "Updated Google", checked.Name)
|
assert.Equal(t, "Changed Updated Google", checked.Name)
|
||||||
assert.True(t, checked.Online)
|
assert.True(t, checked.Online)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckHTTPService(t *testing.T) {
|
func TestCheckHTTPService(t *testing.T) {
|
||||||
service := SelectService(1).ToService()
|
service := SelectService(1)
|
||||||
assert.Equal(t, "Updated Google", service.Name)
|
assert.Equal(t, "Changed Updated Google", service.Name)
|
||||||
assert.True(t, service.Online)
|
assert.True(t, service.Online)
|
||||||
assert.Equal(t, 200, service.LastStatusCode)
|
assert.Equal(t, 200, service.LastStatusCode)
|
||||||
assert.NotZero(t, service.Latency)
|
assert.NotZero(t, service.Latency)
|
||||||
|
@ -69,14 +82,14 @@ func TestCheckHTTPService(t *testing.T) {
|
||||||
|
|
||||||
func TestServiceTCPCheck(t *testing.T) {
|
func TestServiceTCPCheck(t *testing.T) {
|
||||||
service := SelectService(5)
|
service := SelectService(5)
|
||||||
checked := ServiceCheck(service.ToService())
|
checked := ServiceCheck(service, true)
|
||||||
assert.Equal(t, "Google DNS", checked.Name)
|
assert.Equal(t, "Changed Google DNS", checked.Name)
|
||||||
assert.True(t, checked.Online)
|
assert.True(t, checked.Online)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckTCPService(t *testing.T) {
|
func TestCheckTCPService(t *testing.T) {
|
||||||
service := SelectService(5).ToService()
|
service := SelectService(5)
|
||||||
assert.Equal(t, "Google DNS", service.Name)
|
assert.Equal(t, "Changed Google DNS", service.Name)
|
||||||
assert.True(t, service.Online)
|
assert.True(t, service.Online)
|
||||||
assert.NotZero(t, service.Latency)
|
assert.NotZero(t, service.Latency)
|
||||||
}
|
}
|
||||||
|
@ -133,68 +146,74 @@ func TestCountOnline(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateService(t *testing.T) {
|
func TestCreateService(t *testing.T) {
|
||||||
s := &types.Service{
|
s := &Service{Service: &types.Service{
|
||||||
Name: "Interpol - All The Rage Back Home",
|
Name: "That'll do 🐢",
|
||||||
Domain: "https://www.youtube.com/watch?v=-u6DvRyyKGU",
|
Domain: "https://www.youtube.com/watch?v=rjQtzV9IZ0Q",
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
Interval: 30,
|
Interval: 3,
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timeout: 20,
|
Timeout: 20,
|
||||||
}
|
}}
|
||||||
var err error
|
var err error
|
||||||
newServiceId, err = CreateService(s)
|
newServiceId, err = CreateService(s)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotZero(t, newServiceId)
|
assert.NotZero(t, newServiceId)
|
||||||
newService := SelectService(newServiceId).ToService()
|
newService := SelectService(newServiceId)
|
||||||
assert.Equal(t, "Interpol - All The Rage Back Home", newService.Name)
|
assert.Equal(t, "That'll do 🐢", newService.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestViewNewService(t *testing.T) {
|
||||||
|
newService := SelectService(newServiceId)
|
||||||
|
assert.Equal(t, "That'll do 🐢", newService.Name)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateFailingHTTPService(t *testing.T) {
|
func TestCreateFailingHTTPService(t *testing.T) {
|
||||||
s := &types.Service{
|
s := &Service{Service: &types.Service{
|
||||||
Name: "Bad URL",
|
Name: "Bad URL",
|
||||||
Domain: "http://localhost/iamnothere",
|
Domain: "http://localhost/iamnothere",
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
Interval: 30,
|
Interval: 2,
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timeout: 5,
|
Timeout: 5,
|
||||||
}
|
}}
|
||||||
var err error
|
var err error
|
||||||
newServiceId, err = CreateService(s)
|
newServiceId, err = CreateService(s)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotZero(t, newServiceId)
|
assert.NotZero(t, newServiceId)
|
||||||
newService := SelectService(newServiceId).ToService()
|
newService := SelectService(newServiceId)
|
||||||
assert.Equal(t, "Bad URL", newService.Name)
|
assert.Equal(t, "Bad URL", newService.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceFailedCheck(t *testing.T) {
|
func TestServiceFailedCheck(t *testing.T) {
|
||||||
service := SelectService(7)
|
service := SelectService(7)
|
||||||
checked := ServiceCheck(service.ToService())
|
checked := ServiceCheck(service, true)
|
||||||
assert.Equal(t, "Bad URL", checked.Name)
|
assert.Equal(t, "Bad URL", checked.Name)
|
||||||
assert.False(t, checked.Online)
|
assert.False(t, checked.Online)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateFailingTCPService(t *testing.T) {
|
func TestCreateFailingTCPService(t *testing.T) {
|
||||||
s := &types.Service{
|
s := &Service{Service: &types.Service{
|
||||||
Name: "Bad TCP",
|
Name: "Bad TCP",
|
||||||
Domain: "localhost",
|
Domain: "localhost",
|
||||||
Port: 5050,
|
Port: 5050,
|
||||||
Interval: 30,
|
Interval: 30,
|
||||||
Type: "tcp",
|
Type: "tcp",
|
||||||
Timeout: 5,
|
Timeout: 5,
|
||||||
}
|
}}
|
||||||
var err error
|
var err error
|
||||||
newServiceId, err = CreateService(s)
|
newServiceId, err = CreateService(s)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotZero(t, newServiceId)
|
assert.NotZero(t, newServiceId)
|
||||||
newService := SelectService(newServiceId).ToService()
|
newService := SelectService(newServiceId)
|
||||||
assert.Equal(t, "Bad TCP", newService.Name)
|
assert.Equal(t, "Bad TCP", newService.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceFailedTCPCheck(t *testing.T) {
|
func TestServiceFailedTCPCheck(t *testing.T) {
|
||||||
service := SelectService(8)
|
service := SelectService(8)
|
||||||
checked := ServiceCheck(service.ToService())
|
checked := ServiceCheck(service, true)
|
||||||
assert.Equal(t, "Bad TCP", checked.Name)
|
assert.Equal(t, "Bad TCP", checked.Name)
|
||||||
assert.False(t, checked.Online)
|
assert.False(t, checked.Online)
|
||||||
}
|
}
|
||||||
|
@ -206,13 +225,13 @@ func TestCreateServiceFailure(t *testing.T) {
|
||||||
}
|
}
|
||||||
service := SelectService(8)
|
service := SelectService(8)
|
||||||
|
|
||||||
id, err := CreateServiceFailure(service.ToService(), fail)
|
id, err := CreateServiceFailure(service, fail)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotZero(t, id)
|
assert.NotZero(t, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteService(t *testing.T) {
|
func TestDeleteService(t *testing.T) {
|
||||||
service := SelectService(newServiceId).ToService()
|
service := SelectService(newServiceId)
|
||||||
|
|
||||||
count, err := SelectAllServices()
|
count, err := SelectAllServices()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
@ -225,3 +244,23 @@ func TestDeleteService(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 7, len(count))
|
assert.Equal(t, 7, len(count))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServiceCloseRoutine(t *testing.T) {
|
||||||
|
s := new(types.Service)
|
||||||
|
s.Name = "example"
|
||||||
|
s.Domain = "https://google.com"
|
||||||
|
s.Type = "http"
|
||||||
|
s.Method = "GET"
|
||||||
|
s.ExpectedStatus = 200
|
||||||
|
s.Interval = 1
|
||||||
|
service := NewService(s)
|
||||||
|
service.Start()
|
||||||
|
assert.True(t, service.IsRunning())
|
||||||
|
go CheckQueue(service, false)
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
assert.True(t, service.IsRunning())
|
||||||
|
service.Close()
|
||||||
|
assert.False(t, service.IsRunning())
|
||||||
|
service.Close()
|
||||||
|
assert.False(t, service.IsRunning())
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ type ErrorResponse struct {
|
||||||
|
|
||||||
func LoadSampleData() error {
|
func LoadSampleData() error {
|
||||||
utils.Log(1, "Inserting Sample Data...")
|
utils.Log(1, "Inserting Sample Data...")
|
||||||
s1 := &types.Service{
|
s1 := &Service{Service: &types.Service{
|
||||||
Name: "Google",
|
Name: "Google",
|
||||||
Domain: "https://google.com",
|
Domain: "https://google.com",
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
|
@ -43,8 +43,8 @@ func LoadSampleData() error {
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timeout: 10,
|
Timeout: 10,
|
||||||
}
|
}}
|
||||||
s2 := &types.Service{
|
s2 := &Service{Service: &types.Service{
|
||||||
Name: "Statup Github",
|
Name: "Statup Github",
|
||||||
Domain: "https://github.com/hunterlong/statup",
|
Domain: "https://github.com/hunterlong/statup",
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
|
@ -52,8 +52,8 @@ func LoadSampleData() error {
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timeout: 20,
|
Timeout: 20,
|
||||||
}
|
}}
|
||||||
s3 := &types.Service{
|
s3 := &Service{Service: &types.Service{
|
||||||
Name: "JSON Users Test",
|
Name: "JSON Users Test",
|
||||||
Domain: "https://jsonplaceholder.typicode.com/users",
|
Domain: "https://jsonplaceholder.typicode.com/users",
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
|
@ -61,8 +61,8 @@ func LoadSampleData() error {
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
Timeout: 30,
|
Timeout: 30,
|
||||||
}
|
}}
|
||||||
s4 := &types.Service{
|
s4 := &Service{Service: &types.Service{
|
||||||
Name: "JSON API Tester",
|
Name: "JSON API Tester",
|
||||||
Domain: "https://jsonplaceholder.typicode.com/posts",
|
Domain: "https://jsonplaceholder.typicode.com/posts",
|
||||||
ExpectedStatus: 201,
|
ExpectedStatus: 201,
|
||||||
|
@ -72,15 +72,15 @@ func LoadSampleData() error {
|
||||||
Method: "POST",
|
Method: "POST",
|
||||||
PostData: `{ "title": "statup", "body": "bar", "userId": 19999 }`,
|
PostData: `{ "title": "statup", "body": "bar", "userId": 19999 }`,
|
||||||
Timeout: 30,
|
Timeout: 30,
|
||||||
}
|
}}
|
||||||
s5 := &types.Service{
|
s5 := &Service{Service: &types.Service{
|
||||||
Name: "Google DNS",
|
Name: "Google DNS",
|
||||||
Domain: "8.8.8.8",
|
Domain: "8.8.8.8",
|
||||||
Interval: 20,
|
Interval: 20,
|
||||||
Type: "tcp",
|
Type: "tcp",
|
||||||
Port: 53,
|
Port: 53,
|
||||||
Timeout: 120,
|
Timeout: 120,
|
||||||
}
|
}}
|
||||||
id, err := CreateService(s1)
|
id, err := CreateService(s1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
|
utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
|
||||||
|
|
|
@ -79,7 +79,7 @@ func ApiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var s *types.Service
|
var s *types.Service
|
||||||
decoder := json.NewDecoder(r.Body)
|
decoder := json.NewDecoder(r.Body)
|
||||||
decoder.Decode(&s)
|
decoder.Decode(&s)
|
||||||
service := serv.ToService()
|
service := serv
|
||||||
core.UpdateService(service)
|
core.UpdateService(service)
|
||||||
json.NewEncoder(w).Encode(s)
|
json.NewEncoder(w).Encode(s)
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,7 @@ func TestServiceChartHandler(t *testing.T) {
|
||||||
Router().ServeHTTP(rr, req)
|
Router().ServeHTTP(rr, req)
|
||||||
body := rr.Body.String()
|
body := rr.Body.String()
|
||||||
assert.Equal(t, 200, rr.Code)
|
assert.Equal(t, 200, rr.Code)
|
||||||
|
t.Log(body)
|
||||||
assert.Contains(t, body, "var ctx_1")
|
assert.Contains(t, body, "var ctx_1")
|
||||||
assert.Contains(t, body, "var ctx_2")
|
assert.Contains(t, body, "var ctx_2")
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services))
|
system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services))
|
||||||
metrics = append(metrics, system)
|
metrics = append(metrics, system)
|
||||||
for _, ser := range core.CoreApp.Services {
|
for _, ser := range core.CoreApp.Services {
|
||||||
v := ser.ToService()
|
v := ser
|
||||||
online := 1
|
online := 1
|
||||||
if !v.Online {
|
if !v.Online {
|
||||||
online = 0
|
online = 0
|
||||||
|
@ -61,6 +61,13 @@ func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte(output))
|
w.Write([]byte(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ResetDbHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
utils.Log(1, fmt.Sprintf("Prometheus /metrics Request From IP: %v\n", r.RemoteAddr))
|
||||||
|
core.DropDatabase()
|
||||||
|
core.CoreApp = nil
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
func isAuthorized(r *http.Request) bool {
|
func isAuthorized(r *http.Request) bool {
|
||||||
var token string
|
var token string
|
||||||
tokens, ok := r.Header["Authorization"]
|
tokens, ok := r.Header["Authorization"]
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/hunterlong/statup/source"
|
"github.com/hunterlong/statup/source"
|
||||||
"github.com/hunterlong/statup/utils"
|
"github.com/hunterlong/statup/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -88,6 +89,9 @@ func Router() *mux.Router {
|
||||||
r.Handle("/api/users", http.HandlerFunc(ApiAllUsersHandler))
|
r.Handle("/api/users", http.HandlerFunc(ApiAllUsersHandler))
|
||||||
r.Handle("/api/users/{id}", http.HandlerFunc(ApiUserHandler))
|
r.Handle("/api/users/{id}", http.HandlerFunc(ApiUserHandler))
|
||||||
r.Handle("/metrics", http.HandlerFunc(PrometheusHandler))
|
r.Handle("/metrics", http.HandlerFunc(PrometheusHandler))
|
||||||
|
if os.Getenv("GO_ENV") == "test" {
|
||||||
|
r.Handle("/reset", http.HandlerFunc(ResetDbHandler))
|
||||||
|
}
|
||||||
r.NotFoundHandler = http.HandlerFunc(Error404Handler)
|
r.NotFoundHandler = http.HandlerFunc(Error404Handler)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,10 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
*types.Service
|
||||||
|
}
|
||||||
|
|
||||||
func RenderServiceChartsHandler(w http.ResponseWriter, r *http.Request) {
|
func RenderServiceChartsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
services := core.CoreApp.Services
|
services := core.CoreApp.Services
|
||||||
w.Header().Set("Content-Type", "text/javascript")
|
w.Header().Set("Content-Type", "text/javascript")
|
||||||
|
@ -57,7 +61,7 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
checkType := r.PostForm.Get("check_type")
|
checkType := r.PostForm.Get("check_type")
|
||||||
postData := r.PostForm.Get("post_data")
|
postData := r.PostForm.Get("post_data")
|
||||||
|
|
||||||
service := &types.Service{
|
service := &core.Service{Service: &types.Service{
|
||||||
Name: name,
|
Name: name,
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
Method: method,
|
Method: method,
|
||||||
|
@ -68,13 +72,13 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Port: port,
|
Port: port,
|
||||||
PostData: postData,
|
PostData: postData,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
}
|
}}
|
||||||
_, err := core.CreateService(service)
|
_, err := core.CreateService(service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(3, fmt.Sprintf("Error starting %v check routine. %v", service.Name, err))
|
utils.Log(3, fmt.Sprintf("Error starting %v check routine. %v", service.Name, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
go core.CheckQueue(service)
|
go core.CheckQueue(service, true)
|
||||||
core.OnNewService(service)
|
core.OnNewService(service)
|
||||||
|
|
||||||
ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
|
ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
|
||||||
|
@ -87,7 +91,11 @@ func ServicesDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
serv := core.SelectService(utils.StringInt(vars["id"]))
|
serv := core.SelectService(utils.StringInt(vars["id"]))
|
||||||
service := serv.ToService()
|
if serv == nil {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
service := serv
|
||||||
core.DeleteService(service)
|
core.DeleteService(service)
|
||||||
ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
|
ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
|
||||||
}
|
}
|
||||||
|
@ -109,7 +117,7 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
serv := core.SelectService(utils.StringInt(vars["id"]))
|
serv := core.SelectService(utils.StringInt(vars["id"]))
|
||||||
service := serv.ToService()
|
service := serv
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
name := r.PostForm.Get("name")
|
name := r.PostForm.Get("name")
|
||||||
domain := r.PostForm.Get("domain")
|
domain := r.PostForm.Get("domain")
|
||||||
|
@ -121,7 +129,7 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
timeout, _ := strconv.Atoi(r.PostForm.Get("timeout"))
|
timeout, _ := strconv.Atoi(r.PostForm.Get("timeout"))
|
||||||
checkType := r.PostForm.Get("check_type")
|
checkType := r.PostForm.Get("check_type")
|
||||||
postData := r.PostForm.Get("post_data")
|
postData := r.PostForm.Get("post_data")
|
||||||
serviceUpdate := &types.Service{
|
serviceUpdate := &core.Service{Service: &types.Service{
|
||||||
Id: service.Id,
|
Id: service.Id,
|
||||||
Name: name,
|
Name: name,
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
|
@ -133,7 +141,7 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Port: port,
|
Port: port,
|
||||||
PostData: postData,
|
PostData: postData,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
}
|
}}
|
||||||
service = core.UpdateService(serviceUpdate)
|
service = core.UpdateService(serviceUpdate)
|
||||||
core.CoreApp.Services, _ = core.SelectAllServices()
|
core.CoreApp.Services, _ = core.SelectAllServices()
|
||||||
|
|
||||||
|
@ -148,7 +156,7 @@ func ServicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
serv := core.SelectService(utils.StringInt(vars["id"]))
|
serv := core.SelectService(utils.StringInt(vars["id"]))
|
||||||
service := serv.ToService()
|
service := serv
|
||||||
core.DeleteFailures(service)
|
core.DeleteFailures(service)
|
||||||
core.CoreApp.Services, _ = core.SelectAllServices()
|
core.CoreApp.Services, _ = core.SelectAllServices()
|
||||||
ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
|
ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
|
||||||
|
@ -162,7 +170,7 @@ func CheckinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
interval := utils.StringInt(r.PostForm.Get("interval"))
|
interval := utils.StringInt(r.PostForm.Get("interval"))
|
||||||
serv := core.SelectService(utils.StringInt(vars["id"]))
|
serv := core.SelectService(utils.StringInt(vars["id"]))
|
||||||
service := serv.ToService()
|
service := serv
|
||||||
checkin := &core.Checkin{
|
checkin := &core.Checkin{
|
||||||
Service: service.Id,
|
Service: service.Id,
|
||||||
Interval: interval,
|
Interval: interval,
|
||||||
|
|
|
@ -1,21 +1,4 @@
|
||||||
/*
|
{{ range . }}{{$s := .}}{{ if .AvgTime }}var ctx_{{$s.Id}}=document.getElementById("service_{{$s.Id}}").getContext('2d');var chartdata=new Chart(ctx_{{$s.Id}},{type:'line',data:{datasets:[{label:'Response Time (Milliseconds)',data:{{safe .GraphData}},backgroundColor:['rgba(47, 206, 30, 0.92)'],borderColor:['rgb(47, 171, 34)'],borderWidth:1}]},options:{maintainAspectRatio:!1,scaleShowValues:!0,layout:{padding:{left:0,right:0,top:0,bottom:-10}},hover:{animationDuration:0,},responsiveAnimationDuration:0,animation:{duration:3500,onComplete:function(){var chartInstance=this.chart,ctx=chartInstance.ctx;var controller=this.chart.controller;var xAxis=controller.scales['x-axis-0'];var yAxis=controller.scales['y-axis-0'];ctx.font=Chart.helpers.fontString(Chart.defaults.global.defaultFontSize,Chart.defaults.global.defaultFontStyle,Chart.defaults.global.defaultFontFamily);ctx.textAlign='center';ctx.textBaseline='bottom';var numTicks=xAxis.ticks.length;var yOffsetStart=xAxis.width/numTicks;var halfBarWidth=(xAxis.width/(numTicks*2));xAxis.ticks.forEach(function(value,index){var xOffset=20;var yOffset=(yOffsetStart*index)+halfBarWidth;ctx.fillStyle='#e2e2e2';ctx.fillText(value,yOffset,xOffset)});this.data.datasets.forEach(function(dataset,i){var meta=chartInstance.controller.getDatasetMeta(i);var hxH=0;var hyH=0;var hxL=0;var hyL=0;var highestNum=0;var lowestnum=999999999999;meta.data.forEach(function(bar,index){var data=dataset.data[index];if(lowestnum>data.y){lowestnum=data.y;hxL=bar._model.x;hyL=bar._model.y}
|
||||||
* Statup
|
|
||||||
* Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
* Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
*
|
|
||||||
* https://github.com/hunterlong/statup
|
|
||||||
*
|
|
||||||
* The licenses for most software and other practical works are designed
|
|
||||||
* to take away your freedom to share and change the works. By contrast,
|
|
||||||
* the GNU General Public License is intended to guarantee your freedom to
|
|
||||||
* share and change all versions of a program--to make sure it remains free
|
|
||||||
* software for all its users.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
{{ range . }}{{$s := .ToService}}{{ if .AvgTime }}var ctx_{{$s.Id}}=document.getElementById("service_{{$s.Id}}").getContext('2d');var chartdata=new Chart(ctx_{{$s.Id}},{type:'line',data:{datasets:[{label:'Response Time (Milliseconds)',data:{{safe .GraphData}},backgroundColor:['rgba(47, 206, 30, 0.92)'],borderColor:['rgb(47, 171, 34)'],borderWidth:1}]},options:{maintainAspectRatio:!1,scaleShowValues:!0,layout:{padding:{left:0,right:0,top:0,bottom:-10}},hover:{animationDuration:0,},responsiveAnimationDuration:0,animation:{duration:3500,onComplete:function(){var chartInstance=this.chart,ctx=chartInstance.ctx;var controller=this.chart.controller;var xAxis=controller.scales['x-axis-0'];var yAxis=controller.scales['y-axis-0'];ctx.font=Chart.helpers.fontString(Chart.defaults.global.defaultFontSize,Chart.defaults.global.defaultFontStyle,Chart.defaults.global.defaultFontFamily);ctx.textAlign='center';ctx.textBaseline='bottom';var numTicks=xAxis.ticks.length;var yOffsetStart=xAxis.width/numTicks;var halfBarWidth=(xAxis.width/(numTicks*2));xAxis.ticks.forEach(function(value,index){var xOffset=20;var yOffset=(yOffsetStart*index)+halfBarWidth;ctx.fillStyle='#e2e2e2';ctx.fillText(value,yOffset,xOffset)});this.data.datasets.forEach(function(dataset,i){var meta=chartInstance.controller.getDatasetMeta(i);var hxH=0;var hyH=0;var hxL=0;var hyL=0;var highestNum=0;var lowestnum=999999999999;meta.data.forEach(function(bar,index){var data=dataset.data[index];if(lowestnum>data.y){lowestnum=data.y;hxL=bar._model.x;hyL=bar._model.y}
|
|
||||||
if(data.y>highestNum){highestNum=data.y;hxH=bar._model.x;hyH=bar._model.y}});if(hxH>=820){hxH=820}else if(50>=hxH){hxH=50}
|
if(data.y>highestNum){highestNum=data.y;hxH=bar._model.x;hyH=bar._model.y}});if(hxH>=820){hxH=820}else if(50>=hxH){hxH=50}
|
||||||
if(hxL>=820){hxL=820}else if(70>=hxL){hxL=70}
|
if(hxL>=820){hxL=820}else if(70>=hxL){hxL=70}
|
||||||
ctx.fillStyle='#ffa7a2';ctx.fillText(highestNum+"ms",hxH-40,hyH+15);ctx.fillStyle='#45d642';ctx.fillText(lowestnum+"ms",hxL,hyL+10);console.log("done service_id_{{$s.Id}}")})}},legend:{display:!1},tooltips:{"enabled":!1},scales:{yAxes:[{display:!1,ticks:{fontSize:20,display:!1,beginAtZero:!1},gridLines:{display:!1}}],xAxes:[{type:'time',distribution:'series',autoSkip:!1,gridLines:{display:!1},ticks:{stepSize:1,min:0,fontColor:"white",fontSize:20,display:!1,}}]},elements:{point:{radius:0}}}})
|
ctx.fillStyle='#ffa7a2';ctx.fillText(highestNum+"ms",hxH-40,hyH+15);ctx.fillStyle='#45d642';ctx.fillText(lowestnum+"ms",hxL,hyL+10);console.log("done service_id_{{$s.Id}}")})}},legend:{display:!1},tooltips:{"enabled":!1},scales:{yAxes:[{display:!1,ticks:{fontSize:20,display:!1,beginAtZero:!1},gridLines:{display:!1}}],xAxes:[{type:'time',distribution:'series',autoSkip:!1,gridLines:{display:!1},ticks:{stepSize:1,min:0,fontColor:"white",fontSize:20,display:!1,}}]},elements:{point:{radius:0}}}})
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
|
|
||||||
<div class="list-group mb-5 mt-3">
|
<div class="list-group mb-5 mt-3">
|
||||||
{{ range .Services }}
|
{{ range .Services }}
|
||||||
{{ $s := .ToService }}
|
{{ $s := . }}
|
||||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||||
<div class="d-flex w-100 justify-content-between">
|
<div class="d-flex w-100 justify-content-between">
|
||||||
<h5 class="mb-1">{{$s.Name}}</h5>
|
<h5 class="mb-1">{{$s.Name}}</h5>
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ range .Services }}
|
{{ range .Services }}
|
||||||
{{ $s := .ToService }}
|
{{ $s := . }}
|
||||||
{{ if .LimitedFailures }}
|
{{ if .LimitedFailures }}
|
||||||
<h4>{{$s.Name}} Failures</h4>
|
<h4>{{$s.Name}} Failures</h4>
|
||||||
<div class="list-group mt-3 mb-4">
|
<div class="list-group mt-3 mb-4">
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<div class="col-12 full-col-12 mb-5">
|
<div class="col-12 full-col-12 mb-5">
|
||||||
<div class="list-group online_list">
|
<div class="list-group online_list">
|
||||||
{{ range .Services }}
|
{{ range .Services }}
|
||||||
{{ $s := .ToService }}
|
{{ $s := . }}
|
||||||
|
|
||||||
<a href="#" class="service_li list-group-item list-group-item-action {{if not $s.Online}}bg-danger text-white{{ end }}" data-id="{{$s.Id}}">
|
<a href="#" class="service_li list-group-item list-group-item-action {{if not $s.Online}}bg-danger text-white{{ end }}" data-id="{{$s.Id}}">
|
||||||
{{ $s.Name }}
|
{{ $s.Name }}
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{ range .Services }}
|
{{ range .Services }}
|
||||||
{{ $s := .ToService }}
|
{{ $s := . }}
|
||||||
<div class="mt-4" id="service_id_{{$s.Id}}">
|
<div class="mt-4" id="service_id_{{$s.Id}}">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{{ $s := .ToService }}<!doctype html>
|
{{ $s := . }}<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{range .}}
|
{{range .}}
|
||||||
{{ $s := .ToService }}
|
{{ $s := . }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{$s.Name}}</td>
|
<td>{{$s.Name}}</td>
|
||||||
<td>{{if $s.Online}}<span class="badge badge-success">ONLINE</span>{{else}}<span class="badge badge-danger">OFFLINE</span>{{end}} </td>
|
<td>{{if $s.Online}}<span class="badge badge-success">ONLINE</span>{{else}}<span class="badge badge-danger">OFFLINE</span>{{end}} </td>
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Id int64 `db:"id,omitempty" json:"id"`
|
Id int64 `db:"id,omitempty" json:"id"`
|
||||||
|
@ -39,7 +41,7 @@ type Service struct {
|
||||||
OrderId int64 `json:"order_id"`
|
OrderId int64 `json:"order_id"`
|
||||||
Failures []*Failure `json:"failures"`
|
Failures []*Failure `json:"failures"`
|
||||||
Checkins []*Checkin `json:"checkins"`
|
Checkins []*Checkin `json:"checkins"`
|
||||||
StopRoutine chan bool `json:"-"`
|
Running chan bool `json:"-"`
|
||||||
LastResponse string
|
LastResponse string
|
||||||
LastStatusCode int
|
LastStatusCode int
|
||||||
LastOnline time.Time
|
LastOnline time.Time
|
||||||
|
@ -47,9 +49,26 @@ type Service struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Start() {
|
func (s *Service) Start() {
|
||||||
s.StopRoutine = make(chan bool)
|
if s.Running == nil {
|
||||||
|
s.Running = make(chan bool)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Close() {
|
func (s *Service) Close() {
|
||||||
s.StopRoutine <- true
|
if s.IsRunning() {
|
||||||
|
close(s.Running)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) IsRunning() bool {
|
||||||
|
if s.Running == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-s.Running:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue