From b232d5b1ff8cb3aba56a8dc534918cbc0087bf66 Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Thu, 8 Nov 2018 02:50:06 -0800 Subject: [PATCH] cache updates - api updates --- core/checker.go | 6 ++-- core/failures.go | 14 +++++--- core/notifier/notifiers.go | 4 +-- core/sample.go | 4 +-- core/services.go | 10 ++++-- core/services_test.go | 4 +-- handlers/api.go | 74 ++++++++++++++++++++++++++------------ handlers/cache.go | 6 ++++ handlers/routes.go | 1 + handlers/services.go | 1 - source/tmpl/dashboard.html | 5 +-- source/tmpl/index.html | 11 ------ source/tmpl/service.html | 5 +-- types/failure.go | 16 ++++----- types/service.go | 54 ++++++++++++++-------------- 15 files changed, 126 insertions(+), 89 deletions(-) diff --git a/core/checker.go b/core/checker.go index 60795fb9..6b8ccbe9 100644 --- a/core/checker.go +++ b/core/checker.go @@ -246,13 +246,13 @@ func recordSuccess(s *Service) { // recordFailure will create a new 'failure' record in the database for a offline service func recordFailure(s *Service, issue string) { s.Online = false - fail := &types.Failure{ + fail := &failure{&types.Failure{ Service: s.Id, Issue: issue, PingTime: s.PingTime, CreatedAt: time.Now(), - } + }} utils.Log(2, fmt.Sprintf("Service %v Failing: %v | Lookup in: %0.2f ms", s.Name, issue, fail.PingTime*1000)) s.CreateFailure(fail) - notifier.OnFailure(s.Service, fail) + notifier.OnFailure(s.Service, fail.Failure) } diff --git a/core/failures.go b/core/failures.go index bb61241e..dc499857 100644 --- a/core/failures.go +++ b/core/failures.go @@ -29,7 +29,8 @@ type failure struct { } // CreateFailure will create a new failure record for a service -func (s *Service) CreateFailure(f *types.Failure) (int64, error) { +func (s *Service) CreateFailure(fail types.FailureInterface) (int64, error) { + f := fail.(*failure) f.Service = s.Id s.Failures = append(s.Failures, f) row := failuresDB().Create(f) @@ -64,10 +65,10 @@ func (s *Service) DeleteFailures() { s.Failures = nil } -// LimitedFailures will return the last 10 failures from a service -func (s *Service) LimitedFailures() []*failure { +// LimitedFailures will return the last amount of failures from a service +func (s *Service) LimitedFailures(amount int64) []*failure { var failArr []*failure - col := failuresDB().Where("service = ?", s.Id).Order("id desc").Limit(10) + col := failuresDB().Where("service = ?", s.Id).Order("id asc").Limit(amount) col.Find(&failArr) return failArr } @@ -78,6 +79,11 @@ func (f *failure) Ago() string { return got } +// Select returns a *types.Failure +func (f *failure) Select() *types.Failure { + return f.Failure +} + // Delete will remove a failure record from the database func (f *failure) Delete() error { db := failuresDB().Delete(f) diff --git a/core/notifier/notifiers.go b/core/notifier/notifiers.go index c6206f56..a57b3d76 100644 --- a/core/notifier/notifiers.go +++ b/core/notifier/notifiers.go @@ -58,8 +58,8 @@ type Notification struct { Author string `gorm:"-" json:"author"` AuthorUrl string `gorm:"-" json:"author_url"` Icon string `gorm:"-" json:"icon"` - Delay time.Duration `gorm:"-" json:"delay"` - Queue []*QueueData `gorm:"-" json:"queue"` + Delay time.Duration `gorm:"-" json:"delay,string"` + Queue []*QueueData `gorm:"-" json:"-"` Running chan bool `gorm:"-" json:"-"` Online bool `gorm:"-" json:"online"` testable bool `gorm:"-" json:"testable"` diff --git a/core/sample.go b/core/sample.go index e8fbc05f..110ce031 100644 --- a/core/sample.go +++ b/core/sample.go @@ -350,11 +350,11 @@ func insertFailureRecords(since time.Time, amount int64) { for fi := int64(1); fi <= amount; fi++ { createdAt = createdAt.Add(2 * time.Minute) - failure := &types.Failure{ + failure := &failure{&types.Failure{ Service: service.Id, Issue: "testing right here", CreatedAt: createdAt, - } + }} service.CreateFailure(failure) } diff --git a/core/services.go b/core/services.go index ee461db6..f5968168 100644 --- a/core/services.go +++ b/core/services.go @@ -92,7 +92,11 @@ func (c *Core) SelectAllServices(start bool) ([]*Service, error) { service.Start() service.CheckinProcess() } - service.AllFailures() + failures := service.LimitedFailures(100) + service.Failures = nil + for _, fail := range failures { + service.Failures = append(service.Failures, fail) + } CoreApp.Services = append(CoreApp.Services, service) } sort.Sort(ServiceOrder(CoreApp.Services)) @@ -164,7 +168,7 @@ type DateScanObj struct { // lastFailure returns the last failure a service had func (s *Service) lastFailure() *failure { - limited := s.LimitedFailures() + limited := s.LimitedFailures(1) if len(limited) == 0 { return nil } @@ -176,7 +180,7 @@ func (s *Service) lastFailure() *failure { // service.SmallText() // // Online since Monday 3:04:05PM, Jan _2 2006 func (s *Service) SmallText() string { - last := s.LimitedFailures() + last := s.LimitedFailures(1) hits, _ := s.LimitedHits() zone := CoreApp.Timezone if s.Online { diff --git a/core/services_test.go b/core/services_test.go index 814be66c..809a3a8c 100644 --- a/core/services_test.go +++ b/core/services_test.go @@ -256,10 +256,10 @@ func TestServiceFailedTCPCheck(t *testing.T) { } func TestCreateServiceFailure(t *testing.T) { - fail := &types.Failure{ + fail := &failure{&types.Failure{ Issue: "This is not an issue, but it would container HTTP response errors.", Method: "http", - } + }} service := SelectService(8) id, err := service.CreateFailure(fail) assert.Nil(t, err) diff --git a/handlers/api.go b/handlers/api.go index ada8d287..310c4f2a 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -37,7 +37,7 @@ type apiResponse struct { func apiIndexHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } var out core.Core @@ -55,7 +55,7 @@ func apiIndexHandler(w http.ResponseWriter, r *http.Request) { func apiRenewHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } var err error @@ -70,7 +70,7 @@ func apiRenewHandler(w http.ResponseWriter, r *http.Request) { func apiCheckinHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -121,7 +121,7 @@ func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) { func apiServiceHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -137,7 +137,7 @@ func apiServiceHandler(w http.ResponseWriter, r *http.Request) { func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } var service *types.Service @@ -159,7 +159,7 @@ func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) { func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -185,7 +185,7 @@ func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -211,14 +211,13 @@ func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) { func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } allServices := core.CoreApp.Services var services []types.ServiceInterface for _, s := range allServices { service := s.Select() - service.Failures = nil services = append(services, core.ReturnService(service)) } w.Header().Set("Content-Type", "application/json") @@ -227,7 +226,7 @@ func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) { func apiUserHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -242,7 +241,7 @@ func apiUserHandler(w http.ResponseWriter, r *http.Request) { func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -267,7 +266,7 @@ func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiUserDeleteHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -293,7 +292,7 @@ func apiUserDeleteHandler(w http.ResponseWriter, r *http.Request) { func apiAllUsersHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } users, err := core.SelectAllUsers() @@ -306,7 +305,7 @@ func apiAllUsersHandler(w http.ResponseWriter, r *http.Request) { func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } var user *types.User @@ -334,7 +333,7 @@ func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) { func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -349,7 +348,7 @@ func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) { func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -386,7 +385,7 @@ func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) { func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } messages, err := core.SelectMessages() @@ -400,7 +399,7 @@ func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) { func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -415,7 +414,7 @@ func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) { func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -443,7 +442,7 @@ func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) { func apiMessageUpdateHandler(w http.ResponseWriter, r *http.Request) { if !isAPIAuthorized(r) { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + sendUnauthorizedJson(w, r) return } vars := mux.Vars(r) @@ -480,8 +479,8 @@ func apiMessageUpdateHandler(w http.ResponseWriter, r *http.Request) { } func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) { - if !IsAuthenticated(r) { - http.Redirect(w, r, "/", http.StatusSeeOther) + if !isAPIAuthorized(r) { + sendUnauthorizedJson(w, r) return } var notifiers []*notifier.Notification @@ -493,6 +492,37 @@ func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(notifiers) } +func apiAllServiceFailuresHandler(w http.ResponseWriter, r *http.Request) { + if !isAPIAuthorized(r) { + sendUnauthorizedJson(w, r) + return + } + allServices, _ := core.CoreApp.SelectAllServices(false) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(allServices) +} + +func apiServiceFailuresHandler(w http.ResponseWriter, r *http.Request) { + if !isAPIAuthorized(r) { + sendUnauthorizedJson(w, r) + return + } + vars := mux.Vars(r) + service := core.SelectService(utils.StringInt(vars["id"])) + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(service.AllFailures()) +} + +func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) { + data := map[string]interface{}{ + "error": "unauthorized", + "url": r.RequestURI, + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + json.NewEncoder(w).Encode(data) +} + func isAPIAuthorized(r *http.Request) bool { if os.Getenv("GO_ENV") == "test" { return true diff --git a/handlers/cache.go b/handlers/cache.go index 6e318c3e..d6d900fc 100644 --- a/handlers/cache.go +++ b/handlers/cache.go @@ -87,6 +87,12 @@ func cached(duration, contentType string, handler func(w http.ResponseWriter, r c := httptest.NewRecorder() handler(c, r) content := c.Body.Bytes() + result := c.Result() + if result.StatusCode != 200 { + w.WriteHeader(result.StatusCode) + w.Write(content) + return + } if d, err := time.ParseDuration(duration); err == nil { CacheStorage.Set(r.RequestURI, content, d) } diff --git a/handlers/routes.go b/handlers/routes.go index 46e5789d..5492857b 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -112,6 +112,7 @@ func Router() *mux.Router { r.Handle("/api/services/{id}/ping", http.HandlerFunc(apiServicePingDataHandler)).Methods("GET") r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceUpdateHandler)).Methods("POST") r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceDeleteHandler)).Methods("DELETE") + r.Handle("/api/service/{id}/failures", http.HandlerFunc(apiServiceFailuresHandler)).Methods("GET") r.Handle("/api/checkin/{api}", http.HandlerFunc(apiCheckinHandler)) // API USER Routes diff --git a/handlers/services.go b/handlers/services.go index 1fdc99a4..59094fba 100644 --- a/handlers/services.go +++ b/handlers/services.go @@ -33,7 +33,6 @@ func renderServiceChartsHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/javascript") w.Header().Set("Cache-Control", "max-age=60") - //var data []string end := time.Now().UTC() start := time.Now().Add((-24 * 7) * time.Hour).UTC() var srvs []*core.Service diff --git a/source/tmpl/dashboard.html b/source/tmpl/dashboard.html index faa882f3..c7a7e9bf 100644 --- a/source/tmpl/dashboard.html +++ b/source/tmpl/dashboard.html @@ -33,10 +33,11 @@ {{ range Services }} - {{ if .LimitedFailures }} + {{$failures := .LimitedFailures 16}} + {{ if $failures }}

{{.Name}} Failures

- {{ range .LimitedFailures }} + {{ range $failures }}
{{.ParseError}}
diff --git a/source/tmpl/index.html b/source/tmpl/index.html index cd367180..c0584915 100644 --- a/source/tmpl/index.html +++ b/source/tmpl/index.html @@ -75,17 +75,6 @@
- {{if .ActiveMessages}} -
- {{range .ActiveMessages}} - - {{end}} -
- {{end}} - {{ end }} diff --git a/source/tmpl/service.html b/source/tmpl/service.html index b3cb1212..668e0455 100644 --- a/source/tmpl/service.html +++ b/source/tmpl/service.html @@ -70,9 +70,10 @@
{{$s.DowntimeText}}
{{end}} - {{ if $s.LimitedFailures }} + {{$failures := $s.LimitedFailures 16}} + {{ if $failures }}
- {{ range $s.LimitedFailures }} + {{ range $failures }}
{{.ParseError}}
diff --git a/types/failure.go b/types/failure.go index c1a34060..0cc3b374 100644 --- a/types/failure.go +++ b/types/failure.go @@ -22,17 +22,17 @@ import ( // Failure is a failed attempt to check a service. Any a service does not meet the expected requirements, // a new Failure will be inserted into database. type Failure struct { - Id int64 `gorm:"primary_key;column:id" json:"id"` - Issue string `gorm:"column:issue" json:"issue"` - Method string `gorm:"column:method" json:"method,omitempty"` - MethodId int64 `gorm:"column:method_id" json:"method_id,omitempty"` - Service int64 `gorm:"index;column:service" json:"-"` - PingTime float64 `gorm:"column:ping_time"` - CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` - FailureInterface `gorm:"-" json:"-"` + Id int64 `gorm:"primary_key;column:id" json:"id"` + Issue string `gorm:"column:issue" json:"issue"` + Method string `gorm:"column:method" json:"method,omitempty"` + MethodId int64 `gorm:"column:method_id" json:"method_id,omitempty"` + Service int64 `gorm:"index;column:service" json:"-"` + PingTime float64 `gorm:"column:ping_time" json:"ping"` + CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` } type FailureInterface interface { + Select() *Failure Ago() string // Ago returns a human readable timestamp ParseError() string // ParseError returns a human readable error for a service failure } diff --git a/types/service.go b/types/service.go index d6e51b14..9eac994f 100644 --- a/types/service.go +++ b/types/service.go @@ -21,33 +21,33 @@ import ( // Service is the main struct for Services type Service struct { - Id int64 `gorm:"primary_key;column:id" json:"id"` - Name string `gorm:"column:name" json:"name"` - Domain string `gorm:"column:domain" json:"domain"` - Expected NullString `gorm:"column:expected" json:"expected"` - ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"` - Interval int `gorm:"default:30;column:check_interval" json:"check_interval"` - Type string `gorm:"column:check_type" json:"type"` - Method string `gorm:"column:method" json:"method"` - PostData NullString `gorm:"column:post_data" json:"post_data"` - Port int `gorm:"not null;column:port" json:"port"` - Timeout int `gorm:"default:30;column:timeout" json:"timeout"` - Order int `gorm:"default:0;column:order_id" json:"order_id"` - AllowNotifications NullBool `gorm:"default:false;column:allow_notifications" json:"allow_notifications"` - CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` - UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` - Online bool `gorm:"-" json:"online"` - Latency float64 `gorm:"-" json:"latency"` - PingTime float64 `gorm:"-" json:"ping_time"` - Online24Hours float32 `gorm:"-" json:"online_24_hours"` - AvgResponse string `gorm:"-" json:"avg_response"` - Running chan bool `gorm:"-" json:"-"` - Checkpoint time.Time `gorm:"-" json:"-"` - SleepDuration time.Duration `gorm:"-" json:"-"` - LastResponse string `gorm:"-" json:"-"` - LastStatusCode int `gorm:"-" json:"status_code"` - LastOnline time.Time `gorm:"-" json:"last_online"` - Failures []interface{} `gorm:"-" json:"failures,omitempty"` + Id int64 `gorm:"primary_key;column:id" json:"id"` + Name string `gorm:"column:name" json:"name"` + Domain string `gorm:"column:domain" json:"domain"` + Expected NullString `gorm:"column:expected" json:"expected"` + ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"` + Interval int `gorm:"default:30;column:check_interval" json:"check_interval"` + Type string `gorm:"column:check_type" json:"type"` + Method string `gorm:"column:method" json:"method"` + PostData NullString `gorm:"column:post_data" json:"post_data"` + Port int `gorm:"not null;column:port" json:"port"` + Timeout int `gorm:"default:30;column:timeout" json:"timeout"` + Order int `gorm:"default:0;column:order_id" json:"order_id"` + AllowNotifications NullBool `gorm:"default:false;column:allow_notifications" json:"allow_notifications"` + CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` + UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` + Online bool `gorm:"-" json:"online"` + Latency float64 `gorm:"-" json:"latency"` + PingTime float64 `gorm:"-" json:"ping_time"` + Online24Hours float32 `gorm:"-" json:"online_24_hours"` + AvgResponse string `gorm:"-" json:"avg_response"` + Running chan bool `gorm:"-" json:"-"` + Checkpoint time.Time `gorm:"-" json:"-"` + SleepDuration time.Duration `gorm:"-" json:"-"` + LastResponse string `gorm:"-" json:"-"` + LastStatusCode int `gorm:"-" json:"status_code"` + LastOnline time.Time `gorm:"-" json:"last_online"` + Failures []FailureInterface `gorm:"-" json:"failures,omitempty"` } type ServiceInterface interface {