Fix data integrity exception, closes #922
This commit is contained in:
parent
e1d6980c0b
commit
cfb7415e2a
4 changed files with 116 additions and 5 deletions
|
@ -8,6 +8,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
|
|||
* `[rc.2]` — Fixes bad API behavior on `/user` routes.
|
||||
* `[rc.2]` — Fixes Admin CP user editing resetting a password on users unintentionally.
|
||||
* `[rc.2]` — Fixes bug with server creation API endpoint that would fail to validate `allocation.default` correctly.
|
||||
* `[rc.2]` — Fix data integrity exception occuring due to invalid data being passed to server creation service on the API.
|
||||
|
||||
### Added
|
||||
* Added ability to search the following API endpoints: list users, list servers, and list locations.
|
||||
|
|
|
@ -49,6 +49,10 @@ class StoreServerRequest extends ApplicationApiRequest
|
|||
'limits.io' => $rules['io'],
|
||||
'limits.cpu' => $rules['cpu'],
|
||||
|
||||
// Placeholders for rules added in withValidator() function.
|
||||
'allocation.default' => '',
|
||||
'allocation.additional.*' => '',
|
||||
|
||||
// Automatic deployment rules
|
||||
'deploy' => 'sometimes|required|array',
|
||||
'deploy.locations' => 'array',
|
||||
|
|
|
@ -112,7 +112,9 @@ class ServerCreationService
|
|||
|
||||
/**
|
||||
* Create a server on the Panel and trigger a request to the Daemon to begin the server
|
||||
* creation process.
|
||||
* creation process. This function will attempt to set as many additional values
|
||||
* as possible given the input data. For example, if an allocation_id is passed with
|
||||
* no node_id the node_is will be picked from the allocation.
|
||||
*
|
||||
* @param array $data
|
||||
* @param \Pterodactyl\Models\Objects\DeploymentObject|null $deployment
|
||||
|
@ -138,6 +140,12 @@ class ServerCreationService
|
|||
$data['node_id'] = $allocation->node_id;
|
||||
}
|
||||
|
||||
// Auto-configure the node based on the selected allocation
|
||||
// if no node was defined.
|
||||
if (is_null(array_get($data, 'node_id'))) {
|
||||
$data['node_id'] = $this->getNodeFromAllocation($data['allocation_id']);
|
||||
}
|
||||
|
||||
if (is_null(array_get($data, 'nest_id'))) {
|
||||
$egg = $this->eggRepository->setColumns(['id', 'nest_id'])->find(array_get($data, 'egg_id'));
|
||||
$data['nest_id'] = $egg->nest_id;
|
||||
|
@ -263,4 +271,19 @@ class ServerCreationService
|
|||
$this->serverVariableRepository->insert($records);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the node that an allocation belongs to.
|
||||
*
|
||||
* @param int $allocation
|
||||
* @return int
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
private function getNodeFromAllocation(int $allocation): int
|
||||
{
|
||||
$allocation = $this->allocationRepository->setColumns(['id', 'node_id'])->find($allocation);
|
||||
|
||||
return $allocation->node_id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,14 @@ namespace Tests\Unit\Services\Servers;
|
|||
|
||||
use Mockery as m;
|
||||
use Tests\TestCase;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Pterodactyl\Models\Egg;
|
||||
use Pterodactyl\Models\User;
|
||||
use Tests\Traits\MocksUuids;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Allocation;
|
||||
use Tests\Traits\MocksRequestException;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Models\Objects\DeploymentObject;
|
||||
use Pterodactyl\Services\Servers\ServerCreationService;
|
||||
use Pterodactyl\Services\Servers\VariableValidatorService;
|
||||
use Pterodactyl\Services\Deployment\FindViableNodesService;
|
||||
|
@ -35,7 +37,7 @@ class ServerCreationServiceTest extends TestCase
|
|||
private $allocationRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Deployment\AllocationSelectionService
|
||||
* @var \Pterodactyl\Services\Deployment\AllocationSelectionService|\Mockery\Mock
|
||||
*/
|
||||
private $allocationSelectionService;
|
||||
|
||||
|
@ -55,12 +57,12 @@ class ServerCreationServiceTest extends TestCase
|
|||
private $daemonServerRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface
|
||||
* @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface|\Mockery\Mock
|
||||
*/
|
||||
private $eggRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Deployment\FindViableNodesService
|
||||
* @var \Pterodactyl\Services\Deployment\FindViableNodesService|\Mockery\Mock
|
||||
*/
|
||||
private $findViableNodesService;
|
||||
|
||||
|
@ -117,6 +119,7 @@ class ServerCreationServiceTest extends TestCase
|
|||
$this->repository->shouldReceive('create')->with(m::subset([
|
||||
'uuid' => $this->getKnownUuid(),
|
||||
'node_id' => $model->node_id,
|
||||
'allocation_id' => $model->allocation_id,
|
||||
'owner_id' => $model->owner_id,
|
||||
'nest_id' => $model->nest_id,
|
||||
'egg_id' => $model->egg_id,
|
||||
|
@ -147,6 +150,86 @@ class ServerCreationServiceTest extends TestCase
|
|||
$this->assertSame($model, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that optional parameters get auto-filled correctly on the model.
|
||||
*/
|
||||
public function testDataIsAutoFilled()
|
||||
{
|
||||
$model = factory(Server::class)->make(['uuid' => $this->getKnownUuid()]);
|
||||
$allocationModel = factory(Allocation::class)->make(['node_id' => $model->node_id]);
|
||||
$eggModel = factory(Egg::class)->make(['nest_id' => $model->nest_id]);
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs();
|
||||
$this->allocationRepository->shouldReceive('setColumns->find')->once()->with($model->allocation_id)->andReturn($allocationModel);
|
||||
$this->eggRepository->shouldReceive('setColumns->find')->once()->with($model->egg_id)->andReturn($eggModel);
|
||||
|
||||
$this->validatorService->shouldReceive('setUserLevel->handle')->once()->andReturn(collect([]));
|
||||
$this->repository->shouldReceive('create')->once()->with(m::subset([
|
||||
'uuid' => $this->getKnownUuid(),
|
||||
'node_id' => $model->node_id,
|
||||
'allocation_id' => $model->allocation_id,
|
||||
'nest_id' => $model->nest_id,
|
||||
'egg_id' => $model->egg_id,
|
||||
]))->andReturn($model);
|
||||
|
||||
$this->allocationRepository->shouldReceive('assignAllocationsToServer')->once()->with($model->id, [$model->allocation_id]);
|
||||
$this->configurationStructureService->shouldReceive('handle')->once()->with($model)->andReturn([]);
|
||||
|
||||
$this->daemonServerRepository->shouldReceive('setServer->create')->once();
|
||||
$this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
$this->getService()->handle(
|
||||
collect($model->toArray())->except(['node_id', 'nest_id'])->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an auto-deployment object is used correctly if passed.
|
||||
*/
|
||||
public function testAutoDeploymentObject()
|
||||
{
|
||||
$model = factory(Server::class)->make(['uuid' => $this->getKnownUuid()]);
|
||||
$deploymentObject = new DeploymentObject();
|
||||
$deploymentObject->setPorts(['25565']);
|
||||
$deploymentObject->setDedicated(false);
|
||||
$deploymentObject->setLocations([1]);
|
||||
|
||||
$this->connection->shouldReceive('beginTransaction')->once()->withNoArgs();
|
||||
|
||||
$this->findViableNodesService->shouldReceive('setLocations')->once()->with($deploymentObject->getLocations())->andReturnSelf();
|
||||
$this->findViableNodesService->shouldReceive('setDisk')->once()->with($model->disk)->andReturnSelf();
|
||||
$this->findViableNodesService->shouldReceive('setMemory')->once()->with($model->memory)->andReturnSelf();
|
||||
$this->findViableNodesService->shouldReceive('handle')->once()->withNoArgs()->andReturn([1, 2]);
|
||||
|
||||
$allocationModel = factory(Allocation::class)->make([
|
||||
'id' => $model->allocation_id,
|
||||
'node_id' => $model->node_id,
|
||||
]);
|
||||
$this->allocationSelectionService->shouldReceive('setDedicated')->once()->with($deploymentObject->isDedicated())->andReturnSelf();
|
||||
$this->allocationSelectionService->shouldReceive('setNodes')->once()->with([1, 2])->andReturnSelf();
|
||||
$this->allocationSelectionService->shouldReceive('setPorts')->once()->with($deploymentObject->getPorts())->andReturnSelf();
|
||||
$this->allocationSelectionService->shouldReceive('handle')->once()->withNoArgs()->andReturn($allocationModel);
|
||||
|
||||
$this->validatorService->shouldReceive('setUserLevel->handle')->once()->andReturn(collect([]));
|
||||
$this->repository->shouldReceive('create')->once()->with(m::subset([
|
||||
'uuid' => $this->getKnownUuid(),
|
||||
'node_id' => $model->node_id,
|
||||
'allocation_id' => $model->allocation_id,
|
||||
'nest_id' => $model->nest_id,
|
||||
'egg_id' => $model->egg_id,
|
||||
]))->andReturn($model);
|
||||
|
||||
$this->allocationRepository->shouldReceive('assignAllocationsToServer')->once()->with($model->id, [$model->allocation_id]);
|
||||
$this->configurationStructureService->shouldReceive('handle')->once()->with($model)->andReturn([]);
|
||||
|
||||
$this->daemonServerRepository->shouldReceive('setServer->create')->once();
|
||||
$this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull();
|
||||
|
||||
$this->getService()->handle(
|
||||
collect($model->toArray())->except(['allocation_id', 'node_id'])->toArray(), $deploymentObject
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test handling of node timeout or other daemon error.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue