diff --git a/storagenode/console/consoleserver/server.go b/storagenode/console/consoleserver/server.go index 112427512..5fb300a36 100644 --- a/storagenode/console/consoleserver/server.go +++ b/storagenode/console/consoleserver/server.go @@ -5,19 +5,33 @@ package consoleserver import ( "context" + "encoding/json" "net" "net/http" "path/filepath" + "time" "github.com/zeebo/errs" "go.uber.org/zap" "golang.org/x/sync/errgroup" + monkit "gopkg.in/spacemonkeygo/monkit.v2" + "storj.io/storj/internal/version" + "storj.io/storj/pkg/storj" "storj.io/storj/storagenode/console" ) +const ( + contentType = "Content-Type" + + applicationJSON = "application/json" +) + // Error is storagenode console web error type -var Error = errs.Class("storagenode console web error") +var ( + mon = monkit.Package() + Error = errs.Class("storagenode console web error") +) // Config contains configuration for storagenode console web server type Config struct { @@ -54,6 +68,7 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, list mux.Handle("/static/", http.StripPrefix("/static", fs)) mux.Handle("/", http.HandlerFunc(server.appHandler)) + mux.Handle("/api/dashboard/", http.HandlerFunc(server.dashboardHandler)) } server.server = http.Server{ @@ -65,6 +80,8 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, list // Run starts the server that host webapp and api endpoints func (s *Server) Run(ctx context.Context) (err error) { + defer mon.Task()(&ctx)(&err) + ctx, cancel := context.WithCancel(ctx) var group errgroup.Group group.Go(func() error { @@ -88,3 +105,133 @@ func (s *Server) Close() error { func (s *Server) appHandler(w http.ResponseWriter, req *http.Request) { http.ServeFile(w, req, filepath.Join(s.config.StaticDir, "dist", "index.html")) } + +// appHandler is web app http handler function +func (s *Server) dashboardHandler(w http.ResponseWriter, req *http.Request) { + ctx := req.Context() + defer mon.Task()(&ctx)(nil) + w.Header().Set(contentType, applicationJSON) + + var response struct { + Data struct { + Bandwidth console.BandwidthInfo `json:"bandwidth"` + DiskSpace console.DiskSpaceInfo `json:"diskSpace"` + WalletAddress string `json:"walletAddress"` + VersionInfo version.Info `json:"versionInfo"` + IsLastVersion bool `json:"isLastVersion"` + Uptime time.Duration `json:"uptime"` + NodeID string `json:"nodeId"` + Satellites storj.NodeIDList `json:"satellites"` + } `json:"data"` + Error string `json:"error,omitempty"` + } + + defer func() { + err := json.NewEncoder(w).Encode(&response) + if err != nil { + s.log.Error(err.Error()) + } + }() + + satelliteIDParam := req.URL.Query().Get("satelliteId") + s.log.Info("param: " + satelliteIDParam) + satelliteID, err := s.parseSatelliteIDParam(satelliteIDParam) + if satelliteID != nil { + s.log.Info("ID: " + satelliteID.String()) + } + if err != nil { + s.log.Error("satellite id is not valid", zap.Error(err)) + response.Error = "satellite id is not valid" + return + } + + satellites, err := s.service.GetSatellites(ctx) + if satellites == nil { + s.log.Info("SATELLITES ARE NIL") + } + if err != nil { + s.log.Error("can not get satellites list", zap.Error(err)) + response.Error = "can not get satellites list" + return + } + + if satelliteID != nil { + if err = s.checkSatelliteID(satellites, *satelliteID); err != nil { + s.log.Error(err.Error()) + response.Error = err.Error() + return + } + } + + space, err := s.getStorage(ctx, satelliteID) + if err != nil { + s.log.Error("can not get disk space usage", zap.Error(err)) + response.Error = "can not get disk space usage" + return + } + + usage, err := s.getBandwidth(ctx, satelliteID) + if err != nil { + s.log.Error("can not get bandwidth usage", zap.Error(err)) + response.Error = "can not get bandwidth usage" + return + } + + walletAddress := s.service.GetWalletAddress(ctx) + + versionInfo := s.service.GetVersion(ctx) + + err = s.service.CheckVersion(ctx) + if err != nil { + s.log.Error("can not check latest storage node version", zap.Error(err)) + response.Error = "can not check latest storage node version" + return + } + + uptime := s.service.GetUptime(ctx) + nodeID := s.service.GetNodeID(ctx) + + response.Data.DiskSpace = *space + response.Data.Bandwidth = *usage + response.Data.WalletAddress = walletAddress + response.Data.VersionInfo = versionInfo + response.Data.IsLastVersion = true + response.Data.Uptime = uptime + response.Data.NodeID = nodeID.String() + response.Data.Satellites = satellites +} + +func (s *Server) getBandwidth(ctx context.Context, satelliteID *storj.NodeID) (_ *console.BandwidthInfo, err error) { + if satelliteID != nil { + return s.service.GetBandwidthBySatellite(ctx, *satelliteID) + } + + return s.service.GetUsedBandwidthTotal(ctx) +} + +func (s *Server) getStorage(ctx context.Context, satelliteID *storj.NodeID) (_ *console.DiskSpaceInfo, err error) { + if satelliteID != nil { + return s.service.GetUsedStorageBySatellite(ctx, *satelliteID) + } + + return s.service.GetUsedStorageTotal(ctx) +} + +func (s *Server) checkSatelliteID(satelliteIDs storj.NodeIDList, satelliteID storj.NodeID) error { + for _, id := range satelliteIDs { + if satelliteID == id { + return nil + } + } + + return errs.New("satellite id in not found in the available satellite list") +} + +func (s *Server) parseSatelliteIDParam(satelliteID string) (*storj.NodeID, error) { + if satelliteID != "" { + id, err := storj.NodeIDFromString(satelliteID) + return &id, err + } + + return nil, nil +} diff --git a/storagenode/console/service.go b/storagenode/console/service.go index 23ad950cc..f7a1692db 100644 --- a/storagenode/console/service.go +++ b/storagenode/console/service.go @@ -9,6 +9,7 @@ import ( "github.com/zeebo/errs" "go.uber.org/zap" + monkit "gopkg.in/spacemonkeygo/monkit.v2" "storj.io/storj/internal/memory" "storj.io/storj/internal/version" @@ -18,6 +19,8 @@ import ( "storj.io/storj/storagenode/pieces" ) +var mon = monkit.Package() + // DB exposes methods for managing SNO dashboard related data. type DB interface { GetSatelliteIDs(ctx context.Context, from, to time.Time) (storj.NodeIDList, error) @@ -69,6 +72,7 @@ func NewService(log *zap.Logger, consoleDB DB, bandwidth bandwidth.DB, pieceInfo return &Service{ log: log, + consoleDB: consoleDB, bandwidthDB: bandwidth, pieceInfoDB: pieceInfo, kademlia: kademlia, @@ -82,7 +86,9 @@ func NewService(log *zap.Logger, consoleDB DB, bandwidth bandwidth.DB, pieceInfo } // GetUsedBandwidthTotal returns all info about storage node bandwidth usage -func (s *Service) GetUsedBandwidthTotal(ctx context.Context) (*BandwidthInfo, error) { +func (s *Service) GetUsedBandwidthTotal(ctx context.Context) (_ *BandwidthInfo, err error) { + defer mon.Task()(&ctx)(&err) + usage, err := bandwidth.TotalMonthlySummary(ctx, s.bandwidthDB) if err != nil { return nil, err @@ -93,6 +99,8 @@ func (s *Service) GetUsedBandwidthTotal(ctx context.Context) (*BandwidthInfo, er // GetBandwidthBySatellite returns all info about storage node bandwidth usage by satellite func (s *Service) GetBandwidthBySatellite(ctx context.Context, satelliteID storj.NodeID) (_ *BandwidthInfo, err error) { + defer mon.Task()(&ctx)(&err) + summaries, err := s.bandwidthDB.SummaryBySatellite(ctx, time.Time{}, time.Now()) if err != nil { return nil, err @@ -103,7 +111,9 @@ func (s *Service) GetBandwidthBySatellite(ctx context.Context, satelliteID storj } // GetUsedStorageTotal returns all info about storagenode disk space usage -func (s *Service) GetUsedStorageTotal(ctx context.Context) (*DiskSpaceInfo, error) { +func (s *Service) GetUsedStorageTotal(ctx context.Context) (_ *DiskSpaceInfo, err error) { + defer mon.Task()(&ctx)(&err) + spaceUsed, err := s.pieceInfoDB.SpaceUsed(ctx) if err != nil { return nil, err @@ -113,7 +123,9 @@ func (s *Service) GetUsedStorageTotal(ctx context.Context) (*DiskSpaceInfo, erro } // GetUsedStorageBySatellite returns all info about storagenode disk space usage -func (s *Service) GetUsedStorageBySatellite(ctx context.Context, satelliteID storj.NodeID) (*DiskSpaceInfo, error) { +func (s *Service) GetUsedStorageBySatellite(ctx context.Context, satelliteID storj.NodeID) (_ *DiskSpaceInfo, err error) { + defer mon.Task()(&ctx)(&err) + spaceUsed, err := s.pieceInfoDB.SpaceUsedBySatellite(ctx, satelliteID) if err != nil { return nil, err @@ -122,32 +134,43 @@ func (s *Service) GetUsedStorageBySatellite(ctx context.Context, satelliteID sto return &DiskSpaceInfo{Available: s.allocatedDiskSpace.Int64() - spaceUsed, Used: spaceUsed}, nil } -// GetWalletNumber return wallet number of node operator -func (s *Service) GetWalletNumber(ctx context.Context) string { +// GetWalletAddress return wallet address of node operator +func (s *Service) GetWalletAddress(ctx context.Context) string { + defer mon.Task()(&ctx)(nil) + return s.walletAddress } // GetUptime return wallet number of node operator func (s *Service) GetUptime(ctx context.Context) time.Duration { + defer mon.Task()(&ctx)(nil) + return time.Now().Sub(s.startedAt) } // GetNodeID return current node id func (s *Service) GetNodeID(ctx context.Context) storj.NodeID { + defer mon.Task()(&ctx)(nil) + return s.kademlia.Local().Id } // GetVersion return current node version func (s *Service) GetVersion(ctx context.Context) version.Info { + defer mon.Task()(&ctx)(nil) return s.versionInfo } // CheckVersion checks to make sure the version is still okay, returning an error if not -func (s *Service) CheckVersion(ctx context.Context) error { +func (s *Service) CheckVersion(ctx context.Context) (err error) { + defer mon.Task()(&ctx)(&err) + return s.version.CheckVersion(ctx) } // GetSatellites used to retrieve satellites list func (s *Service) GetSatellites(ctx context.Context) (_ storj.NodeIDList, err error) { + defer mon.Task()(&ctx)(&err) + return s.consoleDB.GetSatelliteIDs(ctx, time.Time{}, time.Now()) } diff --git a/storagenode/peer.go b/storagenode/peer.go index b2d4f70b2..7ace739dd 100644 --- a/storagenode/peer.go +++ b/storagenode/peer.go @@ -391,6 +391,11 @@ func (peer *Peer) Close() error { if peer.Kademlia.RoutingTable != nil { errlist.Add(peer.Kademlia.RoutingTable.Close()) } + if peer.Console.Endpoint != nil { + errlist.Add(peer.Console.Endpoint.Close()) + } else if peer.Console.Listener != nil { + errlist.Add(peer.Console.Listener.Close()) + } return errlist.Err() } diff --git a/web/operator/dist/build.js b/web/operator/dist/build.js index bbecf7c21..fafb32cb7 100644 --- a/web/operator/dist/build.js +++ b/web/operator/dist/build.js @@ -1,4 +1,9 @@ // Copyright (C) 2019 Storj Labs, Inc. // See LICENSE for copying information. -alert('hello, node operator'); \ No newline at end of file +var xmlHttp = new XMLHttpRequest(); + +xmlHttp.open("GET", "/api/dashboard?satelliteId=12D1kqUXtJiCsS72UKeCGHyKSQy1FSonerZ5fb6nSQAaSim4Vag", false ); +xmlHttp.send(); + +alert(xmlHttp.responseText); \ No newline at end of file