Initial logic to support logging activity on Wings to send back to the panel

This commit is contained in:
DaneEveritt
2022-07-04 17:36:03 -04:00
parent 214baf83fb
commit 9eab08b92f
10 changed files with 256 additions and 8 deletions

View File

@@ -66,6 +66,7 @@ func Configure(m *wserver.Manager, client remote.Client) *gin.Engine {
server.DELETE("", deleteServer)
server.GET("/logs", getServerLogs)
server.GET("/activity", getServerActivityLogs)
server.POST("/power", postServerPower)
server.POST("/commands", postServerCommands)
server.POST("/install", postServerInstall)

View File

@@ -2,6 +2,9 @@ package router
import (
"context"
"github.com/goccy/go-json"
"github.com/pterodactyl/wings/database"
"github.com/xujiajun/nutsdb"
"net/http"
"os"
"strconv"
@@ -40,6 +43,44 @@ func getServerLogs(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"data": out})
}
// Returns the activity logs tracked internally for the server instance. Note that these
// logs are routinely cleared out as Wings communicates directly with the Panel to pass
// along all of the logs for servers it monitors. As activities are passed to the panel
// they are deleted from Wings.
//
// As a result, this endpoint may or may not return data, and the data returned can change
// between requests.
func getServerActivityLogs(c *gin.Context) {
s := ExtractServer(c)
var out [][]byte
err := database.DB().View(func(tx *nutsdb.Tx) error {
items, err := tx.LRange(database.ServerEventsBucket, []byte(s.ID()), 0, 10)
if err != nil {
return err
}
out = items
return nil
})
if err != nil {
middleware.CaptureAndAbort(c, err)
return
}
var activity []*server.Activity
for _, b := range out {
var a server.Activity
if err := json.Unmarshal(b, &a); err != nil {
middleware.CaptureAndAbort(c, err)
return
}
activity = append(activity, &a)
}
c.JSON(http.StatusOK, gin.H{"data": activity})
}
// Handles a request to control the power state of a server. If the action being passed
// through is invalid a 404 is returned. Otherwise, a HTTP/202 Accepted response is returned
// and the actual power action is run asynchronously so that we don't have to block the

View File

@@ -7,7 +7,6 @@ import (
"github.com/apex/log"
"github.com/gbrlsnchs/jwt/v3"
"github.com/goccy/go-json"
)
// The time at which Wings was booted. No JWT's created before this time are allowed to
@@ -35,15 +34,15 @@ func DenyJTI(jti string) {
denylist.Store(jti, time.Now())
}
// A JWT payload for Websocket connections. This JWT is passed along to the Websocket after
// it has been connected to by sending an "auth" event.
// WebsocketPayload defines the JWT payload for a websocket connection. This JWT is passed along to
// the websocket after it has been connected to by sending an "auth" event.
type WebsocketPayload struct {
jwt.Payload
sync.RWMutex
UserID json.Number `json:"user_id"`
ServerUUID string `json:"server_uuid"`
Permissions []string `json:"permissions"`
UserUUID string `json:"user_uuid"`
ServerUUID string `json:"server_uuid"`
Permissions []string `json:"permissions"`
}
// Returns the JWT payload.

View File

@@ -40,6 +40,7 @@ type Handler struct {
Connection *websocket.Conn `json:"-"`
jwt *tokens.WebsocketPayload
server *server.Server
ra server.RequestActivity
uuid uuid.UUID
}
@@ -109,6 +110,7 @@ func GetHandler(s *server.Server, w http.ResponseWriter, r *http.Request) (*Hand
Connection: conn,
jwt: nil,
server: s,
ra: s.NewRequestActivity("", r.RemoteAddr),
uuid: u,
}, nil
}
@@ -264,6 +266,7 @@ func (h *Handler) GetJwt() *tokens.WebsocketPayload {
// setJwt sets the JWT for the websocket in a race-safe manner.
func (h *Handler) setJwt(token *tokens.WebsocketPayload) {
h.Lock()
h.ra = h.ra.SetUser(token.UserUUID)
h.jwt = token
h.Unlock()
}
@@ -421,6 +424,15 @@ func (h *Handler) HandleInbound(ctx context.Context, m Message) error {
}
}
// Track this command sending event in the local database.
e := h.ra.Event(server.ActivityCommandSent, server.ActivityMeta{
"command": strings.Join(m.Args, ""),
})
if err := e.Save(); err != nil {
h.server.Log().WithField("error", err).Error("activity: failed to persist event to database")
}
return h.server.Environment.SendCommand(strings.Join(m.Args, ""))
}
}