Merge branch 'develop' into feature/react-admin
This commit is contained in:
commit
eb29f6fc04
10 changed files with 201 additions and 196 deletions
|
@ -12,7 +12,7 @@ class PruneOrphanedBackupsCommand extends Command
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'p:maintenance:prune-backups {--since-minutes=30}';
|
protected $signature = 'p:maintenance:prune-backups {--prune-age=}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
|
@ -21,9 +21,9 @@ class PruneOrphanedBackupsCommand extends Command
|
||||||
|
|
||||||
public function handle(BackupRepository $repository)
|
public function handle(BackupRepository $repository)
|
||||||
{
|
{
|
||||||
$since = $this->option('since-minutes');
|
$since = $this->option('prune-age') ?? config('backups.prune_age', 360);
|
||||||
if (!is_digit($since)) {
|
if (!$since || !is_digit($since)) {
|
||||||
throw new InvalidArgumentException('The --since-minutes option must be a valid numeric digit.');
|
throw new InvalidArgumentException('The "--prune-age" argument must be a value greater than 0.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $repository->getBuilder()
|
$query = $repository->getBuilder()
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands\Migration;
|
|
||||||
|
|
||||||
use Pterodactyl\Models\ApiKey;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
|
|
||||||
|
|
||||||
class CleanOrphanedApiKeysCommand extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface
|
|
||||||
*/
|
|
||||||
private $repository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'p:migration:clean-orphaned-keys';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Cleans API keys from the database that are not assigned a specific role.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CleanOrphanedApiKeysCommand constructor.
|
|
||||||
*/
|
|
||||||
public function __construct(ApiKeyRepositoryInterface $repository)
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
|
|
||||||
$this->repository = $repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all orphaned API keys from the database when upgrading from 0.6 to 0.7.
|
|
||||||
*
|
|
||||||
* @return void|null
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$count = $this->repository->findCountWhere([['key_type', '=', ApiKey::TYPE_NONE]]);
|
|
||||||
$continue = $this->confirm(
|
|
||||||
'This action will remove ' . $count . ' keys from the database. Are you sure you wish to continue?',
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$continue) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('Deleting keys...');
|
|
||||||
$this->repository->deleteWhere([['key_type', '=', ApiKey::TYPE_NONE]]);
|
|
||||||
$this->info('Keys were successfully deleted.');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,12 +13,12 @@ class KeyGenerateCommand extends BaseKeyGenerateCommand
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if (!empty(config('app.key')) && $this->input->isInteractive()) {
|
if (!empty(config('app.key')) && $this->input->isInteractive()) {
|
||||||
$this->output->warning(trans('command/messages.key.warning'));
|
$this->output->warning('It appears you have already configured an application encryption key. Continuing with this process with overwrite that key and cause data corruption for any existing encrypted data. DO NOT CONTINUE UNLESS YOU KNOW WHAT YOU ARE DOING.');
|
||||||
if (!$this->confirm(trans('command/messages.key.confirm'))) {
|
if (!$this->confirm('I understand the consequences of performing this command and accept all responsibility for the loss of encrypted data.')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->confirm(trans('command/messages.key.final_confirm'))) {
|
if (!$this->confirm('Are you sure you wish to continue? Changing the application encryption key WILL CAUSE DATA LOSS.')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,17 @@ class SeedCommand extends BaseSeedCommand
|
||||||
use RequiresDatabaseMigrations;
|
use RequiresDatabaseMigrations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block someone from running this seed command if they have not completed the migration
|
* Block someone from running this seed command if they have not completed
|
||||||
* process.
|
* the migration process.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if (!$this->hasCompletedMigrations()) {
|
if (!$this->hasCompletedMigrations()) {
|
||||||
return $this->showMigrationWarning();
|
$this->showMigrationWarning();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::handle();
|
parent::handle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,17 @@ class UpCommand extends BaseUpCommand
|
||||||
use RequiresDatabaseMigrations;
|
use RequiresDatabaseMigrations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool|int
|
* Block someone from running this up command if they have not completed
|
||||||
|
* the migration process.
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if (!$this->hasCompletedMigrations()) {
|
if (!$this->hasCompletedMigrations()) {
|
||||||
return $this->showMigrationWarning();
|
$this->showMigrationWarning();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::handle();
|
parent::handle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Pterodactyl - Panel
|
|
||||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
|
||||||
*
|
|
||||||
* This software is licensed under the terms of the MIT license.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands\Server;
|
|
||||||
|
|
||||||
use Webmozart\Assert\Assert;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use GuzzleHttp\Exception\RequestException;
|
|
||||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
|
||||||
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
|
|
||||||
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
|
|
||||||
|
|
||||||
class BulkReinstallActionCommand extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
|
||||||
*/
|
|
||||||
private $configurationStructureService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \Pterodactyl\Repositories\Wings\DaemonServerRepository
|
|
||||||
*/
|
|
||||||
private $daemonRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \Pterodactyl\Repositories\Eloquent\ServerRepository
|
|
||||||
*/
|
|
||||||
private $repository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Reinstall a single server, all servers on a node, or all servers on the panel.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'p:server:reinstall
|
|
||||||
{server? : The ID of the server to reinstall.}
|
|
||||||
{--node= : ID of the node to reinstall all servers on. Ignored if server is passed.}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BulkReinstallActionCommand constructor.
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
DaemonServerRepository $daemonRepository,
|
|
||||||
ServerConfigurationStructureService $configurationStructureService,
|
|
||||||
ServerRepository $repository
|
|
||||||
) {
|
|
||||||
parent::__construct();
|
|
||||||
|
|
||||||
$this->configurationStructureService = $configurationStructureService;
|
|
||||||
$this->daemonRepository = $daemonRepository;
|
|
||||||
$this->repository = $repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle command execution.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$servers = $this->getServersToProcess();
|
|
||||||
|
|
||||||
if (!$this->confirm(trans('command/messages.server.reinstall.confirm')) && $this->input->isInteractive()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$bar = $this->output->createProgressBar(count($servers));
|
|
||||||
|
|
||||||
$servers->each(function ($server) use ($bar) {
|
|
||||||
$bar->clear();
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->daemonRepository->setServer($server)->reinstall();
|
|
||||||
} catch (RequestException $exception) {
|
|
||||||
$this->output->error(trans('command/messages.server.reinstall.failed', [
|
|
||||||
'name' => $server->name,
|
|
||||||
'id' => $server->id,
|
|
||||||
'node' => $server->node->name,
|
|
||||||
'message' => $exception->getMessage(),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
$bar->advance();
|
|
||||||
$bar->display();
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->line('');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the servers to be reinstalled.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Support\Collection
|
|
||||||
*/
|
|
||||||
private function getServersToProcess()
|
|
||||||
{
|
|
||||||
Assert::nullOrIntegerish($this->argument('server'), 'Value passed in server argument must be null or an integer, received %s.');
|
|
||||||
Assert::nullOrIntegerish($this->option('node'), 'Value passed in node option must be null or integer, received %s.');
|
|
||||||
|
|
||||||
return $this->repository->getDataForReinstall($this->argument('server'), $this->option('node'));
|
|
||||||
}
|
|
||||||
}
|
|
178
app/Console/Commands/UpgradeCommand.php
Normal file
178
app/Console/Commands/UpgradeCommand.php
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Console\Commands;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Pterodactyl\Console\Kernel;
|
||||||
|
use Symfony\Component\Process\Process;
|
||||||
|
use Symfony\Component\Console\Helper\ProgressBar;
|
||||||
|
|
||||||
|
class UpgradeCommand extends Command
|
||||||
|
{
|
||||||
|
protected const DEFAULT_URL = 'https://github.com/pterodactyl/panel/releases/%s/panel.tar.gz';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $signature = 'p:upgrade
|
||||||
|
{--user= : The user that PHP runs under. All files will be owned by this user.}
|
||||||
|
{--url= : The specific archive to download.}
|
||||||
|
{--release= : A specific Pterodactyl version to download from GitHub. Leave blank to use latest.}
|
||||||
|
{--skip-download : If set no archive will be downloaded.}';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $description = 'Downloads a new archive for Pterodactyl from GitHub and then executes the normal upgrade commands.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes an upgrade command which will run through all of our standard
|
||||||
|
* commands for Pterodactyl and enable users to basically just download
|
||||||
|
* the archive and execute this and be done.
|
||||||
|
*
|
||||||
|
* This places the application in maintenance mode as well while the commands
|
||||||
|
* are being executed.
|
||||||
|
*
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$skipDownload = $this->option('skip-download');
|
||||||
|
if (!$skipDownload) {
|
||||||
|
$this->output->warning('This command does not verify the integrity of downloaded assets. Please ensure that you trust the download source before continuing. If you do not wish to download an archive, please indicate that using the --skip-download flag, or answering "no" to the question below.');
|
||||||
|
$this->output->comment('Download Source (set with --url=):');
|
||||||
|
$this->line($this->getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version_compare(PHP_VERSION, '7.4.0') < 0) {
|
||||||
|
$this->error('Cannot execute self-upgrade process. The minimum required PHP version required is 7.4.0, you have [' . PHP_VERSION . '].');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = 'www-data';
|
||||||
|
if ($this->input->isInteractive()) {
|
||||||
|
if (!$skipDownload) {
|
||||||
|
$skipDownload = !$this->confirm('Would you like to download and unpack the archive files for the latest version?', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($this->option('user'))) {
|
||||||
|
$details = posix_getpwuid(fileowner('public'));
|
||||||
|
$user = $details['name'] ?? 'www-data';
|
||||||
|
|
||||||
|
if (!$this->confirm("Your webserver user has been detected as [{$user}]: is this correct?", true)) {
|
||||||
|
$user = $this->anticipate(
|
||||||
|
'Please enter the name of the user running your webserver process. This varies from system to system, but is generally "www-data", "nginx", or "apache".',
|
||||||
|
[
|
||||||
|
'www-data',
|
||||||
|
'apache',
|
||||||
|
'nginx',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->confirm('Are you sure you want to run the upgrade process for your Panel?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_set('output_buffering', 0);
|
||||||
|
$bar = $this->output->createProgressBar($skipDownload ? 9 : 10);
|
||||||
|
$bar->start();
|
||||||
|
|
||||||
|
if (!$skipDownload) {
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line("\$upgrader> curl -L \"{$this->getUrl()}\" | tar -xzv");
|
||||||
|
$process = Process::fromShellCommandline("curl -L \"{$this->getUrl()}\" | tar -xzvf");
|
||||||
|
$process->run(function ($type, $buffer) {
|
||||||
|
$this->{$type === Process::ERR ? 'error' : 'line'}($buffer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line('$upgrader> php artisan down');
|
||||||
|
$this->call('down');
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line('$upgrader> chmod -R 755 storage bootstrap/cache');
|
||||||
|
$process = new Process(['chmod', '-R', '755', 'storage', 'bootstrap/cache']);
|
||||||
|
$process->run(function ($type, $buffer) {
|
||||||
|
$this->{$type === Process::ERR ? 'error' : 'line'}($buffer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$command = ['composer', 'install', '--no-ansi'];
|
||||||
|
if (config('app.env') === 'production' && !config('app.debug')) {
|
||||||
|
$command[] = '--optimize-autoloader';
|
||||||
|
$command[] = '--no-dev';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->line('$upgrader> ' . implode(' ', $command));
|
||||||
|
$process = new Process($command);
|
||||||
|
$process->setTimeout(10 * 60);
|
||||||
|
$process->run(function ($type, $buffer) {
|
||||||
|
$this->line($buffer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @var \Illuminate\Foundation\Application $app */
|
||||||
|
$app = require __DIR__ . '/../../../bootstrap/app.php';
|
||||||
|
/** @var \Pterodactyl\Console\Kernel $kernel */
|
||||||
|
$kernel = $app->make(Kernel::class);
|
||||||
|
$kernel->bootstrap();
|
||||||
|
$this->setLaravel($app);
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line('$upgrader> php artisan view:clear');
|
||||||
|
$this->call('view:clear');
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line('$upgrader> php artisan config:clear');
|
||||||
|
$this->call('config:clear');
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line('$upgrader> php artisan migrate --seed --force');
|
||||||
|
$this->call('migrate', ['--seed' => '', '--force' => '']);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () use ($user) {
|
||||||
|
$this->line("\$upgrader> chown -R {$user}:{$user} *");
|
||||||
|
$process = Process::fromShellCommandline("chown -R {$user}:{$user} *", $this->getLaravel()->basePath());
|
||||||
|
$process->setTimeout(10 * 60);
|
||||||
|
$process->run(function ($type, $buffer) {
|
||||||
|
$this->{$type === Process::ERR ? 'error' : 'line'}($buffer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line('$upgrader> php artisan queue:restart');
|
||||||
|
$this->call('queue:restart');
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->withProgress($bar, function () {
|
||||||
|
$this->line('$upgrader> php artisan up');
|
||||||
|
$this->call('up');
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->newLine();
|
||||||
|
$this->info('Finished running upgrade.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function withProgress(ProgressBar $bar, Closure $callback)
|
||||||
|
{
|
||||||
|
$bar->clear();
|
||||||
|
$callback();
|
||||||
|
$bar->advance();
|
||||||
|
$bar->display();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getUrl(): string
|
||||||
|
{
|
||||||
|
if ($this->option('url')) {
|
||||||
|
return $this->option('url');
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(self::DEFAULT_URL, $this->option('release') ? 'download/v' . $this->option('release') : 'latest/download');
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,12 +23,9 @@ class Kernel extends ConsoleKernel
|
||||||
// Execute scheduled commands for servers every minute, as if there was a normal cron running.
|
// Execute scheduled commands for servers every minute, as if there was a normal cron running.
|
||||||
$schedule->command('p:schedule:process')->everyMinute()->withoutOverlapping();
|
$schedule->command('p:schedule:process')->everyMinute()->withoutOverlapping();
|
||||||
|
|
||||||
|
if (config('backups.prune_age')) {
|
||||||
// Every 30 minutes, run the backup pruning command so that any abandoned backups can be deleted.
|
// Every 30 minutes, run the backup pruning command so that any abandoned backups can be deleted.
|
||||||
$pruneAge = config('backups.prune_age', 360); // Defaults to 6 hours (time is in minuteS)
|
$schedule->command('p:maintenance:prune-backups')->everyThirtyMinutes();
|
||||||
if ($pruneAge > 0) {
|
|
||||||
$schedule->command('p:maintenance:prune-backups', [
|
|
||||||
'--since-minutes' => $pruneAge,
|
|
||||||
])->everyThirtyMinutes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every day cleanup any internal backups of service files.
|
// Every day cleanup any internal backups of service files.
|
||||||
|
|
|
@ -33,7 +33,7 @@ trait RequiresDatabaseMigrations
|
||||||
* them to properly run the migrations rather than ignoring all of the other previous
|
* them to properly run the migrations rather than ignoring all of the other previous
|
||||||
* errors...
|
* errors...
|
||||||
*/
|
*/
|
||||||
protected function showMigrationWarning(): int
|
protected function showMigrationWarning()
|
||||||
{
|
{
|
||||||
$this->getOutput()->writeln('<options=bold>
|
$this->getOutput()->writeln('<options=bold>
|
||||||
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
|
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
|
||||||
|
@ -51,7 +51,5 @@ database state by running the command above.
|
||||||
');
|
');
|
||||||
|
|
||||||
$this->getOutput()->error('You must correct the error above before continuing.');
|
$this->getOutput()->error('You must correct the error above before continuing.');
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'key' => [
|
|
||||||
'warning' => 'It appears you have already configured an application encryption key. Continuing with this process with overwrite that key and cause data corruption for any existing encrypted data. DO NOT CONTINUE UNLESS YOU KNOW WHAT YOU ARE DOING.',
|
|
||||||
'confirm' => 'I understand the consequences of performing this command and accept all responsibility for the loss of encrypted data.',
|
|
||||||
'final_confirm' => 'Are you sure you wish to continue? Changing the application encryption key WILL CAUSE DATA LOSS.',
|
|
||||||
],
|
|
||||||
'location' => [
|
'location' => [
|
||||||
'no_location_found' => 'Could not locate a record matching the provided short code.',
|
'no_location_found' => 'Could not locate a record matching the provided short code.',
|
||||||
'ask_short' => 'Location Short Code',
|
'ask_short' => 'Location Short Code',
|
||||||
|
|
Loading…
Reference in a new issue