From 6af3cb2c9bf183c15695898939f2eea18f03df61 Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Sat, 4 Apr 2020 16:15:49 -0600 Subject: [PATCH] Get transfers 'fully' working, need to add fail request though --- api/server_endpoints.go | 30 ++++++++++++++++++++++ http.go | 57 +++++++++++++++++++++++++++++++++++++++-- server/server.go | 2 +- server/update.go | 5 ++++ 4 files changed, 91 insertions(+), 3 deletions(-) diff --git a/api/server_endpoints.go b/api/server_endpoints.go index da4b758..caf84ab 100644 --- a/api/server_endpoints.go +++ b/api/server_endpoints.go @@ -146,3 +146,33 @@ func (r *PanelRequest) SendArchiveStatus(uuid string, successful bool) (*Request return nil, nil } + +func (r *PanelRequest) SendTransferFailure(uuid string) (*RequestError, error) { + resp, err := r.Get(fmt.Sprintf("/servers/%s/transfer/failure", uuid)) + if err != nil { + return nil, errors.WithStack(err) + } + defer resp.Body.Close() + + r.Response = resp + if r.HasError() { + return r.Error(), nil + } + + return nil, nil +} + +func (r *PanelRequest) SendTransferSuccess(uuid string) (*RequestError, error) { + resp, err := r.Get(fmt.Sprintf("/servers/%s/transfer/success", uuid)) + if err != nil { + return nil, errors.WithStack(err) + } + defer resp.Body.Close() + + r.Response = resp + if r.HasError() { + return r.Error(), nil + } + + return nil, nil +} diff --git a/http.go b/http.go index eda79cc..a12344f 100644 --- a/http.go +++ b/http.go @@ -10,6 +10,7 @@ import ( "github.com/buger/jsonparser" "github.com/gorilla/websocket" "github.com/julienschmidt/httprouter" + "github.com/mholt/archiver/v3" "github.com/pkg/errors" "github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/config" @@ -468,6 +469,7 @@ func (rt *Router) routeServerUpdate(w http.ResponseWriter, r *http.Request, ps h return } + zap.S().Debugw("updated server's data structure", zap.String("server", s.Uuid)) w.WriteHeader(http.StatusNoContent) } @@ -700,6 +702,7 @@ func (rt *Router) routeIncomingTransfer(w http.ResponseWriter, r *http.Request, } defer res.Body.Close() + // Handle non-200 status codes. if res.StatusCode != 200 { body, err := ioutil.ReadAll(res.Body) if err != nil { @@ -711,45 +714,95 @@ func (rt *Router) routeIncomingTransfer(w http.ResponseWriter, r *http.Request, return } + // Get the path to the archive. archivePath := filepath.Join(config.Get().System.ArchiveDirectory, serverID + ".tar.gz") - // Create the file + // Create the file. file, err := os.Create(archivePath) if err != nil { zap.S().Errorw("failed to open file on disk", zap.Error(err)) return } + // Copy the file. _, err = io.Copy(file, res.Body) if err != nil { zap.S().Errorw("failed to copy file to disk", zap.Error(err)) return } + // Close the file so it can be opened to verify the checksum. if err := file.Close(); err != nil { zap.S().Errorw("failed to close archive file", zap.Error(err)) return } + zap.S().Debug("server archive has been downloaded, computing checksum..", zap.String("server", serverID)) + // Open the archive file for computing a checksum. file, err = os.Open(archivePath) if err != nil { zap.S().Errorw("failed to open file on disk", zap.Error(err)) return } - defer file.Close() + // Compute the sha256 checksum of the file. hash := sha256.New() if _, err := io.Copy(hash, file); err != nil { zap.S().Errorw("failed to copy file for checksum verification", zap.Error(err)) return } + // Verify the two checksums. if hex.EncodeToString(hash.Sum(nil)) != res.Header.Get("X-Checksum") { zap.S().Errorw("checksum failed verification") return } + // Close the file. + if err := file.Close(); err != nil { + zap.S().Errorw("failed to close archive file", zap.Error(err)) + return + } + zap.S().Infow("server archive transfer was successful", zap.String("server", serverID)) + + // Get the server data from the request. + serverData, t, _, _ := jsonparser.Get(data, "server") + if t != jsonparser.Object { + zap.S().Errorw("invalid server data passed in request") + return + } + + zap.S().Debug(string(serverData)) + + // Create a new server installer (note this does not execute the install script) + i, err := installer.New(serverData) + if err != nil { + zap.S().Warnw("failed to validate the received server data", zap.Error(err)) + return + } + + // Add the server to the collection. + server.GetServers().Add(i.Server()) + + // Create the server's environment (note this does not execute the install script) + i.Execute() + + // Un-archive the archive. That sounds weird.. + archiver.NewTarGz().Unarchive(archivePath, i.Server().Filesystem.Path()) + + rerr, err := api.NewRequester().SendTransferSuccess(serverID) + if rerr != nil || err != nil { + if err != nil { + zap.S().Errorw("failed to notify panel with archive status", zap.String("server", serverID), zap.Error(err)) + return + } + + zap.S().Errorw("panel returned an error when sending the archive status", zap.String("server", serverID), zap.Error(errors.New(rerr.String()))) + return + } + + zap.S().Debugw("successfully notified panel about transfer success", zap.String("server", serverID)) }(rt.ReaderToBytes(r.Body)) w.WriteHeader(202) diff --git a/server/server.go b/server/server.go index 398fb59..d095d34 100644 --- a/server/server.go +++ b/server/server.go @@ -371,7 +371,7 @@ func (s *Server) SetState(state string) error { // // In the event that we have passed the thresholds, don't do anything, otherwise // automatically attempt to start the process back up for the user. This is done in a - // seperate thread as to not block any actions currently taking place in the flow + // separate thread as to not block any actions currently taking place in the flow // that called this function. if (prevState == ProcessStartingState || prevState == ProcessRunningState) && s.State == ProcessOfflineState { zap.S().Infow("detected server as entering a potentially crashed state; running handler", zap.String("server", s.Uuid)) diff --git a/server/update.go b/server/update.go index 9bc8307..9e74676 100644 --- a/server/update.go +++ b/server/update.go @@ -52,6 +52,11 @@ func (s *Server) UpdateDataStructure(data []byte, background bool) error { } } else { s.Suspended = v + if s.Suspended { + zap.S().Debugw("server has been suspended", zap.String("server", s.Uuid)) + } else { + zap.S().Debugw("server has been unsuspended", zap.String("server", s.Uuid)) + } } // Environment and Mappings should be treated as a full update at all times, never a