2020-04-14 05:01:07 +00:00
|
|
|
package backup
|
|
|
|
|
|
|
|
import (
|
2020-08-24 00:34:48 +00:00
|
|
|
"crypto/sha1"
|
2020-05-02 22:02:02 +00:00
|
|
|
"encoding/hex"
|
2020-06-13 17:40:26 +00:00
|
|
|
"github.com/apex/log"
|
2020-04-14 05:01:07 +00:00
|
|
|
"github.com/pterodactyl/wings/api"
|
2020-05-02 22:02:02 +00:00
|
|
|
"github.com/pterodactyl/wings/config"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"sync"
|
2020-04-14 05:01:07 +00:00
|
|
|
)
|
|
|
|
|
2020-04-26 23:21:58 +00:00
|
|
|
const (
|
2020-04-26 23:43:18 +00:00
|
|
|
LocalBackupAdapter = "wings"
|
2020-04-26 23:21:58 +00:00
|
|
|
S3BackupAdapter = "s3"
|
|
|
|
)
|
|
|
|
|
2020-05-02 22:02:02 +00:00
|
|
|
type ArchiveDetails struct {
|
2020-08-24 00:52:46 +00:00
|
|
|
Checksum string `json:"checksum"`
|
|
|
|
ChecksumType string `json:"checksum_type"`
|
|
|
|
Size int64 `json:"size"`
|
2020-04-26 23:21:58 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 22:02:02 +00:00
|
|
|
// Returns a request object.
|
|
|
|
func (ad *ArchiveDetails) ToRequest(successful bool) api.BackupRequest {
|
|
|
|
return api.BackupRequest{
|
2020-08-24 00:52:46 +00:00
|
|
|
Checksum: ad.Checksum,
|
|
|
|
ChecksumType: ad.ChecksumType,
|
|
|
|
Size: ad.Size,
|
|
|
|
Successful: successful,
|
2020-04-26 23:21:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-02 22:02:02 +00:00
|
|
|
type Backup struct {
|
|
|
|
// The UUID of this backup object. This must line up with a backup from
|
|
|
|
// the panel instance.
|
|
|
|
Uuid string `json:"uuid"`
|
2020-04-26 23:43:18 +00:00
|
|
|
|
2020-05-02 22:02:02 +00:00
|
|
|
// An array of files to ignore when generating this backup. This should be
|
|
|
|
// compatible with a standard .gitignore structure.
|
|
|
|
IgnoredFiles []string `json:"ignored_files"`
|
2020-04-26 23:43:18 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 22:02:02 +00:00
|
|
|
// noinspection GoNameStartsWithPackageName
|
|
|
|
type BackupInterface interface {
|
2020-04-17 20:46:36 +00:00
|
|
|
// Returns the UUID of this backup as tracked by the panel instance.
|
|
|
|
Identifier() string
|
2020-04-14 05:01:07 +00:00
|
|
|
|
2020-04-17 20:46:36 +00:00
|
|
|
// Generates a backup in whatever the configured source for the specific
|
|
|
|
// implementation is.
|
2020-05-10 02:24:30 +00:00
|
|
|
Generate(*IncludedFiles, string) (*ArchiveDetails, error)
|
2020-04-17 20:46:36 +00:00
|
|
|
|
2020-04-26 23:43:18 +00:00
|
|
|
// Returns the ignored files for this backup instance.
|
|
|
|
Ignored() []string
|
|
|
|
|
2020-04-17 20:46:36 +00:00
|
|
|
// Returns a SHA256 checksum for the generated backup.
|
|
|
|
Checksum() ([]byte, error)
|
|
|
|
|
|
|
|
// Returns the size of the generated backup.
|
|
|
|
Size() (int64, error)
|
|
|
|
|
|
|
|
// Returns the path to the backup on the machine. This is not always the final
|
|
|
|
// storage location of the backup, simply the location we're using to store
|
|
|
|
// it until it is moved to the final spot.
|
|
|
|
Path() string
|
|
|
|
|
|
|
|
// Returns details about the archive.
|
|
|
|
Details() *ArchiveDetails
|
2020-04-26 23:43:18 +00:00
|
|
|
|
|
|
|
// Removes a backup file.
|
|
|
|
Remove() error
|
2020-04-14 05:01:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 22:02:02 +00:00
|
|
|
func (b *Backup) Identifier() string {
|
|
|
|
return b.Uuid
|
2020-04-14 05:01:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 22:02:02 +00:00
|
|
|
// Returns the path for this specific backup.
|
|
|
|
func (b *Backup) Path() string {
|
|
|
|
return path.Join(config.Get().System.BackupDirectory, b.Identifier()+".tar.gz")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the size of the generated backup.
|
|
|
|
func (b *Backup) Size() (int64, error) {
|
|
|
|
st, err := os.Stat(b.Path())
|
|
|
|
if err != nil {
|
2020-11-28 23:57:10 +00:00
|
|
|
return 0, err
|
2020-04-14 05:01:07 +00:00
|
|
|
}
|
2020-05-02 22:02:02 +00:00
|
|
|
|
|
|
|
return st.Size(), nil
|
2020-04-26 23:21:58 +00:00
|
|
|
}
|
2020-05-02 22:02:02 +00:00
|
|
|
|
|
|
|
// Returns the SHA256 checksum of a backup.
|
|
|
|
func (b *Backup) Checksum() ([]byte, error) {
|
2020-08-24 00:34:48 +00:00
|
|
|
h := sha1.New()
|
2020-05-02 22:02:02 +00:00
|
|
|
|
|
|
|
f, err := os.Open(b.Path())
|
|
|
|
if err != nil {
|
2020-11-28 23:57:10 +00:00
|
|
|
return nil, err
|
2020-05-02 22:02:02 +00:00
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
2020-08-24 00:18:40 +00:00
|
|
|
buf := make([]byte, 1024*4)
|
|
|
|
if _, err := io.CopyBuffer(h, f, buf); err != nil {
|
|
|
|
return nil, err
|
2020-05-02 22:02:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return h.Sum(nil), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns details of the archive by utilizing two go-routines to get the checksum and
|
|
|
|
// the size of the archive.
|
|
|
|
func (b *Backup) Details() *ArchiveDetails {
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(2)
|
|
|
|
|
|
|
|
var checksum string
|
|
|
|
// Calculate the checksum for the file.
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
|
resp, err := b.Checksum()
|
|
|
|
if err != nil {
|
2020-06-13 17:40:26 +00:00
|
|
|
log.WithFields(log.Fields{
|
|
|
|
"backup": b.Identifier(),
|
2020-08-24 00:18:40 +00:00
|
|
|
"error": err,
|
2020-06-13 17:40:26 +00:00
|
|
|
}).Error("failed to calculate checksum for backup")
|
2020-11-28 23:57:10 +00:00
|
|
|
return
|
2020-05-02 22:02:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
checksum = hex.EncodeToString(resp)
|
|
|
|
}()
|
|
|
|
|
|
|
|
var sz int64
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
|
if s, err := b.Size(); err != nil {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
sz = s
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
return &ArchiveDetails{
|
2020-08-24 00:52:46 +00:00
|
|
|
Checksum: checksum,
|
|
|
|
ChecksumType: "sha1",
|
|
|
|
Size: sz,
|
2020-05-02 22:02:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *Backup) Ignored() []string {
|
|
|
|
return b.IgnoredFiles
|
2020-08-24 00:18:40 +00:00
|
|
|
}
|