diff --git a/uchiwa/daemon/daemon.go b/uchiwa/daemon/daemon.go index e321c70..e551c17 100644 --- a/uchiwa/daemon/daemon.go +++ b/uchiwa/daemon/daemon.go @@ -80,36 +80,43 @@ func (d *Daemon) fetchData() { // fetch sensu data from the datacenter stashes, err := datacenter.GetStashes() if err != nil { + logger.Debug(err) logger.Warningf("Connection failed to the datacenter %s", datacenter.Name) continue } silenced, err := datacenter.GetSilenced() if err != nil { + logger.Debug(err) logger.Warningf("Impossible to retrieve silenced entries from the "+ "datacenter %s. Silencing might not be possible, please update Sensu", datacenter.Name) } checks, err := datacenter.GetChecks() if err != nil { + logger.Debug(err) logger.Warningf("Connection failed to the datacenter %s", datacenter.Name) continue } clients, err := datacenter.GetClients() if err != nil { + logger.Debug(err) logger.Warningf("Connection failed to the datacenter %s", datacenter.Name) continue } events, err := datacenter.GetEvents() if err != nil { + logger.Debug(err) logger.Warningf("Connection failed to the datacenter %s", datacenter.Name) continue } info, err := datacenter.GetInfo() if err != nil { + logger.Debug(err) logger.Warningf("Connection failed to the datacenter %s", datacenter.Name) continue } aggregates, err := datacenter.GetAggregates() if err != nil { + logger.Debug(err) logger.Warningf("Connection failed to the datacenter %s", datacenter.Name) continue } @@ -155,12 +162,12 @@ func (d *Daemon) fetchData() { // build datacenter dc := d.buildDatacenter(&datacenter.Name, info) - dc.Stats["aggregates"] = len(aggregates) - dc.Stats["checks"] = len(checks) - dc.Stats["clients"] = len(clients) - dc.Stats["events"] = len(events) - dc.Stats["silenced"] = len(silenced) - dc.Stats["stashes"] = len(stashes) + dc.Metrics["aggregates"] = len(aggregates) + dc.Metrics["checks"] = len(checks) + dc.Metrics["clients"] = len(clients) + dc.Metrics["events"] = len(events) + dc.Metrics["silenced"] = len(silenced) + dc.Metrics["stashes"] = len(stashes) d.Data.Dc = append(d.Data.Dc, dc) } } diff --git a/uchiwa/daemon/datacenters.go b/uchiwa/daemon/datacenters.go index 235cb4c..d45b28e 100644 --- a/uchiwa/daemon/datacenters.go +++ b/uchiwa/daemon/datacenters.go @@ -4,9 +4,9 @@ import "github.com/sensu/uchiwa/uchiwa/structs" func (d *Daemon) buildDatacenter(name *string, info *structs.Info) *structs.Datacenter { datacenter := structs.Datacenter{ - Name: *name, - Info: *info, - Stats: make(map[string]int, 5), + Name: *name, + Info: *info, + Metrics: make(map[string]int, 5), } return &datacenter diff --git a/uchiwa/datacenter.go b/uchiwa/datacenter.go new file mode 100644 index 0000000..6ac88f4 --- /dev/null +++ b/uchiwa/datacenter.go @@ -0,0 +1,17 @@ +package uchiwa + +import ( + "fmt" + + "github.com/sensu/uchiwa/uchiwa/structs" +) + +func (u *Uchiwa) Datacenter(name string) (*structs.Datacenter, error) { + for _, dc := range u.Data.Dc { + if dc.Name == name { + return dc, nil + } + } + + return nil, fmt.Errorf("") +} diff --git a/uchiwa/server.go b/uchiwa/server.go index f0dad6a..77849be 100644 --- a/uchiwa/server.go +++ b/uchiwa/server.go @@ -483,6 +483,47 @@ func (u *Uchiwa) configHandler(w http.ResponseWriter, r *http.Request) { } } +// datacentersHandler serves the /datacenters/:name endpoint +func (u *Uchiwa) datacenterHandler(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" && r.Method != "HEAD" { + http.Error(w, "", http.StatusBadRequest) + return + } + + resources := strings.Split(r.URL.Path, "/") + if len(resources) < 3 || resources[2] == "" { + http.Error(w, "", http.StatusBadRequest) + return + } + + name := resources[2] + + token := authentication.GetJWTFromContext(r) + unauthorized := Filters.GetRequest(name, token) + if unauthorized { + http.Error(w, fmt.Sprint(""), http.StatusNotFound) + return + } + + // Create header + w.Header().Add("Accept-Charset", "utf-8") + w.Header().Add("Content-Type", "application/json") + + datacenter, err := u.Datacenter(name) + if err != nil { + http.Error(w, fmt.Sprint(""), http.StatusNotFound) + return + } + + encoder := json.NewEncoder(w) + if err := encoder.Encode(datacenter); err != nil { + http.Error(w, fmt.Sprintf("Cannot encode response data: %v", err), http.StatusInternalServerError) + return + } + + return +} + // datacentersHandler serves the /datacenters endpoint func (u *Uchiwa) datacentersHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" && r.Method != "HEAD" { @@ -1173,6 +1214,7 @@ func (u *Uchiwa) WebServer(publicPath *string, auth authentication.Config) { http.Handle("/clients/", auth.Authenticate(Authorization.Handler(http.HandlerFunc(u.clientHandler)))) http.Handle("/config", auth.Authenticate(Authorization.Handler(http.HandlerFunc(u.configHandler)))) http.Handle("/datacenters", auth.Authenticate(Authorization.Handler(http.HandlerFunc(u.datacentersHandler)))) + http.Handle("/datacenters/", auth.Authenticate(Authorization.Handler(http.HandlerFunc(u.datacenterHandler)))) http.Handle("/events", auth.Authenticate(Authorization.Handler(http.HandlerFunc(u.eventsHandler)))) http.Handle("/events/", auth.Authenticate(Authorization.Handler(http.HandlerFunc(u.eventHandler)))) http.Handle("/logout", auth.Authenticate(Authorization.Handler(http.HandlerFunc(u.logoutHandler)))) diff --git a/uchiwa/structs/structs.go b/uchiwa/structs/structs.go index 922b102..21ae3bf 100644 --- a/uchiwa/structs/structs.go +++ b/uchiwa/structs/structs.go @@ -47,9 +47,9 @@ type Data struct { // Datacenter is a structure for holding the information about a datacenter type Datacenter struct { - Name string `json:"name"` - Info Info `json:"info"` - Stats map[string]int `json:"stats"` + Name string `json:"name"` + Info Info `json:"info"` + Metrics map[string]int `json:"metrics"` } // Generic is a structure for holding a generic element @@ -93,9 +93,19 @@ type SensuHealth struct { // Info is a structure for holding the /info API information type Info struct { - Redis Redis `json:"redis"` - Sensu Sensu `json:"sensu"` - Transport transport `json:"transport"` + Redis Redis `json:"redis"` + Sensu Sensu `json:"sensu"` + Servers []InfoServer `json:"servers"` + Transport transport `json:"transport"` +} + +type InfoServer struct { + ID string `json:"id"` + Hostname string `json:"hostname"` + Address string `json:"address"` + IsLeader bool `json:"is_leader"` + Metrics map[string]map[string]float32 `json:"metrics"` + Timestamp int `json:"timestamp"` } // Redis is a structure for holding the redis status