forked from pterodactyl/panel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBackupStatusController.php
More file actions
132 lines (114 loc) · 4.81 KB
/
BackupStatusController.php
File metadata and controls
132 lines (114 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php
namespace Pterodactyl\Http\Controllers\Api\Remote\Backups;
use Carbon\CarbonImmutable;
use Pterodactyl\Models\Backup;
use Pterodactyl\Models\AuditLog;
use Illuminate\Http\JsonResponse;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Extensions\Backups\BackupManager;
use Pterodactyl\Repositories\Eloquent\BackupRepository;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Pterodactyl\Http\Requests\Api\Remote\ReportBackupCompleteRequest;
class BackupStatusController extends Controller
{
/**
* @var \Pterodactyl\Repositories\Eloquent\BackupRepository
*/
private $repository;
/**
* @var \Pterodactyl\Extensions\Backups\BackupManager
*/
private $backupManager;
/**
* BackupStatusController constructor.
*
* @param \Pterodactyl\Repositories\Eloquent\BackupRepository $repository
* @param \Pterodactyl\Extensions\Backups\BackupManager $backupManager
*/
public function __construct(BackupRepository $repository, BackupManager $backupManager)
{
$this->repository = $repository;
$this->backupManager = $backupManager;
}
/**
* Handles updating the state of a backup.
*
* @param \Pterodactyl\Http\Requests\Api\Remote\ReportBackupCompleteRequest $request
* @param string $backup
* @return \Illuminate\Http\JsonResponse
*
* @throws \Throwable
*/
public function __invoke(ReportBackupCompleteRequest $request, string $backup)
{
/** @var \Pterodactyl\Models\Backup $model */
$model = Backup::query()->where('uuid', $backup)->firstOrFail();
if (! is_null($model->completed_at)) {
throw new BadRequestHttpException(
'Cannot update the status of a backup that is already marked as completed.'
);
}
$action = $request->input('successful')
? AuditLog::ACTION_SERVER_BACKUP_COMPELTED
: AuditLog::ACTION_SERVER_BACKUP_FAILED;
$model->server->audit($action, function (AuditLog $audit) use ($model, $request) {
$audit->metadata = ['backup_uuid' => $model->uuid];
$successful = $request->input('successful') ? true : false;
$model->fill([
'is_successful' => $successful,
'checksum' => $successful ? ($request->input('checksum_type') . ':' . $request->input('checksum')) : null,
'bytes' => $successful ? $request->input('size') : 0,
'completed_at' => CarbonImmutable::now(),
])->save();
// Check if we are using the s3 backup adapter. If so, make sure we mark the backup as
// being completed in S3 correctly.
$adapter = $this->backupManager->adapter();
if ($adapter instanceof AwsS3Adapter) {
$this->completeMultipartUpload($model, $adapter, $successful);
}
});
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
}
/**
* Marks a multipart upload in a given S3-compatiable instance as failed or successful for
* the given backup.
*
* @param \Pterodactyl\Models\Backup $backup
* @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter
* @param bool $successful
*
* @throws \Exception
* @throws \Pterodactyl\Exceptions\DisplayException
*/
protected function completeMultipartUpload(Backup $backup, AwsS3Adapter $adapter, bool $successful)
{
// This should never really happen, but if it does don't let us fall victim to Amazon's
// wildly fun error messaging. Just stop the process right here.
if (empty($backup->upload_id)) {
// A failed backup doesn't need to error here, this can happen if the backup encouters
// an error before we even start the upload. AWS gives you tooling to clear these failed
// multipart uploads as needed too.
if (! $successful) {
return;
}
throw new DisplayException('Cannot complete backup request: no upload_id present on model.');
}
$params = [
'Bucket' => $adapter->getBucket(),
'Key' => sprintf('%s/%s.tar.gz', $backup->server->uuid, $backup->uuid),
'UploadId' => $backup->upload_id,
];
$client = $adapter->getClient();
if (! $successful) {
$client->execute($client->getCommand('AbortMultipartUpload', $params));
return;
}
// Otherwise send a CompleteMultipartUpload request.
$params['MultipartUpload'] = [
'Parts' => $client->execute($client->getCommand('ListParts', $params))['Parts'],
];
$client->execute($client->getCommand('CompleteMultipartUpload', $params));
}
}