2020-04-04 23:07:25 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2020-04-20 02:52:19 +00:00
|
|
|
"bufio"
|
2020-12-16 05:56:53 +00:00
|
|
|
"emperror.dev/errors"
|
2020-06-13 17:40:26 +00:00
|
|
|
"github.com/apex/log"
|
2020-04-17 20:46:36 +00:00
|
|
|
"github.com/pterodactyl/wings/api"
|
2020-04-14 05:01:07 +00:00
|
|
|
"github.com/pterodactyl/wings/server/backup"
|
2020-04-20 02:52:19 +00:00
|
|
|
"os"
|
|
|
|
"path"
|
2020-04-04 23:07:25 +00:00
|
|
|
)
|
|
|
|
|
2020-04-17 20:46:36 +00:00
|
|
|
// Notifies the panel of a backup's state and returns an error if one is encountered
|
|
|
|
// while performing this action.
|
|
|
|
func (s *Server) notifyPanelOfBackup(uuid string, ad *backup.ArchiveDetails, successful bool) error {
|
2020-12-06 20:56:17 +00:00
|
|
|
if err := api.New().SendBackupStatus(uuid, ad.ToRequest(successful)); err != nil {
|
2020-10-31 17:04:20 +00:00
|
|
|
if !api.IsRequestError(err) {
|
2020-06-13 17:40:26 +00:00
|
|
|
s.Log().WithFields(log.Fields{
|
|
|
|
"backup": uuid,
|
|
|
|
"error": err,
|
2020-08-28 02:35:57 +00:00
|
|
|
}).Error("failed to notify panel of backup status due to wings error")
|
2020-04-17 20:46:36 +00:00
|
|
|
|
2020-11-28 23:57:10 +00:00
|
|
|
return err
|
2020-04-17 20:46:36 +00:00
|
|
|
}
|
|
|
|
|
2020-10-31 17:04:20 +00:00
|
|
|
return errors.New(err.Error())
|
2020-04-17 20:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-04-26 23:43:18 +00:00
|
|
|
// Get all of the ignored files for a server based on its .pteroignore file in the root.
|
|
|
|
func (s *Server) getServerwideIgnoredFiles() ([]string, error) {
|
|
|
|
var ignored []string
|
|
|
|
|
2020-09-27 19:24:08 +00:00
|
|
|
f, err := os.Open(path.Join(s.Filesystem().Path(), ".pteroignore"))
|
2020-04-26 23:43:18 +00:00
|
|
|
if err != nil {
|
|
|
|
if !os.IsNotExist(err) {
|
2020-11-28 23:57:10 +00:00
|
|
|
return nil, err
|
2020-04-26 23:43:18 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
|
|
for scanner.Scan() {
|
|
|
|
// Only include non-empty lines, for the sake of clarity...
|
|
|
|
if t := scanner.Text(); t != "" {
|
|
|
|
ignored = append(ignored, t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := scanner.Err(); err != nil {
|
2020-11-28 23:57:10 +00:00
|
|
|
return nil, err
|
2020-04-26 23:43:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ignored, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the backup files to include when generating it.
|
|
|
|
func (s *Server) GetIncludedBackupFiles(ignored []string) (*backup.IncludedFiles, error) {
|
2020-04-20 02:52:19 +00:00
|
|
|
// If no ignored files are present in the request, check for a .pteroignore file in the root
|
|
|
|
// of the server files directory, and use that to generate the backup.
|
2020-04-26 23:43:18 +00:00
|
|
|
if len(ignored) == 0 {
|
|
|
|
if i, err := s.getServerwideIgnoredFiles(); err != nil {
|
2020-06-13 17:40:26 +00:00
|
|
|
s.Log().WithField("error", err).Warn("failed to retrieve ignored files listing for server")
|
2020-04-20 02:52:19 +00:00
|
|
|
} else {
|
2020-04-26 23:43:18 +00:00
|
|
|
ignored = i
|
2020-04-20 02:52:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the included files based on the root path and the ignored files provided.
|
2020-09-27 19:24:08 +00:00
|
|
|
return s.Filesystem().GetIncludedFiles(s.Filesystem().Path(), ignored)
|
2020-04-26 23:43:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Performs a server backup and then emits the event over the server websocket. We
|
|
|
|
// let the actual backup system handle notifying the panel of the status, but that
|
|
|
|
// won't emit a websocket event.
|
2020-05-02 22:02:02 +00:00
|
|
|
func (s *Server) Backup(b backup.BackupInterface) error {
|
2020-04-26 23:43:18 +00:00
|
|
|
// Get the included files based on the root path and the ignored files provided.
|
|
|
|
inc, err := s.GetIncludedBackupFiles(b.Ignored())
|
2020-04-19 06:26:23 +00:00
|
|
|
if err != nil {
|
2020-11-28 23:57:10 +00:00
|
|
|
return err
|
2020-04-19 06:26:23 +00:00
|
|
|
}
|
|
|
|
|
2020-09-27 19:24:08 +00:00
|
|
|
ad, err := b.Generate(inc, s.Filesystem().Path())
|
2020-05-10 02:24:30 +00:00
|
|
|
if err != nil {
|
2020-04-17 20:46:36 +00:00
|
|
|
if notifyError := s.notifyPanelOfBackup(b.Identifier(), &backup.ArchiveDetails{}, false); notifyError != nil {
|
2020-06-13 17:40:26 +00:00
|
|
|
s.Log().WithFields(log.Fields{
|
|
|
|
"backup": b.Identifier(),
|
2020-08-28 02:35:57 +00:00
|
|
|
"error": notifyError,
|
2020-06-13 17:40:26 +00:00
|
|
|
}).Warn("failed to notify panel of failed backup state")
|
2020-11-28 23:57:10 +00:00
|
|
|
} else {
|
|
|
|
s.Log().WithFields(log.Fields{
|
|
|
|
"backup": b.Identifier(),
|
|
|
|
"error": err,
|
|
|
|
}).Info("notified panel of failed backup state")
|
2020-04-04 23:07:25 +00:00
|
|
|
}
|
|
|
|
|
2020-08-21 04:28:06 +00:00
|
|
|
s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
|
|
|
|
"uuid": b.Identifier(),
|
|
|
|
"is_successful": false,
|
2020-08-24 01:06:17 +00:00
|
|
|
"checksum": "",
|
|
|
|
"checksum_type": "sha1",
|
2020-08-21 04:28:06 +00:00
|
|
|
"file_size": 0,
|
|
|
|
})
|
|
|
|
|
2020-11-28 23:57:10 +00:00
|
|
|
return errors.WithMessage(err, "backup: error while generating server backup")
|
2020-04-04 23:07:25 +00:00
|
|
|
}
|
|
|
|
|
2020-04-14 05:01:07 +00:00
|
|
|
// Try to notify the panel about the status of this backup. If for some reason this request
|
|
|
|
// fails, delete the archive from the daemon and return that error up the chain to the caller.
|
2020-04-17 20:46:36 +00:00
|
|
|
if notifyError := s.notifyPanelOfBackup(b.Identifier(), ad, true); notifyError != nil {
|
2020-04-14 05:01:07 +00:00
|
|
|
b.Remove()
|
2020-11-28 23:57:10 +00:00
|
|
|
s.Log().WithField("error", notifyError).Info("failed to notify panel of successful backup state")
|
|
|
|
return err
|
|
|
|
} else {
|
|
|
|
s.Log().WithField("backup", b.Identifier()).Info("notified panel of successful backup state")
|
2020-04-04 23:07:25 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 04:03:50 +00:00
|
|
|
// Emit an event over the socket so we can update the backup in realtime on
|
|
|
|
// the frontend for the server.
|
2020-04-26 23:43:18 +00:00
|
|
|
s.Events().PublishJson(BackupCompletedEvent+":"+b.Identifier(), map[string]interface{}{
|
2020-08-21 04:28:06 +00:00
|
|
|
"uuid": b.Identifier(),
|
|
|
|
"is_successful": true,
|
2020-08-24 01:06:17 +00:00
|
|
|
"checksum": ad.Checksum,
|
|
|
|
"checksum_type": "sha1",
|
2020-08-21 04:28:06 +00:00
|
|
|
"file_size": ad.Size,
|
2020-04-07 04:03:50 +00:00
|
|
|
})
|
|
|
|
|
2020-04-04 23:07:25 +00:00
|
|
|
return nil
|
2020-06-13 17:40:26 +00:00
|
|
|
}
|