Add bulk power management via CLI
This commit is contained in:
parent
c6137db529
commit
021710aa1c
5 changed files with 182 additions and 0 deletions
|
@ -19,6 +19,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||||
* Added proper transformer for Packs and re-enabled missing includes on server.
|
* Added proper transformer for Packs and re-enabled missing includes on server.
|
||||||
* Added support for using Filesystem as a caching driver, although not recommended.
|
* Added support for using Filesystem as a caching driver, although not recommended.
|
||||||
* Added support for user management of server databases.
|
* Added support for user management of server databases.
|
||||||
|
* **Added bulk power management CLI interface to send start, stop, kill, restart actions to servers across configurable nodes.**
|
||||||
|
|
||||||
## v0.7.3 (Derelict Dermodactylus)
|
## v0.7.3 (Derelict Dermodactylus)
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
119
app/Console/Commands/Server/BulkPowerActionCommand.php
Normal file
119
app/Console/Commands/Server/BulkPowerActionCommand.php
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pterodactyl\Console\Commands\Server;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
use Illuminate\Validation\Factory as ValidatorFactory;
|
||||||
|
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||||
|
use Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface;
|
||||||
|
|
||||||
|
class BulkPowerActionCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface
|
||||||
|
*/
|
||||||
|
private $powerRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||||
|
*/
|
||||||
|
private $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Illuminate\Validation\Factory
|
||||||
|
*/
|
||||||
|
private $validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'p:server:bulk-power
|
||||||
|
{action : The action to perform (start, stop, restart, kill)}
|
||||||
|
{--servers= : A comma seperated list of servers.}
|
||||||
|
{--nodes= : A comma seperated list of nodes.}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Perform bulk power management on large groupings of servers or nodes at once.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BulkPowerActionCommand constructor.
|
||||||
|
*
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface $powerRepository
|
||||||
|
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||||
|
* @param \Illuminate\Validation\Factory $validator
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
PowerRepositoryInterface $powerRepository,
|
||||||
|
ServerRepositoryInterface $repository,
|
||||||
|
ValidatorFactory $validator
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->powerRepository = $powerRepository;
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->validator = $validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the bulk power request.
|
||||||
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Repository\Daemon\InvalidPowerSignalException
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$action = $this->argument('action');
|
||||||
|
$nodes = empty($this->option('nodes')) ? [] : explode(',', $this->option('nodes'));
|
||||||
|
$servers = empty($this->option('servers')) ? [] : explode(',', $this->option('servers'));
|
||||||
|
|
||||||
|
$validator = $this->validator->make([
|
||||||
|
'action' => $action,
|
||||||
|
'nodes' => $nodes,
|
||||||
|
'servers' => $servers,
|
||||||
|
], [
|
||||||
|
'action' => 'string|in:start,stop,kill,restart',
|
||||||
|
'nodes' => 'array',
|
||||||
|
'nodes.*' => 'integer|min:1',
|
||||||
|
'servers' => 'array',
|
||||||
|
'servers.*' => 'integer|min:1',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
foreach ($validator->getMessageBag()->all() as $message) {
|
||||||
|
$this->output->error($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = $this->repository->getServersForPowerActionCount($servers, $nodes);
|
||||||
|
if (! $this->confirm(trans('command/messages.server.power.confirm', ['action' => $action, 'count' => $count]))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bar = $this->output->createProgressBar($count);
|
||||||
|
$servers = $this->repository->getServersForPowerAction($servers, $nodes);
|
||||||
|
|
||||||
|
foreach ($servers as $server) {
|
||||||
|
$bar->clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->powerRepository->setServer($server)->sendSignal($action);
|
||||||
|
} catch (RequestException $exception) {
|
||||||
|
$this->output->error(trans('command/messages.server.power.action_failed', [
|
||||||
|
'name' => $server->name,
|
||||||
|
'id' => $server->id,
|
||||||
|
'node' => $server->node->name,
|
||||||
|
'message' => $exception->getMessage(),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bar->advance();
|
||||||
|
$bar->display();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->line('');
|
||||||
|
}
|
||||||
|
}
|
|
@ -117,4 +117,23 @@ interface ServerRepositoryInterface extends RepositoryInterface, SearchableInter
|
||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
*/
|
*/
|
||||||
public function getByUuid(string $uuid): Server;
|
public function getByUuid(string $uuid): Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all of the servers that should have a power action performed aganist them.
|
||||||
|
*
|
||||||
|
* @param int[] $servers
|
||||||
|
* @param int[] $nodes
|
||||||
|
* @param bool $returnCount
|
||||||
|
* @return int|\Generator
|
||||||
|
*/
|
||||||
|
public function getServersForPowerAction(array $servers = [], array $nodes = [], bool $returnCount = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the total number of servers that will be affected by the query.
|
||||||
|
*
|
||||||
|
* @param int[] $servers
|
||||||
|
* @param int[] $nodes
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getServersForPowerActionCount(array $servers = [], array $nodes = []): int;
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,6 +264,45 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all of the servers that should have a power action performed aganist them.
|
||||||
|
*
|
||||||
|
* @param int[] $servers
|
||||||
|
* @param int[] $nodes
|
||||||
|
* @param bool $returnCount
|
||||||
|
* @return int|\Generator
|
||||||
|
*/
|
||||||
|
public function getServersForPowerAction(array $servers = [], array $nodes = [], bool $returnCount = false)
|
||||||
|
{
|
||||||
|
$instance = $this->getBuilder();
|
||||||
|
|
||||||
|
if (! empty($nodes) && ! empty($servers)) {
|
||||||
|
$instance->whereIn('id', $servers)->orWhereIn('node_id', $nodes);
|
||||||
|
} elseif (empty($nodes) && ! empty($servers)) {
|
||||||
|
$instance->whereIn('id', $servers);
|
||||||
|
} elseif (! empty($nodes) && empty($servers)) {
|
||||||
|
$instance->whereIn('node_id', $nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($returnCount) {
|
||||||
|
return $instance->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $instance->with('node')->cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the total number of servers that will be affected by the query.
|
||||||
|
*
|
||||||
|
* @param int[] $servers
|
||||||
|
* @param int[] $nodes
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getServersForPowerActionCount(array $servers = [], array $nodes = []): int
|
||||||
|
{
|
||||||
|
return $this->getServersForPowerAction($servers, $nodes, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an array of server IDs that a given user can access based
|
* Return an array of server IDs that a given user can access based
|
||||||
* on owner and subuser permissions.
|
* on owner and subuser permissions.
|
||||||
|
|
|
@ -37,6 +37,10 @@ return [
|
||||||
],
|
],
|
||||||
'server' => [
|
'server' => [
|
||||||
'rebuild_failed' => 'Rebuild request for ":name" (#:id) on node ":node" failed with error: :message',
|
'rebuild_failed' => 'Rebuild request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||||
|
'power' => [
|
||||||
|
'confirm' => 'You are about to perform a :action aganist :count servers. Do you wish to continue?',
|
||||||
|
'action_failed' => 'Power action request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'environment' => [
|
'environment' => [
|
||||||
'mail' => [
|
'mail' => [
|
||||||
|
|
Loading…
Reference in a new issue