pull/78/head v0.72
Hunter Long 2018-10-04 01:18:55 -07:00
parent fc1fe03f89
commit 9a6c91a997
12 changed files with 157 additions and 96 deletions

View File

@ -49,26 +49,41 @@ func SelectCheckin(api string) *Checkin {
return &checkin
}
func FindCheckin(api string) *types.Checkin {
for _, ser := range CoreApp.Services {
service := ser.Select()
for _, c := range service.Checkins {
if c.ApiKey == api {
return c
}
}
}
return nil
func (u Checkin) Period() time.Duration {
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.Interval))
return duration
}
func (u Checkin) Grace() time.Duration {
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.GracePeriod))
return duration
}
func (u Checkin) Expected() time.Duration {
last := u.Last().CreatedAt
now := time.Now()
lastDir := now.Sub(last)
sub := time.Duration(u.Period() - lastDir)
return sub
}
func (u Checkin) Last() CheckinHit {
var hit CheckinHit
checkinHitsDB().Where("checkin = ?", u.Id).Last(&hit)
return hit
}
func (u *Checkin) Hits() []CheckinHit {
var checkins []CheckinHit
checkinDB().Where("checkin = ?", u.Id).Order("id DESC").Find(&checkins)
checkinHitsDB().Where("checkin = ?", u.Id).Order("id DESC").Find(&checkins)
return checkins
}
func (u *Checkin) Create() (int64, error) {
u.CreatedAt = time.Now()
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now()
}
u.ApiKey = utils.NewSHA1Hash(7)
row := checkinDB().Create(u)
if row.Error == nil {
utils.Log(2, row.Error)
@ -78,7 +93,9 @@ func (u *Checkin) Create() (int64, error) {
}
func (u *CheckinHit) Create() (int64, error) {
u.CreatedAt = time.Now()
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now()
}
row := checkinHitsDB().Create(u)
if row.Error == nil {
utils.Log(2, row.Error)

View File

@ -108,6 +108,16 @@ func (u *User) AfterFind() (err error) {
return
}
func (s *Checkin) AfterFind() (err error) {
s.CreatedAt = utils.Timezoner(s.CreatedAt, CoreApp.Timezone)
return
}
func (s *CheckinHit) AfterFind() (err error) {
s.CreatedAt = utils.Timezoner(s.CreatedAt, CoreApp.Timezone)
return
}
func (u *Hit) BeforeCreate() (err error) {
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now().UTC()
@ -130,6 +140,16 @@ func (u *Service) BeforeCreate() (err error) {
return
}
func (u *Checkin) BeforeCreate() (err error) {
u.CreatedAt = time.Now().UTC()
return
}
func (u *CheckinHit) BeforeCreate() (err error) {
u.CreatedAt = time.Now().UTC()
return
}
// InsertCore create the single row for the Core settings in Statup
func (db *DbConfig) InsertCore() (*Core, error) {
CoreApp = &Core{Core: &types.Core{

View File

@ -84,6 +84,31 @@ func InsertSampleData() error {
s4.Create(false)
s5.Create(false)
checkin1 := ReturnCheckin(&types.Checkin{
Service: s1.Id,
Interval: 300,
GracePeriod: 300,
})
checkin1.Create()
checkin2 := ReturnCheckin(&types.Checkin{
Service: s2.Id,
Interval: 900,
GracePeriod: 300,
})
checkin2.Create()
checkTime := time.Now().Add(-24 * time.Hour)
for i := 0; i <= 60; i++ {
checkHit := ReturnCheckinHit(&types.CheckinHit{
Checkin: checkin1.Id,
From: "192.168.0.1",
CreatedAt: checkTime.UTC(),
})
checkHit.Create()
checkTime = checkTime.Add(10 * time.Minute)
}
utils.Log(1, "Sample data has finished importing")
return nil
@ -114,39 +139,6 @@ func InsertSampleHits() error {
return nil
}
func sampleGraphData(i float64, upward *bool) float64 {
alpha := 0.0003
if *upward {
i += 0.3
if i >= 6500 {
i += 0.1
*upward = false
} else if i >= 4500 {
i += 3
} else if i >= 2300 {
i += 1
} else if i >= 1150 {
i += 2
} else if i >= 500 {
i += 1
}
} else {
i -= 0.3
if i <= 6500 {
i -= 0.1
} else if i <= 4500 {
i -= 3
} else if i <= 2300 {
i -= 1
} else if i <= 1150 {
i -= 2
} else if i <= 500 {
i -= 1
}
}
return i * alpha
}
func insertSampleCore() error {
core := &types.Core{
Name: "Statup Sample Data",

View File

@ -49,9 +49,9 @@ func SelectService(id int64) *Service {
return nil
}
func (s *Service) Checkins() []*Checkin {
var hits []*Checkin
servicesDB().Where("service = ?", s.Id).Find(&hits)
func (s *Service) Checkin() Checkin {
var hits Checkin
servicesDB().Where("service = ?", s.Id).First(&hits)
return hits
}
@ -66,7 +66,7 @@ func (c *Core) SelectAllServices() ([]*Service, error) {
CoreApp.Services = nil
for _, service := range services {
service.Start()
service.Checkins()
service.Checkin()
service.AllFailures()
CoreApp.Services = append(CoreApp.Services, service)
}

View File

@ -72,7 +72,7 @@ func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
return
}
vars := mux.Vars(r)
checkin := core.FindCheckin(vars["api"])
checkin := core.SelectCheckin(vars["api"])
//checkin.Receivehit()
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(checkin)

View File

@ -137,6 +137,25 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap
"ToString": func(v interface{}) string {
return utils.ToString(v)
},
"Ago": func(t time.Time) string {
return utils.Timestamp(t).Ago()
},
"Duration": func(t time.Duration) string {
var out string
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", t.Seconds()))
if duration.Minutes() < 1 {
out = fmt.Sprintf("%0.0f second", duration.Seconds())
if duration.Seconds() >= 2 {
out += "s"
}
} else {
out = fmt.Sprintf("%0.0f minute", duration.Minutes())
if duration.Minutes() >= 2 {
out += "s"
}
}
return out
},
"ToUnix": func(t time.Time) int64 {
return t.UTC().Unix()
},

View File

@ -53,6 +53,31 @@ func Router() *mux.Router {
r.Handle("/dashboard", http.HandlerFunc(dashboardHandler)).Methods("GET")
r.Handle("/dashboard", http.HandlerFunc(loginHandler)).Methods("POST")
r.Handle("/logout", http.HandlerFunc(logoutHandler))
r.Handle("/checkin/{id}", http.HandlerFunc(checkinUpdateHandler))
r.Handle("/plugins/download/{name}", http.HandlerFunc(pluginsDownloadHandler))
r.Handle("/plugins/{name}/save", http.HandlerFunc(pluginSavedHandler)).Methods("POST")
r.Handle("/help", http.HandlerFunc(helpHandler))
r.Handle("/logs", http.HandlerFunc(logsHandler))
r.Handle("/logs/line", http.HandlerFunc(logsLineHandler))
// USER Routes
r.Handle("/users", http.HandlerFunc(usersHandler)).Methods("GET")
r.Handle("/users", http.HandlerFunc(createUserHandler)).Methods("POST")
r.Handle("/user/{id}", http.HandlerFunc(usersEditHandler)).Methods("GET")
r.Handle("/user/{id}", http.HandlerFunc(updateUserHandler)).Methods("POST")
r.Handle("/user/{id}/delete", http.HandlerFunc(usersDeleteHandler)).Methods("GET")
// SETTINGS Routes
r.Handle("/settings", http.HandlerFunc(settingsHandler)).Methods("GET")
r.Handle("/settings", http.HandlerFunc(saveSettingsHandler)).Methods("POST")
r.Handle("/settings/css", http.HandlerFunc(saveSASSHandler)).Methods("POST")
r.Handle("/settings/build", http.HandlerFunc(saveAssetsHandler)).Methods("GET")
r.Handle("/settings/delete_assets", http.HandlerFunc(deleteAssetsHandler)).Methods("GET")
r.Handle("/settings/notifier/{method}", http.HandlerFunc(saveNotificationHandler)).Methods("POST")
r.Handle("/settings/notifier/{method}/test", http.HandlerFunc(testNotificationHandler)).Methods("POST")
r.Handle("/settings/export", http.HandlerFunc(exportHandler)).Methods("GET")
// SERVICE Routes
r.Handle("/services", http.HandlerFunc(servicesHandler)).Methods("GET")
r.Handle("/services", http.HandlerFunc(createServiceHandler)).Methods("POST")
r.Handle("/services/reorder", http.HandlerFunc(reorderServiceHandler)).Methods("POST")
@ -62,27 +87,8 @@ func Router() *mux.Router {
r.Handle("/service/{id}/delete", http.HandlerFunc(servicesDeleteHandler))
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(servicesDeleteFailuresHandler)).Methods("GET")
r.Handle("/service/{id}/checkin", http.HandlerFunc(checkinCreateUpdateHandler)).Methods("POST")
r.Handle("/checkin/{id}", http.HandlerFunc(checkinUpdateHandler))
r.Handle("/users", http.HandlerFunc(usersHandler)).Methods("GET")
r.Handle("/users", http.HandlerFunc(createUserHandler)).Methods("POST")
r.Handle("/user/{id}", http.HandlerFunc(usersEditHandler)).Methods("GET")
r.Handle("/user/{id}", http.HandlerFunc(updateUserHandler)).Methods("POST")
r.Handle("/user/{id}/delete", http.HandlerFunc(usersDeleteHandler)).Methods("GET")
r.Handle("/settings", http.HandlerFunc(settingsHandler)).Methods("GET")
r.Handle("/settings", http.HandlerFunc(saveSettingsHandler)).Methods("POST")
r.Handle("/settings/css", http.HandlerFunc(saveSASSHandler)).Methods("POST")
r.Handle("/settings/build", http.HandlerFunc(saveAssetsHandler)).Methods("GET")
r.Handle("/settings/delete_assets", http.HandlerFunc(deleteAssetsHandler)).Methods("GET")
r.Handle("/settings/notifier/{method}", http.HandlerFunc(saveNotificationHandler)).Methods("POST")
r.Handle("/settings/notifier/{method}/test", http.HandlerFunc(testNotificationHandler)).Methods("POST")
r.Handle("/settings/export", http.HandlerFunc(exportHandler)).Methods("GET")
r.Handle("/plugins/download/{name}", http.HandlerFunc(pluginsDownloadHandler))
r.Handle("/plugins/{name}/save", http.HandlerFunc(pluginSavedHandler)).Methods("POST")
r.Handle("/help", http.HandlerFunc(helpHandler))
r.Handle("/logs", http.HandlerFunc(logsHandler))
r.Handle("/logs/line", http.HandlerFunc(logsLineHandler))
// SERVICE API Routes
// API SERVICE Routes
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
r.Handle("/api/services", http.HandlerFunc(apiCreateServiceHandler)).Methods("POST")
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceHandler)).Methods("GET")
@ -91,7 +97,7 @@ func Router() *mux.Router {
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceUpdateHandler)).Methods("POST")
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceDeleteHandler)).Methods("DELETE")
// USER API Routes
// API USER Routes
r.Handle("/api/users", http.HandlerFunc(apiAllUsersHandler)).Methods("GET")
r.Handle("/api/users", http.HandlerFunc(apiCreateUsersHandler)).Methods("POST")
r.Handle("/api/users/{id}", http.HandlerFunc(apiUserHandler)).Methods("GET")
@ -103,8 +109,8 @@ func Router() *mux.Router {
r.Handle("/api/renew", http.HandlerFunc(apiRenewHandler))
r.Handle("/api/checkin/{api}", http.HandlerFunc(apiCheckinHandler))
r.Handle("/metrics", http.HandlerFunc(prometheusHandler))
r.NotFoundHandler = http.HandlerFunc(error404Handler)
r.Handle("/tray", http.HandlerFunc(trayHandler))
r.NotFoundHandler = http.HandlerFunc(error404Handler)
return r
}

View File

@ -268,7 +268,6 @@ func checkinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
Service: service.Id,
Interval: interval,
GracePeriod: grace,
ApiKey: utils.NewSHA1Hash(18),
})
checkin.Create()
executeResponse(w, r, "service.html", service, fmt.Sprintf("/service/%v", service.Id))

View File

@ -52,7 +52,7 @@
<input type="number" name="expected_status" class="form-control" value="{{if ne .ExpectedStatus 0}}{{.ExpectedStatus}}{{end}}" placeholder="200" id="service_response_code">
</div>
</div>
<div class="form-group row{{if eq .Type "http"}} d-none{{end}}">
<div class="form-group row{{if eq .Type ""}} d-none{{else if eq .Type "http"}} d-none{{end}}">
<label for="service_port" class="col-sm-4 col-form-label">TCP Port</label>
<div class="col-sm-8">
<input type="number" name="port" class="form-control" value="{{if ne .Port 0}}{{.Port}}{{end}}" id="service_port" placeholder="8080">

View File

@ -96,18 +96,27 @@
</div>
</div>
<div class="col-12 mt-4{{if eq $s.Type "tcp"}} d-none{{end}}">
<h3>Service Checkins</h3>
{{ range $s.Checkins }}
<h5>Check #{{.Id}} <span class="badge online_badge float-right">Checked in</span></h5>
<input type="text" class="form-control" value="{{CoreApp.Domain}}/checkin/{{.ApiKey}}">
<ul class="list-group">
{{ range .Hits }}
<li class="list-group-item">Received Checkin at {{.CreatedAt}}</li>
{{end}}
</ul>
{{ end }}
<div class="col-12 mt-4">
<h3>Service Checkin</h3>
<table class="table">
<thead>
<tr>
<th scope="col">Checkin</th>
<th scope="col">Report Period<br>Grace Period</th>
<th scope="col">Last Seen</th>
<th scope="col">Expected</th>
</tr>
</thead>
<tbody>
{{$ch := $s.Checkin}}
<tr>
<td>{{CoreApp.Domain}}/checkin/{{$ch.ApiKey}}</td>
<td>every {{Duration $ch.Period}}<br>{{Duration $ch.Grace}} grace period</td>
<td>{{Ago $ch.Last.CreatedAt}}</td>
<td>{{ if lt $ch.Expected 0}}{{Duration $ch.Expected}} ago{{else}}in {{Duration $ch.Expected}}{{end}}</td>
</tr>
</tbody>
</table>
{{template "form_checkin" $s}}
</div>

View File

@ -20,14 +20,13 @@ import (
)
type Checkin struct {
Id int64 `gorm:"primary_key;column:id"`
Service int64 `gorm:"index;column:service"`
Interval int64 `gorm:"column:check_interval"`
GracePeriod int64 `gorm:"column:grace_period"`
ApiKey string `gorm:"column:api_key"`
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
Hits []CheckinHit `json:"hits"`
Id int64 `gorm:"primary_key;column:id"`
Service int64 `gorm:"index;column:service"`
Interval int64 `gorm:"column:check_interval"`
GracePeriod int64 `gorm:"column:grace_period"`
ApiKey string `gorm:"column:api_key"`
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
}
type CheckinHit struct {

View File

@ -46,7 +46,7 @@ type Service struct {
LastStatusCode int `gorm:"-" json:"status_code"`
LastOnline time.Time `gorm:"-" json:"last_online"`
Failures []interface{} `gorm:"-" json:"failures,omitempty"`
Checkins []*Checkin `gorm:"-" json:"checkins,omitempty"`
//Checkins []*Checkin `gorm:"-" json:"checkins,omitempty"`
}
type ServiceInterface interface {