Add more CLI commands for panel management
This commit is contained in:
parent
763f7a996a
commit
ccda2b63fa
|
@ -1,110 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Pterodactyl - Panel
|
|
||||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Pterodactyl\Models\Location;
|
|
||||||
use Pterodactyl\Repositories\NodeRepository;
|
|
||||||
|
|
||||||
class AddNode extends Command
|
|
||||||
{
|
|
||||||
protected $data = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'pterodactyl:node
|
|
||||||
{--name= : Name of the node.}
|
|
||||||
{--location= : The shortcode of the location to add this node to.}
|
|
||||||
{--fqdn= : The fully-qualified domain for the node.}
|
|
||||||
{--ssl= : Should the daemon use SSL for connections (T/F).}
|
|
||||||
{--memory= : The total memory available on this node for servers.}
|
|
||||||
{--disk= : The total disk space available on this node for servers.}
|
|
||||||
{--daemonBase= : The directory in which server files will be stored.}
|
|
||||||
{--daemonListen= : The port the daemon will listen on for connections.}
|
|
||||||
{--daemonSFTP= : The port to be used for SFTP conncetions to the daemon.}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Adds a new node to the system via the CLI.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$locations = Location::all(['id', 'short', 'long']);
|
|
||||||
|
|
||||||
$this->data['name'] = (is_null($this->option('name'))) ? $this->ask('Node Name') : $this->option('name');
|
|
||||||
|
|
||||||
if (is_null($this->option('location'))) {
|
|
||||||
$this->table(['ID', 'Short Code', 'Description'], $locations->toArray());
|
|
||||||
$selectedLocation = $this->anticipate('Node Location (Short Name)', $locations->pluck('short')->toArray());
|
|
||||||
} else {
|
|
||||||
$selectedLocation = $this->option('location');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->data['location_id'] = $locations->where('short', $selectedLocation)->first()->id;
|
|
||||||
|
|
||||||
if (is_null($this->option('fqdn'))) {
|
|
||||||
$this->line('Please enter domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node.');
|
|
||||||
$this->data['fqdn'] = $this->ask('Fully Qualified Domain Name');
|
|
||||||
} else {
|
|
||||||
$this->data['fqdn'] = $this->option('fqdn');
|
|
||||||
}
|
|
||||||
|
|
||||||
$useSSL = (is_null($this->option('ssl'))) ? $this->confirm('Use SSL', true) : $this->option('ssl');
|
|
||||||
|
|
||||||
$this->data['scheme'] = ($useSSL) ? 'https' : 'http';
|
|
||||||
$this->data['memory'] = (is_null($this->option('memory'))) ? $this->ask('Total Memory (in MB)') : $this->option('memory');
|
|
||||||
$this->data['memory_overallocate'] = 0;
|
|
||||||
$this->data['disk'] = (is_null($this->option('disk'))) ? $this->ask('Total Disk Space (in MB)') : $this->option('disk');
|
|
||||||
$this->data['disk_overallocate'] = 0;
|
|
||||||
$this->data['public'] = 1;
|
|
||||||
$this->data['daemonBase'] = (is_null($this->option('daemonBase'))) ? $this->ask('Daemon Server File Location', '/srv/daemon-data') : $this->option('daemonBase');
|
|
||||||
$this->data['daemonListen'] = (is_null($this->option('daemonListen'))) ? $this->ask('Daemon Listening Port', 8080) : $this->option('daemonListen');
|
|
||||||
$this->data['daemonSFTP'] = (is_null($this->option('daemonSFTP'))) ? $this->ask('Daemon SFTP Port', 2022) : $this->option('daemonSFTP');
|
|
||||||
|
|
||||||
$repo = new NodeRepository;
|
|
||||||
$id = $repo->create($this->data);
|
|
||||||
|
|
||||||
$this->info('Node created with ID: ' . $id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Pterodactyl - Panel
|
|
||||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands;
|
|
||||||
|
|
||||||
use Carbon;
|
|
||||||
use Pterodactyl\Models;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
|
||||||
|
|
||||||
class ClearTasks extends Command
|
|
||||||
{
|
|
||||||
use DispatchesJobs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'pterodactyl:tasks:clearlog';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Clears old log entires (> 2 months) from the last log.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$entries = Models\TaskLog::where('run_time', '<=', Carbon::now()->subHours(config('pterodactyl.tasks.clear_log'))->toAtomString())->get();
|
|
||||||
|
|
||||||
$this->info(sprintf('Preparing to delete %d old task log entries.', count($entries)));
|
|
||||||
$bar = $this->output->createProgressBar(count($entries));
|
|
||||||
|
|
||||||
foreach ($entries as &$entry) {
|
|
||||||
$entry->delete();
|
|
||||||
$bar->advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
$bar->finish();
|
|
||||||
$this->info("\nFinished deleting old logs.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/*
|
||||||
* Pterodactyl - Panel
|
* Pterodactyl - Panel
|
||||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
*
|
*
|
||||||
|
@ -22,66 +22,61 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands;
|
namespace Pterodactyl\Console\Commands\Maintenance;
|
||||||
|
|
||||||
use DB;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Contracts\Filesystem\Factory as FilesystemFactory;
|
||||||
|
|
||||||
class ClearServices extends Command
|
class CleanServiceBackupFilesCommand extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* @var \Carbon\Carbon
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
*/
|
||||||
protected $signature = 'pterodactyl:clear-services';
|
protected $carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $description = 'Removes all services from the database for installing updated ones as needed.';
|
protected $description = 'Clean orphaned .bak files created when modifying services.';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new command instance.
|
* @var \Illuminate\Contracts\Filesystem\Filesystem
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
protected $disk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'p:maintenance:clean-service-backups';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CleanServiceBackupFilesCommand constructor.
|
||||||
|
*
|
||||||
|
* @param \Carbon\Carbon $carbon
|
||||||
|
* @param \Illuminate\Contracts\Filesystem\Factory $filesystem
|
||||||
|
*/
|
||||||
|
public function __construct(Carbon $carbon, FilesystemFactory $filesystem)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->carbon = $carbon;
|
||||||
|
$this->disk = $filesystem->disk();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Handle command execution.
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if (! $this->confirm('This is a destructive operation, are you sure you wish to continue?')) {
|
$files = $this->disk->files('services/.bak');
|
||||||
$this->error('Canceling.');
|
|
||||||
exit();
|
collect($files)->each(function ($file) {
|
||||||
|
$lastModified = $this->carbon->timestamp($this->disk->lastModified($file));
|
||||||
|
if ($lastModified->diffInMinutes($this->carbon->now()) > 5) {
|
||||||
|
$this->disk->delete($file);
|
||||||
|
$this->info(trans('command/messages.maintenance.deleting_service_backup', ['file' => $file]));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
$bar = $this->output->createProgressBar(3);
|
|
||||||
DB::beginTransaction();
|
|
||||||
|
|
||||||
try {
|
|
||||||
DB::table('services')->truncate();
|
|
||||||
$bar->advance();
|
|
||||||
|
|
||||||
DB::table('service_options')->truncate();
|
|
||||||
$bar->advance();
|
|
||||||
|
|
||||||
DB::table('service_variables')->truncate();
|
|
||||||
$bar->advance();
|
|
||||||
|
|
||||||
DB::commit();
|
|
||||||
} catch (\Exception $ex) {
|
|
||||||
DB::rollBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->info("\n");
|
|
||||||
$this->info('All services have been removed. Consider running `php artisan pterodactyl:service-defaults` at this time.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,144 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Pterodactyl - Panel
|
|
||||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands;
|
|
||||||
|
|
||||||
use Pterodactyl\Models\Node;
|
|
||||||
use Pterodactyl\Models\Server;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
class RebuildServer extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'pterodactyl:rebuild
|
|
||||||
{--all}
|
|
||||||
{--node= : Id of node to rebuild all servers on.}
|
|
||||||
{--server= : UUID of server to rebuild.}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Rebuild docker containers for a server or multiple servers.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
if ($this->option('all')) {
|
|
||||||
$servers = Server::all();
|
|
||||||
} elseif ($this->option('node')) {
|
|
||||||
$servers = Server::where('node_id', $this->option('node'))->get();
|
|
||||||
} elseif ($this->option('server')) {
|
|
||||||
$servers = Server::where('id', $this->option('server'))->get();
|
|
||||||
} else {
|
|
||||||
$this->error('You must pass a flag to determine which server(s) to rebuild.');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$servers->load('node', 'service', 'option.variables', 'pack');
|
|
||||||
|
|
||||||
$this->line('Beginning processing, do not exit this script.');
|
|
||||||
$bar = $this->output->createProgressBar(count($servers));
|
|
||||||
$results = collect([]);
|
|
||||||
foreach ($servers as $server) {
|
|
||||||
try {
|
|
||||||
$environment = $server->option->variables->map(function ($item, $key) use ($server) {
|
|
||||||
$display = $server->variables->where('variable_id', $item->id)->pluck('variable_value')->first();
|
|
||||||
|
|
||||||
return [
|
|
||||||
'variable' => $item->env_variable,
|
|
||||||
'value' => (! is_null($display)) ? $display : $item->default_value,
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
$server->node->guzzleClient([
|
|
||||||
'X-Access-Server' => $server->uuid,
|
|
||||||
'X-Access-Token' => $server->node->daemonSecret,
|
|
||||||
])->request('PATCH', '/server', [
|
|
||||||
'json' => [
|
|
||||||
'build' => [
|
|
||||||
'image' => $server->image,
|
|
||||||
'env|overwrite' => $environment->pluck('value', 'variable')->merge(['STARTUP' => $server->startup]),
|
|
||||||
],
|
|
||||||
'service' => [
|
|
||||||
'type' => $server->service->folder,
|
|
||||||
'option' => $server->option->tag,
|
|
||||||
'pack' => ! is_null($server->pack) ? $server->pack->uuid : null,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$results = $results->merge([
|
|
||||||
$server->uuid => [
|
|
||||||
'status' => 'info',
|
|
||||||
'messages' => [
|
|
||||||
'[✓] Processed rebuild request for ' . $server->uuid,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
} catch (\Exception $ex) {
|
|
||||||
$results = $results->merge([
|
|
||||||
$server->uuid => [
|
|
||||||
'status' => 'error',
|
|
||||||
'messages' => [
|
|
||||||
'[✗] Failed to process rebuild request for ' . $server->uuid,
|
|
||||||
$ex->getMessage(),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$bar->advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
$bar->finish();
|
|
||||||
$console = $this;
|
|
||||||
|
|
||||||
$this->line("\n");
|
|
||||||
$results->each(function ($item, $key) use ($console) {
|
|
||||||
foreach ($item['messages'] as $line) {
|
|
||||||
$console->{$item['status']}($line);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$this->line("\nCompleted rebuild command processing.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Pterodactyl - Panel
|
|
||||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands;
|
|
||||||
|
|
||||||
use Carbon;
|
|
||||||
use Pterodactyl\Models\Task;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Pterodactyl\Jobs\SendScheduledTask;
|
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
|
||||||
|
|
||||||
class RunTasks extends Command
|
|
||||||
{
|
|
||||||
use DispatchesJobs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'pterodactyl:tasks';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Find and run scheduled tasks.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$tasks = Task::where('queued', false)->where('active', true)->where('next_run', '<=', Carbon::now()->toAtomString())->get();
|
|
||||||
|
|
||||||
$this->info(sprintf('Preparing to queue %d tasks.', count($tasks)));
|
|
||||||
$bar = $this->output->createProgressBar(count($tasks));
|
|
||||||
|
|
||||||
foreach ($tasks as &$task) {
|
|
||||||
$bar->advance();
|
|
||||||
$this->dispatch((new SendScheduledTask($task))->onQueue(config('pterodactyl.queues.low')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$bar->finish();
|
|
||||||
$this->info("\nFinished queuing tasks for running.");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -87,23 +87,22 @@ class ProcessRunnableCommand extends Command
|
||||||
$schedules = $this->repository->getSchedulesToProcess($this->carbon->now()->toAtomString());
|
$schedules = $this->repository->getSchedulesToProcess($this->carbon->now()->toAtomString());
|
||||||
|
|
||||||
$bar = $this->output->createProgressBar(count($schedules));
|
$bar = $this->output->createProgressBar(count($schedules));
|
||||||
foreach ($schedules as $schedule) {
|
$schedules->each(function ($schedule) use ($bar) {
|
||||||
if (! $schedule->tasks instanceof Collection || count($schedule->tasks) < 1) {
|
if ($schedule->tasks instanceof Collection && count($schedule->tasks) > 0) {
|
||||||
$bar->advance();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->processScheduleService->handle($schedule);
|
$this->processScheduleService->handle($schedule);
|
||||||
|
|
||||||
if ($this->input->isInteractive()) {
|
if ($this->input->isInteractive()) {
|
||||||
|
$bar->clear();
|
||||||
$this->line(trans('command/messages.schedule.output_line', [
|
$this->line(trans('command/messages.schedule.output_line', [
|
||||||
'schedule' => $schedule->name,
|
'schedule' => $schedule->name,
|
||||||
'hash' => $schedule->hashid,
|
'hash' => $schedule->hashid,
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$bar->advance();
|
$bar->advance();
|
||||||
}
|
$bar->display();
|
||||||
|
});
|
||||||
|
|
||||||
$this->line('');
|
$this->line('');
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Pterodactyl\Console\Commands\Server;
|
||||||
|
|
||||||
|
use Webmozart\Assert\Assert;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use Pterodactyl\Services\Servers\EnvironmentService;
|
||||||
|
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||||
|
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||||
|
|
||||||
|
class RebuildServerCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $daemonRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Rebuild a single server, all servers on a node, or all servers on the panel.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Services\Servers\EnvironmentService
|
||||||
|
*/
|
||||||
|
protected $environmentService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'p:server:rebuild
|
||||||
|
{server? : The ID of the server to rebuild.}
|
||||||
|
{--node= : ID of the node to rebuild all servers on. Ignored if server is passed.}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RebuildServerCommand constructor.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonRepository
|
||||||
|
* @param \Pterodactyl\Services\Servers\EnvironmentService $environmentService
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
DaemonServerRepositoryInterface $daemonRepository,
|
||||||
|
EnvironmentService $environmentService,
|
||||||
|
ServerRepositoryInterface $repository
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->daemonRepository = $daemonRepository;
|
||||||
|
$this->environmentService = $environmentService;
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle command execution.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$servers = $this->getServersToProcess();
|
||||||
|
$bar = $this->output->createProgressBar(count($servers));
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
$servers->each(function ($server) use ($bar, &$results) {
|
||||||
|
$bar->clear();
|
||||||
|
$json = [
|
||||||
|
'build' => [
|
||||||
|
'image' => $server->image,
|
||||||
|
'env|overwrite' => $this->environmentService->process($server),
|
||||||
|
],
|
||||||
|
'service' => [
|
||||||
|
'type' => $server->option->service->folder,
|
||||||
|
'option' => $server->option->tag,
|
||||||
|
'pack' => object_get($server, 'pack.uuid'),
|
||||||
|
'skip_scripts' => $server->skip_scripts,
|
||||||
|
],
|
||||||
|
'rebuild' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->daemonRepository->setNode($server->node_id)
|
||||||
|
->setAccessServer($server->uuid)
|
||||||
|
->setAccessToken($server->node->daemonSecret)
|
||||||
|
->update($json);
|
||||||
|
} catch (RequestException $exception) {
|
||||||
|
$this->output->error(trans('command/messages.server.rebuild_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 rebuilt.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\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->getDataForRebuild($this->argument('server'), $this->option('node'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,10 +7,12 @@ use Pterodactyl\Console\Commands\InfoCommand;
|
||||||
use Pterodactyl\Console\Commands\User\MakeUserCommand;
|
use Pterodactyl\Console\Commands\User\MakeUserCommand;
|
||||||
use Pterodactyl\Console\Commands\User\DeleteUserCommand;
|
use Pterodactyl\Console\Commands\User\DeleteUserCommand;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
use Pterodactyl\Console\Commands\Server\RebuildServerCommand;
|
||||||
use Pterodactyl\Console\Commands\Location\MakeLocationCommand;
|
use Pterodactyl\Console\Commands\Location\MakeLocationCommand;
|
||||||
use Pterodactyl\Console\Commands\User\DisableTwoFactorCommand;
|
use Pterodactyl\Console\Commands\User\DisableTwoFactorCommand;
|
||||||
use Pterodactyl\Console\Commands\Location\DeleteLocationCommand;
|
use Pterodactyl\Console\Commands\Location\DeleteLocationCommand;
|
||||||
use Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand;
|
use Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand;
|
||||||
|
use Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
|
||||||
|
|
||||||
class Kernel extends ConsoleKernel
|
class Kernel extends ConsoleKernel
|
||||||
{
|
{
|
||||||
|
@ -20,6 +22,7 @@ class Kernel extends ConsoleKernel
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $commands = [
|
protected $commands = [
|
||||||
|
CleanServiceBackupFilesCommand::class,
|
||||||
DeleteLocationCommand::class,
|
DeleteLocationCommand::class,
|
||||||
DeleteUserCommand::class,
|
DeleteUserCommand::class,
|
||||||
DisableTwoFactorCommand::class,
|
DisableTwoFactorCommand::class,
|
||||||
|
@ -27,6 +30,7 @@ class Kernel extends ConsoleKernel
|
||||||
MakeLocationCommand::class,
|
MakeLocationCommand::class,
|
||||||
MakeUserCommand::class,
|
MakeUserCommand::class,
|
||||||
ProcessRunnableCommand::class,
|
ProcessRunnableCommand::class,
|
||||||
|
RebuildServerCommand::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,8 +40,7 @@ class Kernel extends ConsoleKernel
|
||||||
*/
|
*/
|
||||||
protected function schedule(Schedule $schedule)
|
protected function schedule(Schedule $schedule)
|
||||||
{
|
{
|
||||||
// $schedule->command('pterodactyl:tasks')->everyMinute()->withoutOverlapping();
|
$schedule->command('p:process:runnable')->everyMinute()->withoutOverlapping();
|
||||||
// $schedule->command('pterodactyl:tasks:clearlog')->twiceDaily(3, 15);
|
$schedule->command('p:maintenance:clean-service-backups')->daily();
|
||||||
// $schedule->command('pterodactyl:cleanservices')->twiceDaily(1, 13);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,20 @@ interface ServerRepositoryInterface extends RepositoryInterface, SearchableInter
|
||||||
/**
|
/**
|
||||||
* Returns a listing of all servers that exist including relationships.
|
* Returns a listing of all servers that exist including relationships.
|
||||||
*
|
*
|
||||||
* @param int $paginate
|
* @param int|null $paginate
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getAllServers($paginate);
|
public function getAllServers($paginate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a collection of servers with their associated data for rebuild operations.
|
||||||
|
*
|
||||||
|
* @param int|null $server
|
||||||
|
* @param int|null $node
|
||||||
|
* @return \Illuminate\Database\Eloquent\Collection
|
||||||
|
*/
|
||||||
|
public function getDataForRebuild($server = null, $node = null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a server model and all variables associated with the server.
|
* Return a server model and all variables associated with the server.
|
||||||
*
|
*
|
||||||
|
|
|
@ -47,13 +47,30 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
|
||||||
*/
|
*/
|
||||||
public function getAllServers($paginate = 25)
|
public function getAllServers($paginate = 25)
|
||||||
{
|
{
|
||||||
$instance = $this->getBuilder()->with('node', 'user', 'allocation');
|
Assert::nullOrIntegerish($paginate, 'First argument passed to getAllServers must be integer or null, received %s.');
|
||||||
|
|
||||||
if ($this->searchTerm) {
|
$instance = $this->getBuilder()->with('node', 'user', 'allocation')->search($this->searchTerm);
|
||||||
$instance->search($this->searchTerm);
|
|
||||||
|
return is_null($paginate) ? $instance->get($this->getColumns()) : $instance->paginate($paginate, $this->getColumns());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $instance->paginate($paginate);
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDataForRebuild($server = null, $node = null)
|
||||||
|
{
|
||||||
|
Assert::nullOrIntegerish($server, 'First argument passed to getDataForRebuild must be null or integer, received %s.');
|
||||||
|
Assert::nullOrIntegerish($node, 'Second argument passed to getDataForRebuild must be null or integer, received %s.');
|
||||||
|
|
||||||
|
$instance = $this->getBuilder()->with('node', 'option.service', 'pack');
|
||||||
|
|
||||||
|
if (! is_null($server) && is_null($node)) {
|
||||||
|
$instance = $instance->where('id', '=', $server);
|
||||||
|
} elseif (is_null($server) && ! is_null($node)) {
|
||||||
|
$instance = $instance->where('node_id', '=', $node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $instance->get($this->getColumns());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,6 +79,8 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
|
||||||
*/
|
*/
|
||||||
public function findWithVariables($id)
|
public function findWithVariables($id)
|
||||||
{
|
{
|
||||||
|
Assert::integerish($id, 'First argument passed to findWithVariables must be integer, received %s.');
|
||||||
|
|
||||||
$instance = $this->getBuilder()->with('option.variables', 'variables')
|
$instance = $this->getBuilder()->with('option.variables', 'variables')
|
||||||
->where($this->getModel()->getKeyName(), '=', $id)
|
->where($this->getModel()->getKeyName(), '=', $id)
|
||||||
->first($this->getColumns());
|
->first($this->getColumns());
|
||||||
|
|
|
@ -76,16 +76,12 @@ class EnvironmentService
|
||||||
*
|
*
|
||||||
* @param int|\Pterodactyl\Models\Server $server
|
* @param int|\Pterodactyl\Models\Server $server
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
*/
|
*/
|
||||||
public function process($server)
|
public function process($server)
|
||||||
{
|
{
|
||||||
if (! $server instanceof Server) {
|
if (! $server instanceof Server) {
|
||||||
if (! is_numeric($server)) {
|
|
||||||
throw new \InvalidArgumentException(
|
|
||||||
'First argument passed to process() must be an instance of \\Pterodactyl\\Models\\Server or numeric.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$server = $this->repository->find($server);
|
$server = $this->repository->find($server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,4 +54,10 @@ return [
|
||||||
'schedule' => [
|
'schedule' => [
|
||||||
'output_line' => 'Dispatching job for first task in `:schedule` (:hash).',
|
'output_line' => 'Dispatching job for first task in `:schedule` (:hash).',
|
||||||
],
|
],
|
||||||
|
'maintenance' => [
|
||||||
|
'deleting_service_backup' => 'Deleting service backup file :file.',
|
||||||
|
],
|
||||||
|
'server' => [
|
||||||
|
'rebuild_failed' => 'Rebuild request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/*
|
||||||
* Pterodactyl - Panel
|
* Pterodactyl - Panel
|
||||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
*
|
*
|
||||||
|
@ -22,51 +22,34 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Pterodactyl\Console\Commands;
|
namespace Tests\Unit\Commands;
|
||||||
|
|
||||||
use Carbon;
|
use Tests\TestCase;
|
||||||
use Storage;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
|
||||||
class CleanServiceBackup extends Command
|
abstract class CommandTestCase extends TestCase
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* Return the display from running a command.
|
||||||
*
|
*
|
||||||
* @var string
|
* @param \Illuminate\Console\Command $command
|
||||||
|
* @param array $args
|
||||||
|
* @param array $inputs
|
||||||
|
* @param array $opts
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'pterodactyl:cleanservices';
|
protected function runCommand(Command $command, array $args = [], array $inputs = [], array $opts = [])
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Cleans .bak files assocaited with service backups whene editing files through the panel.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
{
|
||||||
parent::__construct();
|
if (! $command->getLaravel() instanceof Application) {
|
||||||
|
$command->setLaravel($this->app);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$response = new CommandTester($command);
|
||||||
* Execute the console command.
|
$response->setInputs($inputs);
|
||||||
*
|
$response->execute($args, $opts);
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$files = Storage::files('services/.bak');
|
|
||||||
|
|
||||||
foreach ($files as $file) {
|
return $response->getDisplay();
|
||||||
$lastModified = Carbon::createFromTimestamp(Storage::lastModified($file));
|
|
||||||
if ($lastModified->diffInMinutes(Carbon::now()) > 5) {
|
|
||||||
$this->info('Deleting ' . $file);
|
|
||||||
Storage::delete($file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tests\Unit\Commands\Maintenance;
|
||||||
|
|
||||||
|
use Mockery as m;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Contracts\Filesystem\Factory;
|
||||||
|
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
use Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
|
||||||
|
|
||||||
|
class CleanServiceBackupFilesCommandTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Carbon\Carbon
|
||||||
|
*/
|
||||||
|
protected $carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand
|
||||||
|
*/
|
||||||
|
protected $command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Illuminate\Contracts\Filesystem\Filesystem
|
||||||
|
*/
|
||||||
|
protected $disk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Illuminate\Contracts\Filesystem\Factory
|
||||||
|
*/
|
||||||
|
protected $filesystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup tests.
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->carbon = m::mock(Carbon::class);
|
||||||
|
$this->disk = m::mock(Filesystem::class);
|
||||||
|
$this->filesystem = m::mock(Factory::class);
|
||||||
|
$this->filesystem->shouldReceive('disk')->withNoArgs()->once()->andReturn($this->disk);
|
||||||
|
|
||||||
|
$this->command = new CleanServiceBackupFilesCommand($this->carbon, $this->filesystem);
|
||||||
|
$this->command->setLaravel($this->app);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a file is deleted if it is > 5min old.
|
||||||
|
*/
|
||||||
|
public function testCommandCleansFilesMoreThan5MinutesOld()
|
||||||
|
{
|
||||||
|
$this->disk->shouldReceive('files')->with('services/.bak')->once()->andReturn(['testfile.txt']);
|
||||||
|
$this->disk->shouldReceive('lastModified')->with('testfile.txt')->once()->andReturn('disk:last:modified');
|
||||||
|
$this->carbon->shouldReceive('timestamp')->with('disk:last:modified')->once()->andReturnSelf();
|
||||||
|
$this->carbon->shouldReceive('now')->withNoArgs()->once()->andReturnNull();
|
||||||
|
$this->carbon->shouldReceive('diffInMinutes')->with(null)->once()->andReturn(10);
|
||||||
|
$this->disk->shouldReceive('delete')->with('testfile.txt')->once()->andReturnNull();
|
||||||
|
|
||||||
|
$response = new CommandTester($this->command);
|
||||||
|
$response->execute([]);
|
||||||
|
|
||||||
|
$display = $response->getDisplay();
|
||||||
|
$this->assertNotEmpty($display);
|
||||||
|
$this->assertContains(trans('command/messages.maintenance.deleting_service_backup', ['file' => 'testfile.txt']), $display);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a file isn't deleted if it is < 5min old.
|
||||||
|
*/
|
||||||
|
public function testCommandDoesNotCleanFileLessThan5MinutesOld()
|
||||||
|
{
|
||||||
|
$this->disk->shouldReceive('files')->with('services/.bak')->once()->andReturn(['testfile.txt']);
|
||||||
|
$this->disk->shouldReceive('lastModified')->with('testfile.txt')->once()->andReturn('disk:last:modified');
|
||||||
|
$this->carbon->shouldReceive('timestamp')->with('disk:last:modified')->once()->andReturnSelf();
|
||||||
|
$this->carbon->shouldReceive('now')->withNoArgs()->once()->andReturnNull();
|
||||||
|
$this->carbon->shouldReceive('diffInMinutes')->with(null)->once()->andReturn(2);
|
||||||
|
|
||||||
|
$response = new CommandTester($this->command);
|
||||||
|
$response->execute([]);
|
||||||
|
|
||||||
|
$display = $response->getDisplay();
|
||||||
|
$this->assertEmpty($display);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Pterodactyl - Panel
|
||||||
|
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tests\Unit\Commands\Schedule;
|
||||||
|
|
||||||
|
use Mockery as m;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Pterodactyl\Models\Task;
|
||||||
|
use Pterodactyl\Models\Schedule;
|
||||||
|
use Tests\Unit\Commands\CommandTestCase;
|
||||||
|
use Pterodactyl\Services\Schedules\ProcessScheduleService;
|
||||||
|
use Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand;
|
||||||
|
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||||
|
|
||||||
|
class ProcessRunnableCommandTest extends CommandTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Carbon\Carbon
|
||||||
|
*/
|
||||||
|
protected $carbon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand
|
||||||
|
*/
|
||||||
|
protected $command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Services\Schedules\ProcessScheduleService
|
||||||
|
*/
|
||||||
|
protected $processScheduleService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
|
||||||
|
*/
|
||||||
|
protected $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup tests.
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->carbon = m::mock(Carbon::class);
|
||||||
|
$this->processScheduleService = m::mock(ProcessScheduleService::class);
|
||||||
|
$this->repository = m::mock(ScheduleRepositoryInterface::class);
|
||||||
|
|
||||||
|
$this->command = new ProcessRunnableCommand($this->carbon, $this->processScheduleService, $this->repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a schedule can be queued up correctly.
|
||||||
|
*/
|
||||||
|
public function testScheduleIsQueued()
|
||||||
|
{
|
||||||
|
$schedule = factory(Schedule::class)->make();
|
||||||
|
$schedule->tasks = collect([factory(Task::class)->make()]);
|
||||||
|
|
||||||
|
$this->carbon->shouldReceive('now')->withNoArgs()->once()->andReturnSelf()
|
||||||
|
->shouldReceive('toAtomString')->withNoArgs()->once()->andReturn('00:00:00');
|
||||||
|
$this->repository->shouldReceive('getSchedulesToProcess')->with('00:00:00')->once()->andReturn(collect([$schedule]));
|
||||||
|
$this->processScheduleService->shouldReceive('handle')->with($schedule)->once()->andReturnNull();
|
||||||
|
|
||||||
|
$display = $this->runCommand($this->command);
|
||||||
|
$this->assertNotEmpty($display);
|
||||||
|
$this->assertContains(trans('command/messages.schedule.output_line', [
|
||||||
|
'schedule' => $schedule->name,
|
||||||
|
'hash' => $schedule->hashid,
|
||||||
|
]), $display);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If tasks is an empty collection, don't process it.
|
||||||
|
*/
|
||||||
|
public function testScheduleWithNoTasksIsNotProcessed()
|
||||||
|
{
|
||||||
|
$schedule = factory(Schedule::class)->make();
|
||||||
|
$schedule->tasks = collect([]);
|
||||||
|
|
||||||
|
$this->carbon->shouldReceive('now')->withNoArgs()->once()->andReturnSelf()
|
||||||
|
->shouldReceive('toAtomString')->withNoArgs()->once()->andReturn('00:00:00');
|
||||||
|
$this->repository->shouldReceive('getSchedulesToProcess')->with('00:00:00')->once()->andReturn(collect([$schedule]));
|
||||||
|
|
||||||
|
$display = $this->runCommand($this->command);
|
||||||
|
$this->assertNotEmpty($display);
|
||||||
|
$this->assertNotContains(trans('command/messages.schedule.output_line', [
|
||||||
|
'schedule' => $schedule->name,
|
||||||
|
'hash' => $schedule->hashid,
|
||||||
|
]), $display);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If tasks isn't an instance of a collection, don't process it.
|
||||||
|
*/
|
||||||
|
public function testScheduleWithTasksObjectThatIsNotInstanceOfCollectionIsNotProcessed()
|
||||||
|
{
|
||||||
|
$schedule = factory(Schedule::class)->make(['tasks' => null]);
|
||||||
|
|
||||||
|
$this->carbon->shouldReceive('now')->withNoArgs()->once()->andReturnSelf()
|
||||||
|
->shouldReceive('toAtomString')->withNoArgs()->once()->andReturn('00:00:00');
|
||||||
|
$this->repository->shouldReceive('getSchedulesToProcess')->with('00:00:00')->once()->andReturn(collect([$schedule]));
|
||||||
|
|
||||||
|
$display = $this->runCommand($this->command);
|
||||||
|
$this->assertNotEmpty($display);
|
||||||
|
$this->assertNotContains(trans('command/messages.schedule.output_line', [
|
||||||
|
'schedule' => $schedule->name,
|
||||||
|
'hash' => $schedule->hashid,
|
||||||
|
]), $display);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue