forked from pterodactyl/panel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBackupRemoteUploadController.php
More file actions
144 lines (123 loc) · 4.81 KB
/
BackupRemoteUploadController.php
File metadata and controls
144 lines (123 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
133
134
135
136
137
138
139
140
141
142
143
144
<?php
namespace Pterodactyl\Http\Controllers\Api\Remote\Backups;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
use Pterodactyl\Models\Backup;
use Illuminate\Http\JsonResponse;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Extensions\Backups\BackupManager;
use Pterodactyl\Repositories\Eloquent\BackupRepository;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class BackupRemoteUploadController extends Controller
{
const PART_SIZE = 5 * 1024 * 1024 * 1024;
/**
* @var \Pterodactyl\Repositories\Eloquent\BackupRepository
*/
private $repository;
/**
* @var \Pterodactyl\Extensions\Backups\BackupManager
*/
private $backupManager;
/**
* BackupRemoteUploadController 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;
}
/**
* Returns the required presigned urls to upload a backup to S3 cloud storage.
*
* @param \Illuminate\Http\Request $request
* @param string $backup
*
* @return \Illuminate\Http\JsonResponse
*
* @throws \Exception
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function __invoke(Request $request, string $backup)
{
// Get the size query parameter.
$size = $request->query('size', null);
if (is_null($size)) {
throw new BadRequestHttpException('Missing size query parameter.');
}
/** @var \Pterodactyl\Models\Backup $model */
$model = Backup::query()->where([[ 'uuid', '=', $backup ]])->firstOrFail();
// Prevent backups that have already been completed from trying to
// be uploaded again.
if (! is_null($model->completed_at)) {
return new JsonResponse([], JsonResponse::HTTP_CONFLICT);
}
// Ensure we are using the S3 adapter.
$adapter = $this->backupManager->adapter();
if (! $adapter instanceof AwsS3Adapter) {
throw new BadRequestHttpException('Backups are not using the s3 storage driver');
}
// The path where backup will be uploaded to
$path = sprintf('%s/%s.tar.gz', $model->server->uuid, $model->uuid);
// Get the S3 client
$client = $adapter->getClient();
// Params for generating the presigned urls
$params = [
'Bucket' => $adapter->getBucket(),
'Key' => $path,
'ContentType' => 'application/x-gzip',
];
// Execute the CreateMultipartUpload request
$result = $client->execute($client->getCommand('CreateMultipartUpload', $params));
// Get the UploadId from the CreateMultipartUpload request,
// this is needed to create the other presigned urls
$uploadId = $result->get('UploadId');
// Create a CompleteMultipartUpload presigned url
$completeMultipartUpload = $client->createPresignedRequest(
$client->getCommand(
'CompleteMultipartUpload',
array_merge($params, [
'UploadId' => $uploadId,
])
),
CarbonImmutable::now()->addMinutes(30)
);
// Create a AbortMultipartUpload presigned url
$abortMultipartUpload = $client->createPresignedRequest(
$client->getCommand(
'AbortMultipartUpload',
array_merge($params, [
'UploadId' => $uploadId,
])
),
CarbonImmutable::now()->addMinutes(45)
);
// Calculate the number of parts needed to upload the backup
$partCount = (int) $size / (self::PART_SIZE);
// Create as many UploadPart presigned urls as needed
$parts = [];
for ($i = 0; $i < $partCount; $i++) {
$part = $client->createPresignedRequest(
$client->getCommand(
'UploadPart',
array_merge($params, [
'UploadId' => $uploadId,
'PartNumber' => $i + 1,
])
),
CarbonImmutable::now()->addMinutes(30)
);
array_push($parts, $part->getUri()->__toString());
}
return new JsonResponse([
'complete_multipart_upload' => $completeMultipartUpload->getUri()->__toString(),
'abort_multipart_upload' => $abortMultipartUpload->getUri()->__toString(),
'parts' => $parts,
'part_size' => self::PART_SIZE,
]);
}
}