Add more CLI commands for panel management
This commit is contained in:
parent
763f7a996a
commit
ccda2b63fa
15 changed files with 496 additions and 516 deletions
|
@ -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
|
||||
/**
|
||||
/*
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
|
@ -22,66 +22,61 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Console\Commands;
|
||||
namespace Pterodactyl\Console\Commands\Maintenance;
|
||||
|
||||
use DB;
|
||||
use Carbon\Carbon;
|
||||
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 string
|
||||
* @var \Carbon\Carbon
|
||||
*/
|
||||
protected $signature = 'pterodactyl:clear-services';
|
||||
protected $carbon;
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @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();
|
||||
|
||||
$this->carbon = $carbon;
|
||||
$this->disk = $filesystem->disk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (! $this->confirm('This is a destructive operation, are you sure you wish to continue?')) {
|
||||
$this->error('Canceling.');
|
||||
exit();
|
||||
$files = $this->disk->files('services/.bak');
|
||||
|
||||
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());
|
||||
|
||||
$bar = $this->output->createProgressBar(count($schedules));
|
||||
foreach ($schedules as $schedule) {
|
||||
if (! $schedule->tasks instanceof Collection || count($schedule->tasks) < 1) {
|
||||
$bar->advance();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$schedules->each(function ($schedule) use ($bar) {
|
||||
if ($schedule->tasks instanceof Collection && count($schedule->tasks) > 0) {
|
||||
$this->processScheduleService->handle($schedule);
|
||||
|
||||
if ($this->input->isInteractive()) {
|
||||
$bar->clear();
|
||||
$this->line(trans('command/messages.schedule.output_line', [
|
||||
'schedule' => $schedule->name,
|
||||
'hash' => $schedule->hashid,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
$bar->advance();
|
||||
}
|
||||
$bar->display();
|
||||
});
|
||||
|
||||
$this->line('');
|
||||
}
|
||||
|
|
140
app/Console/Commands/Server/RebuildServerCommand.php
Normal file
140
app/Console/Commands/Server/RebuildServerCommand.php
Normal file
|
@ -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\DeleteUserCommand;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
use Pterodactyl\Console\Commands\Server\RebuildServerCommand;
|
||||
use Pterodactyl\Console\Commands\Location\MakeLocationCommand;
|
||||
use Pterodactyl\Console\Commands\User\DisableTwoFactorCommand;
|
||||
use Pterodactyl\Console\Commands\Location\DeleteLocationCommand;
|
||||
use Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand;
|
||||
use Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
|
@ -20,6 +22,7 @@ class Kernel extends ConsoleKernel
|
|||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
CleanServiceBackupFilesCommand::class,
|
||||
DeleteLocationCommand::class,
|
||||
DeleteUserCommand::class,
|
||||
DisableTwoFactorCommand::class,
|
||||
|
@ -27,6 +30,7 @@ class Kernel extends ConsoleKernel
|
|||
MakeLocationCommand::class,
|
||||
MakeUserCommand::class,
|
||||
ProcessRunnableCommand::class,
|
||||
RebuildServerCommand::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -36,8 +40,7 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// $schedule->command('pterodactyl:tasks')->everyMinute()->withoutOverlapping();
|
||||
// $schedule->command('pterodactyl:tasks:clearlog')->twiceDaily(3, 15);
|
||||
// $schedule->command('pterodactyl:cleanservices')->twiceDaily(1, 13);
|
||||
$schedule->command('p:process:runnable')->everyMinute()->withoutOverlapping();
|
||||
$schedule->command('p:maintenance:clean-service-backups')->daily();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,20 @@ interface ServerRepositoryInterface extends RepositoryInterface, SearchableInter
|
|||
/**
|
||||
* Returns a listing of all servers that exist including relationships.
|
||||
*
|
||||
* @param int $paginate
|
||||
* @param int|null $paginate
|
||||
* @return mixed
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -47,13 +47,30 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
|
|||
*/
|
||||
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->search($this->searchTerm);
|
||||
$instance = $this->getBuilder()->with('node', 'user', 'allocation')->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)
|
||||
{
|
||||
Assert::integerish($id, 'First argument passed to findWithVariables must be integer, received %s.');
|
||||
|
||||
$instance = $this->getBuilder()->with('option.variables', 'variables')
|
||||
->where($this->getModel()->getKeyName(), '=', $id)
|
||||
->first($this->getColumns());
|
||||
|
|
|
@ -76,16 +76,12 @@ class EnvironmentService
|
|||
*
|
||||
* @param int|\Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function process($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);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,4 +54,10 @@ return [
|
|||
'schedule' => [
|
||||
'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
|
||||
/**
|
||||
/*
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
|
@ -22,51 +22,34 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Console\Commands;
|
||||
namespace Tests\Unit\Commands;
|
||||
|
||||
use Carbon;
|
||||
use Storage;
|
||||
use Tests\TestCase;
|
||||
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';
|
||||
|
||||
/**
|
||||
* 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()
|
||||
protected function runCommand(Command $command, array $args = [], array $inputs = [], array $opts = [])
|
||||
{
|
||||
parent::__construct();
|
||||
if (! $command->getLaravel() instanceof Application) {
|
||||
$command->setLaravel($this->app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$files = Storage::files('services/.bak');
|
||||
$response = new CommandTester($command);
|
||||
$response->setInputs($inputs);
|
||||
$response->execute($args, $opts);
|
||||
|
||||
foreach ($files as $file) {
|
||||
$lastModified = Carbon::createFromTimestamp(Storage::lastModified($file));
|
||||
if ($lastModified->diffInMinutes(Carbon::now()) > 5) {
|
||||
$this->info('Deleting ' . $file);
|
||||
Storage::delete($file);
|
||||
}
|
||||
}
|
||||
return $response->getDisplay();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
131
tests/Unit/Commands/Schedule/ProcessRunnableCommandTest.php
Normal file
131
tests/Unit/Commands/Schedule/ProcessRunnableCommandTest.php
Normal file
|
@ -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 a new issue