2015-12-14 03:22:16 +00:00
< ? php
2016-01-20 00:10:39 +00:00
/**
2016-01-20 21:05:16 +00:00
* Pterodactyl - Panel
2017-01-24 22:57:08 +00:00
* Copyright ( c ) 2015 - 2017 Dane Everitt < dane @ daneeveritt . com >.
2016-01-20 00:10:39 +00:00
*
2016-01-20 20:56:40 +00:00
* 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 :
2016-01-20 00:10:39 +00:00
*
2016-01-20 20:56:40 +00:00
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
2016-01-20 00:10:39 +00:00
*
2016-01-20 20:56:40 +00:00
* 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 .
2016-01-20 00:10:39 +00:00
*/
2016-12-07 22:46:38 +00:00
2015-12-14 03:22:16 +00:00
namespace Pterodactyl\Repositories ;
use DB ;
2016-01-02 23:04:18 +00:00
use Log ;
2016-12-07 22:46:38 +00:00
use Crypt ;
use Validator ;
2015-12-14 03:22:16 +00:00
use Pterodactyl\Models ;
use Pterodactyl\Services\UuidService ;
2016-09-28 01:01:46 +00:00
use Pterodactyl\Services\DeploymentService ;
2015-12-14 03:22:16 +00:00
use Pterodactyl\Exceptions\DisplayException ;
2016-12-07 22:46:38 +00:00
use Pterodactyl\Notifications\ServerCreated ;
2015-12-14 03:22:16 +00:00
use Pterodactyl\Exceptions\DisplayValidationException ;
class ServerRepository
{
2016-01-19 02:35:37 +00:00
protected $daemonPermissions = [
2016-12-07 22:46:38 +00:00
's:*' ,
2016-01-19 02:35:37 +00:00
];
2015-12-14 03:22:16 +00:00
public function __construct ()
{
//
}
/**
* Generates a SFTP username for a server given a server name .
2016-12-07 22:46:38 +00:00
* format : mumble_67c7a4b0 .
2015-12-14 03:22:16 +00:00
*
* @ param string $name
2017-01-14 03:22:25 +00:00
* @ param string $identifier
2015-12-14 03:22:16 +00:00
* @ return string
*/
2017-01-14 03:22:25 +00:00
protected function generateSFTPUsername ( $name , $identifier = null )
2015-12-14 03:22:16 +00:00
{
2017-01-14 03:22:25 +00:00
if ( is_null ( $identifier ) || ! ctype_alnum ( $identifier )) {
$unique = str_random ( 8 );
} else {
if ( strlen ( $identifier ) < 8 ) {
$unique = $identifier . str_random (( 8 - strlen ( $identifier )));
} else {
$unique = substr ( $identifier , 0 , 8 );
}
}
2015-12-14 03:22:16 +00:00
2017-01-14 03:22:25 +00:00
// Filter the Server Name
$name = trim ( preg_replace ( '/[^\w]+/' , '' , $name ), '_' );
$name = ( strlen ( $name ) < 1 ) ? str_random ( 6 ) : $name ;
return strtolower ( substr ( $name , 0 , 6 ) . '_' . $unique );
2015-12-14 03:22:16 +00:00
}
/**
* Adds a new server to the system .
2016-01-02 23:04:18 +00:00
* @ param array $data An array of data descriptors for creating the server . These should align to the columns in the database .
2016-12-07 22:46:38 +00:00
* @ return int
2015-12-14 03:22:16 +00:00
*/
public function create ( array $data )
{
// Validate Fields
$validator = Validator :: make ( $data , [
2016-10-07 18:26:50 +00:00
'owner' => 'bail|required' ,
2016-12-30 20:46:10 +00:00
'name' => 'required|regex:/^([\w .-]{1,200})$/' ,
2016-02-21 06:18:30 +00:00
'memory' => 'required|numeric|min:0' ,
'swap' => 'required|numeric|min:-1' ,
2015-12-14 03:22:16 +00:00
'io' => 'required|numeric|min:10|max:1000' ,
2016-02-21 06:18:30 +00:00
'cpu' => 'required|numeric|min:0' ,
'disk' => 'required|numeric|min:0' ,
2016-12-14 22:17:16 +00:00
'service' => 'required|numeric|min:1|exists:services,id' ,
'option' => 'required|numeric|min:1|exists:service_options,id' ,
2017-01-25 11:01:57 +00:00
'location' => 'required|numeric|min:1|exists:locations,id' ,
2017-01-14 04:21:35 +00:00
'pack' => 'sometimes|nullable|numeric|min:0' ,
2016-09-16 22:39:36 +00:00
'startup' => 'string' ,
2015-12-14 03:22:16 +00:00
'custom_image_name' => 'required_if:use_custom_image,on' ,
2016-11-30 16:01:22 +00:00
'auto_deploy' => 'sometimes|boolean' ,
'custom_id' => 'sometimes|required|numeric|unique:servers,id' ,
2015-12-14 03:22:16 +00:00
]);
2016-09-28 01:01:46 +00:00
$validator -> sometimes ( 'node' , 'bail|required|numeric|min:1|exists:nodes,id' , function ( $input ) {
2016-12-07 22:46:38 +00:00
return ! ( $input -> auto_deploy );
2016-09-28 01:01:46 +00:00
});
$validator -> sometimes ( 'ip' , 'required|ip' , function ( $input ) {
2016-12-07 22:46:38 +00:00
return ! $input -> auto_deploy && ! $input -> allocation ;
2016-09-28 01:01:46 +00:00
});
$validator -> sometimes ( 'port' , 'required|numeric|min:1|max:65535' , function ( $input ) {
2016-12-07 22:46:38 +00:00
return ! $input -> auto_deploy && ! $input -> allocation ;
2016-09-28 01:01:46 +00:00
});
$validator -> sometimes ( 'allocation' , 'numeric|exists:allocations,id' , function ( $input ) {
2016-12-07 22:46:38 +00:00
return ! ( $input -> auto_deploy || ( $input -> port && $input -> ip ));
2016-09-28 01:01:46 +00:00
});
2015-12-14 03:22:16 +00:00
// Run validator, throw catchable and displayable exception if it fails.
// Exception includes a JSON result of failed validation rules.
if ( $validator -> fails ()) {
2015-12-15 20:08:41 +00:00
throw new DisplayValidationException ( $validator -> errors ());
2015-12-14 03:22:16 +00:00
}
2016-10-07 02:43:50 +00:00
if ( is_int ( $data [ 'owner' ])) {
2016-10-14 19:58:52 +00:00
$user = Models\User :: select ( 'id' , 'email' ) -> where ( 'id' , $data [ 'owner' ]) -> first ();
2016-10-07 02:43:50 +00:00
} else {
2016-10-14 19:58:52 +00:00
$user = Models\User :: select ( 'id' , 'email' ) -> where ( 'email' , $data [ 'owner' ]) -> first ();
2016-10-07 02:43:50 +00:00
}
2016-12-07 22:46:38 +00:00
if ( ! $user ) {
2016-10-23 22:48:14 +00:00
throw new DisplayException ( 'The user id or email passed to the function was not found on the system.' );
2016-10-07 02:43:50 +00:00
}
2015-12-14 03:22:16 +00:00
2016-09-28 01:01:46 +00:00
$autoDeployed = false ;
2016-12-07 22:46:38 +00:00
if ( isset ( $data [ 'auto_deploy' ]) && in_array ( $data [ 'auto_deploy' ], [ true , 1 , '1' ])) {
2016-09-28 01:01:46 +00:00
// This is an auto-deployment situation
// Ignore any other passed node data
unset ( $data [ 'node' ], $data [ 'ip' ], $data [ 'port' ], $data [ 'allocation' ]);
$autoDeployed = true ;
$node = DeploymentService :: smartRandomNode ( $data [ 'memory' ], $data [ 'disk' ], $data [ 'location' ]);
$allocation = DeploymentService :: randomAllocation ( $node -> id );
} else {
$node = Models\Node :: getByID ( $data [ 'node' ]);
}
2016-09-05 20:21:36 +00:00
2015-12-14 03:22:16 +00:00
// Verify IP & Port are a.) free and b.) assigned to the node.
// We know the node exists because of 'exists:nodes,id' in the validation
2016-12-07 22:46:38 +00:00
if ( ! $autoDeployed ) {
if ( ! isset ( $data [ 'allocation' ])) {
2016-09-28 01:01:46 +00:00
$allocation = Models\Allocation :: where ( 'ip' , $data [ 'ip' ]) -> where ( 'port' , $data [ 'port' ]) -> where ( 'node' , $data [ 'node' ]) -> whereNull ( 'assigned_to' ) -> first ();
} else {
2016-12-07 22:46:38 +00:00
$allocation = Models\Allocation :: where ( 'id' , $data [ 'allocation' ]) -> where ( 'node' , $data [ 'node' ]) -> whereNull ( 'assigned_to' ) -> first ();
2016-09-28 01:01:46 +00:00
}
2016-09-05 20:21:36 +00:00
}
2015-12-14 03:22:16 +00:00
// Something failed in the query, either that combo doesn't exist, or it is in use.
2016-12-07 22:46:38 +00:00
if ( ! $allocation ) {
2016-09-05 20:21:36 +00:00
throw new DisplayException ( 'The selected IP/Port combination or Allocation ID is either already in use, or unavaliable for this node.' );
2015-12-14 03:22:16 +00:00
}
// Validate those Service Option Variables
// We know the service and option exists because of the validation.
// We need to verify that the option exists for the service, and then check for
// any required variable fields. (fields are labeled env_<env_variable>)
$option = Models\ServiceOptions :: where ( 'id' , $data [ 'option' ]) -> where ( 'parent_service' , $data [ 'service' ]) -> first ();
2016-12-07 22:46:38 +00:00
if ( ! $option ) {
2015-12-14 03:22:16 +00:00
throw new DisplayException ( 'The requested service option does not exist for the specified service.' );
}
2016-11-27 19:50:10 +00:00
// Validate the Pack
2016-12-14 22:17:16 +00:00
if ( $data [ 'pack' ] == 0 ) {
2016-11-27 19:50:10 +00:00
$data [ 'pack' ] = null ;
}
2016-12-14 21:56:25 +00:00
if ( ! is_null ( $data [ 'pack' ])) {
2016-11-27 19:50:10 +00:00
$pack = Models\ServicePack :: where ( 'id' , $data [ 'pack' ]) -> where ( 'option' , $data [ 'option' ]) -> first ();
2016-12-14 21:56:25 +00:00
if ( ! $pack ) {
2016-11-27 19:50:10 +00:00
throw new DisplayException ( 'The requested service pack does not seem to exist for this combination.' );
}
}
2016-01-03 23:10:28 +00:00
// Load up the Service Information
$service = Models\Service :: find ( $option -> parent_service );
2015-12-14 03:22:16 +00:00
// Check those Variables
$variables = Models\ServiceVariables :: where ( 'option_id' , $data [ 'option' ]) -> get ();
2015-12-15 20:08:41 +00:00
$variableList = [];
2015-12-14 03:22:16 +00:00
if ( $variables ) {
2016-12-07 22:46:38 +00:00
foreach ( $variables as $variable ) {
2015-12-14 03:22:16 +00:00
// Is the variable required?
2016-12-30 21:00:51 +00:00
if ( ! isset ( $data [ 'env_' . $variable -> env_variable ])) {
2015-12-14 03:22:16 +00:00
if ( $variable -> required === 1 ) {
throw new DisplayException ( 'A required service option variable field (env_' . $variable -> env_variable . ') was missing from the request.' );
}
2016-12-12 19:30:57 +00:00
$variableList [] = [
2016-01-03 23:10:28 +00:00
'id' => $variable -> id ,
'env' => $variable -> env_variable ,
2016-12-07 22:46:38 +00:00
'val' => $variable -> default_value ,
2016-12-12 19:30:57 +00:00
];
2015-12-14 03:22:16 +00:00
continue ;
}
// Check aganist Regex Pattern
2016-12-07 22:46:38 +00:00
if ( ! is_null ( $variable -> regex ) && ! preg_match ( $variable -> regex , $data [ 'env_' . $variable -> env_variable ])) {
2015-12-14 03:22:16 +00:00
throw new DisplayException ( 'Failed to validate service option variable field (env_' . $variable -> env_variable . ') aganist regex (' . $variable -> regex . ').' );
}
2016-12-12 19:30:57 +00:00
$variableList [] = [
2016-01-03 23:10:28 +00:00
'id' => $variable -> id ,
'env' => $variable -> env_variable ,
2016-12-07 22:46:38 +00:00
'val' => $data [ 'env_' . $variable -> env_variable ],
2016-12-12 19:30:57 +00:00
];
2015-12-14 03:22:16 +00:00
continue ;
2015-12-15 20:08:41 +00:00
}
}
// Check Overallocation
2016-12-07 22:46:38 +00:00
if ( ! $autoDeployed ) {
2016-09-28 01:01:46 +00:00
if ( is_numeric ( $node -> memory_overallocate ) || is_numeric ( $node -> disk_overallocate )) {
$totals = Models\Server :: select ( DB :: raw ( 'SUM(memory) as memory, SUM(disk) as disk' )) -> where ( 'node' , $node -> id ) -> first ();
2015-12-15 20:08:41 +00:00
2016-09-28 01:01:46 +00:00
// Check memory limits
if ( is_numeric ( $node -> memory_overallocate )) {
$newMemory = $totals -> memory + $data [ 'memory' ];
$memoryLimit = ( $node -> memory * ( 1 + ( $node -> memory_overallocate / 100 )));
2016-12-07 22:46:38 +00:00
if ( $newMemory > $memoryLimit ) {
2016-09-28 01:01:46 +00:00
throw new DisplayException ( 'The amount of memory allocated to this server would put the node over its allocation limits. This node is allowed ' . ( $node -> memory_overallocate + 100 ) . '% of its assigned ' . $node -> memory . 'Mb of memory (' . $memoryLimit . 'Mb) of which ' . (( $totals -> memory / $node -> memory ) * 100 ) . '% (' . $totals -> memory . 'Mb) is in use already. By allocating this server the node would be at ' . (( $newMemory / $node -> memory ) * 100 ) . '% (' . $newMemory . 'Mb) usage.' );
}
2015-12-15 20:08:41 +00:00
}
2016-09-28 01:01:46 +00:00
// Check Disk Limits
if ( is_numeric ( $node -> disk_overallocate )) {
$newDisk = $totals -> disk + $data [ 'disk' ];
$diskLimit = ( $node -> disk * ( 1 + ( $node -> disk_overallocate / 100 )));
2016-12-07 22:46:38 +00:00
if ( $newDisk > $diskLimit ) {
2016-09-28 01:01:46 +00:00
throw new DisplayException ( 'The amount of disk allocated to this server would put the node over its allocation limits. This node is allowed ' . ( $node -> disk_overallocate + 100 ) . '% of its assigned ' . $node -> disk . 'Mb of disk (' . $diskLimit . 'Mb) of which ' . (( $totals -> disk / $node -> disk ) * 100 ) . '% (' . $totals -> disk . 'Mb) is in use already. By allocating this server the node would be at ' . (( $newDisk / $node -> disk ) * 100 ) . '% (' . $newDisk . 'Mb) usage.' );
}
2015-12-15 20:08:41 +00:00
}
}
}
DB :: beginTransaction ();
2016-02-27 15:30:59 +00:00
try {
$uuid = new UuidService ;
// Add Server to the Database
$server = new Models\Server ;
2016-10-14 19:34:01 +00:00
$genUuid = $uuid -> generate ( 'servers' , 'uuid' );
2016-10-14 19:58:52 +00:00
$genShortUuid = $uuid -> generateShort ( 'servers' , 'uuidShort' , $genUuid );
2016-12-07 22:46:38 +00:00
2016-11-30 16:01:22 +00:00
if ( isset ( $data [ 'custom_id' ])) {
$server -> id = $data [ 'custom_id' ];
}
2016-02-27 15:30:59 +00:00
$server -> fill ([
2016-10-14 19:34:01 +00:00
'uuid' => $genUuid ,
'uuidShort' => $genShortUuid ,
2016-09-28 01:01:46 +00:00
'node' => $node -> id ,
2016-02-27 15:30:59 +00:00
'name' => $data [ 'name' ],
2016-09-02 01:21:01 +00:00
'suspended' => 0 ,
2016-02-27 15:30:59 +00:00
'owner' => $user -> id ,
'memory' => $data [ 'memory' ],
'swap' => $data [ 'swap' ],
'disk' => $data [ 'disk' ],
'io' => $data [ 'io' ],
'cpu' => $data [ 'cpu' ],
'oom_disabled' => ( isset ( $data [ 'oom_disabled' ])) ? true : false ,
2016-08-31 20:03:37 +00:00
'allocation' => $allocation -> id ,
2016-02-27 15:30:59 +00:00
'service' => $data [ 'service' ],
'option' => $data [ 'option' ],
2016-11-27 19:50:10 +00:00
'pack' => $data [ 'pack' ],
2016-02-27 15:30:59 +00:00
'startup' => $data [ 'startup' ],
'daemonSecret' => $uuid -> generate ( 'servers' , 'daemonSecret' ),
2016-10-07 02:32:54 +00:00
'image' => ( isset ( $data [ 'custom_image_name' ])) ? $data [ 'custom_image_name' ] : $option -> docker_image ,
2016-10-14 19:34:01 +00:00
'username' => $this -> generateSFTPUsername ( $data [ 'name' ], $genShortUuid ),
2016-12-07 22:46:38 +00:00
'sftp_password' => Crypt :: encrypt ( 'not set' ),
2016-02-27 15:30:59 +00:00
]);
$server -> save ();
2015-12-15 20:08:41 +00:00
2016-02-27 15:30:59 +00:00
// Mark Allocation in Use
$allocation -> assigned_to = $server -> id ;
$allocation -> save ();
2015-12-15 20:08:41 +00:00
2016-02-27 15:30:59 +00:00
// Add Variables
2016-12-12 19:30:57 +00:00
$environmentVariables = [
2016-12-07 22:46:38 +00:00
'STARTUP' => $data [ 'startup' ],
2016-12-12 19:30:57 +00:00
];
2016-12-07 22:46:38 +00:00
foreach ( $variableList as $item ) {
2016-12-12 19:30:57 +00:00
$environmentVariables [ $item [ 'env' ]] = $item [ 'val' ];
2016-02-27 15:30:59 +00:00
Models\ServerVariables :: create ([
'server_id' => $server -> id ,
'variable_id' => $item [ 'id' ],
2016-12-07 22:46:38 +00:00
'variable_value' => $item [ 'val' ],
2016-02-27 15:30:59 +00:00
]);
}
2015-12-15 20:08:41 +00:00
2016-10-14 19:58:52 +00:00
// Queue Notification Email
$user -> notify (( new ServerCreated ([
'name' => $server -> name ,
'memory' => $server -> memory ,
'node' => $node -> name ,
'service' => $service -> name ,
'option' => $option -> name ,
2016-12-07 22:46:38 +00:00
'uuidShort' => $server -> uuidShort ,
2016-10-14 19:58:52 +00:00
])));
2016-01-03 23:10:28 +00:00
$client = Models\Node :: guzzleRequest ( $node -> id );
$client -> request ( 'POST' , '/servers' , [
'headers' => [
2016-12-07 22:46:38 +00:00
'X-Access-Token' => $node -> daemonSecret ,
2016-01-03 23:10:28 +00:00
],
'json' => [
'uuid' => ( string ) $server -> uuid ,
'user' => $server -> username ,
'build' => [
'default' => [
2016-08-31 20:03:37 +00:00
'ip' => $allocation -> ip ,
2016-11-27 19:50:10 +00:00
'port' => ( int ) $allocation -> port ,
2016-01-03 23:10:28 +00:00
],
'ports' => [
2016-12-07 22:46:38 +00:00
( string ) $allocation -> ip => [( int ) $allocation -> port ],
2016-01-03 23:10:28 +00:00
],
'env' => $environmentVariables ,
'memory' => ( int ) $server -> memory ,
'swap' => ( int ) $server -> swap ,
'io' => ( int ) $server -> io ,
'cpu' => ( int ) $server -> cpu ,
'disk' => ( int ) $server -> disk ,
2016-11-27 19:50:10 +00:00
'image' => ( isset ( $data [ 'custom_image_name' ])) ? $data [ 'custom_image_name' ] : $option -> docker_image ,
2016-01-03 23:10:28 +00:00
],
'service' => [
'type' => $service -> file ,
2016-11-27 19:50:10 +00:00
'option' => $option -> tag ,
'pack' => ( isset ( $pack )) ? $pack -> uuid : null ,
2016-01-03 23:10:28 +00:00
],
'keys' => [
2016-11-27 19:50:10 +00:00
( string ) $server -> daemonSecret => $this -> daemonPermissions ,
2016-01-03 23:10:28 +00:00
],
2016-11-27 19:50:10 +00:00
'rebuild' => false ,
2016-12-07 22:46:38 +00:00
],
2016-01-03 23:10:28 +00:00
]);
2015-12-15 20:08:41 +00:00
DB :: commit ();
2016-12-07 22:46:38 +00:00
2015-12-15 20:08:41 +00:00
return $server -> id ;
2016-01-03 23:10:28 +00:00
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
DB :: rollBack ();
2016-09-05 20:21:36 +00:00
throw new DisplayException ( 'There was an error while attempting to connect to the daemon to add this server.' , $ex );
2016-01-03 23:10:28 +00:00
} catch ( \Exception $ex ) {
2015-12-15 20:08:41 +00:00
DB :: rollBack ();
2016-01-03 23:10:28 +00:00
throw $ex ;
2015-12-15 20:08:41 +00:00
}
2015-12-14 03:22:16 +00:00
}
2016-01-02 23:04:18 +00:00
/**
2016-12-07 22:46:38 +00:00
* [ updateDetails description ] .
* @ param int $id
2016-01-02 23:04:18 +00:00
* @ param array $data
2016-12-07 22:46:38 +00:00
* @ return bool
2016-01-02 23:04:18 +00:00
*/
public function updateDetails ( $id , array $data )
{
$uuid = new UuidService ;
$resetDaemonKey = false ;
// Validate Fields
$validator = Validator :: make ( $data , [
'owner' => 'email|exists:users,email' ,
2016-12-30 20:46:10 +00:00
'name' => 'regex:([\w .-]{1,200})' ,
2016-01-02 23:04:18 +00:00
]);
// Run validator, throw catchable and displayable exception if it fails.
// Exception includes a JSON result of failed validation rules.
if ( $validator -> fails ()) {
throw new DisplayValidationException ( $validator -> errors ());
}
DB :: beginTransaction ();
2016-02-27 15:30:59 +00:00
try {
$server = Models\Server :: findOrFail ( $id );
$owner = Models\User :: findOrFail ( $server -> owner );
// Update daemon secret if it was passed.
if (( isset ( $data [ 'reset_token' ]) && $data [ 'reset_token' ] === true ) || ( isset ( $data [ 'owner' ]) && $data [ 'owner' ] !== $owner -> email )) {
$oldDaemonKey = $server -> daemonSecret ;
$server -> daemonSecret = $uuid -> generate ( 'servers' , 'daemonSecret' );
$resetDaemonKey = true ;
}
2016-01-02 23:04:18 +00:00
2016-02-27 15:30:59 +00:00
// Update Server Owner if it was passed.
if ( isset ( $data [ 'owner' ]) && $data [ 'owner' ] !== $owner -> email ) {
$newOwner = Models\User :: select ( 'id' ) -> where ( 'email' , $data [ 'owner' ]) -> first ();
$server -> owner = $newOwner -> id ;
}
2016-01-02 23:04:18 +00:00
2016-02-27 15:30:59 +00:00
// Update Server Name if it was passed.
if ( isset ( $data [ 'name' ])) {
$server -> name = $data [ 'name' ];
}
2016-01-02 23:04:18 +00:00
2016-02-27 15:30:59 +00:00
// Save our changes
$server -> save ();
2016-01-02 23:04:18 +00:00
2016-02-27 15:30:59 +00:00
// Do we need to update? If not, return successful.
2016-12-07 22:46:38 +00:00
if ( ! $resetDaemonKey ) {
2016-02-27 15:30:59 +00:00
DB :: commit ();
2016-12-07 22:46:38 +00:00
2016-02-27 15:30:59 +00:00
return true ;
}
2016-01-02 23:04:18 +00:00
2016-02-27 15:30:59 +00:00
// If we need to update do it here.
2016-01-02 23:04:18 +00:00
$node = Models\Node :: getByID ( $server -> node );
$client = Models\Node :: guzzleRequest ( $server -> node );
$res = $client -> request ( 'PATCH' , '/server' , [
'headers' => [
'X-Access-Server' => $server -> uuid ,
2016-12-07 22:46:38 +00:00
'X-Access-Token' => $node -> daemonSecret ,
2016-01-02 23:04:18 +00:00
],
'exceptions' => false ,
'json' => [
'keys' => [
( string ) $oldDaemonKey => [],
2016-12-07 22:46:38 +00:00
( string ) $server -> daemonSecret => $this -> daemonPermissions ,
],
],
2016-01-02 23:04:18 +00:00
]);
if ( $res -> getStatusCode () === 204 ) {
DB :: commit ();
2016-12-07 22:46:38 +00:00
2016-01-02 23:04:18 +00:00
return true ;
} else {
throw new DisplayException ( 'Daemon returned a a non HTTP/204 error code. HTTP/' + $res -> getStatusCode ());
}
} catch ( \Exception $ex ) {
2016-01-03 04:21:22 +00:00
DB :: rollBack ();
2016-01-02 23:04:18 +00:00
Log :: error ( $ex );
throw new DisplayException ( 'An error occured while attempting to update this server\'s information.' );
}
}
2016-09-18 00:14:36 +00:00
/**
2016-12-07 22:46:38 +00:00
* [ updateContainer description ] .
2016-09-18 00:14:36 +00:00
* @ param int $id
* @ param array $data
* @ return bool
*/
public function updateContainer ( $id , array $data )
{
$validator = Validator :: make ( $data , [
2016-12-07 22:46:38 +00:00
'image' => 'required|string' ,
2016-09-18 00:14:36 +00:00
]);
// Run validator, throw catchable and displayable exception if it fails.
// Exception includes a JSON result of failed validation rules.
if ( $validator -> fails ()) {
throw new DisplayValidationException ( $validator -> errors ());
}
DB :: beginTransaction ();
try {
$server = Models\Server :: findOrFail ( $id );
$server -> image = $data [ 'image' ];
$server -> save ();
$node = Models\Node :: getByID ( $server -> node );
$client = Models\Node :: guzzleRequest ( $server -> node );
$client -> request ( 'PATCH' , '/server' , [
'headers' => [
'X-Access-Server' => $server -> uuid ,
2016-12-07 22:46:38 +00:00
'X-Access-Token' => $node -> daemonSecret ,
2016-09-18 00:14:36 +00:00
],
'json' => [
'build' => [
2016-12-07 22:46:38 +00:00
'image' => $server -> image ,
],
],
2016-09-18 00:14:36 +00:00
]);
DB :: commit ();
2016-12-07 22:46:38 +00:00
2016-09-18 00:14:36 +00:00
return true ;
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
DB :: rollBack ();
throw new DisplayException ( 'An error occured while attempting to update the container image.' , $ex );
} catch ( \Exception $ex ) {
DB :: rollBack ();
throw $ex ;
}
}
2016-01-03 04:21:22 +00:00
/**
2016-12-07 22:46:38 +00:00
* [ changeBuild description ] .
* @ param int $id
2016-01-03 04:21:22 +00:00
* @ param array $data
2016-12-07 22:46:38 +00:00
* @ return bool
2016-01-03 04:21:22 +00:00
*/
public function changeBuild ( $id , array $data )
{
$validator = Validator :: make ( $data , [
'default' => [
'string' ,
2016-12-07 22:46:38 +00:00
'regex:/^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5])):(\d{1,5})$/' ,
2016-01-03 04:21:22 +00:00
],
2016-09-14 22:36:12 +00:00
'add_additional' => 'nullable|array' ,
'remove_additional' => 'nullable|array' ,
2016-01-03 04:21:22 +00:00
'memory' => 'integer|min:0' ,
2016-02-13 05:06:23 +00:00
'swap' => 'integer|min:-1' ,
2016-01-03 04:21:22 +00:00
'io' => 'integer|min:10|max:1000' ,
'cpu' => 'integer|min:0' ,
2016-12-07 22:46:38 +00:00
'disk' => 'integer|min:0' ,
2016-01-03 04:21:22 +00:00
]);
// Run validator, throw catchable and displayable exception if it fails.
// Exception includes a JSON result of failed validation rules.
if ( $validator -> fails ()) {
throw new DisplayValidationException ( $validator -> errors ());
}
DB :: beginTransaction ();
2016-02-27 15:30:59 +00:00
try {
$server = Models\Server :: findOrFail ( $id );
2016-08-31 20:03:37 +00:00
$allocation = Models\Allocation :: findOrFail ( $server -> allocation );
2016-02-27 15:30:59 +00:00
2016-09-14 22:36:12 +00:00
$newBuild = [];
2016-02-27 15:30:59 +00:00
if ( isset ( $data [ 'default' ])) {
list ( $ip , $port ) = explode ( ':' , $data [ 'default' ]);
2016-09-14 22:36:12 +00:00
if ( $ip !== $allocation -> ip || ( int ) $port !== $allocation -> port ) {
2016-08-31 20:03:37 +00:00
$selection = Models\Allocation :: where ( 'ip' , $ip ) -> where ( 'port' , $port ) -> where ( 'assigned_to' , $server -> id ) -> first ();
2016-12-07 22:46:38 +00:00
if ( ! $selection ) {
2016-02-27 15:30:59 +00:00
throw new DisplayException ( 'The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.' );
}
2016-01-03 04:21:22 +00:00
2016-08-31 20:03:37 +00:00
$server -> allocation = $selection -> id ;
2016-09-14 22:36:12 +00:00
$newBuild [ 'default' ] = [
'ip' => $ip ,
2016-12-07 22:46:38 +00:00
'port' => ( int ) $port ,
2016-09-14 22:36:12 +00:00
];
2016-08-31 20:03:37 +00:00
// Re-Run to keep updated for rest of function
$allocation = Models\Allocation :: findOrFail ( $server -> allocation );
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
}
2016-09-14 22:36:12 +00:00
$newPorts = false ;
2016-02-27 15:30:59 +00:00
// Remove Assignments
if ( isset ( $data [ 'remove_additional' ])) {
foreach ( $data [ 'remove_additional' ] as $id => $combo ) {
list ( $ip , $port ) = explode ( ':' , $combo );
// Invalid, not worth killing the whole thing, we'll just skip over it.
2016-12-07 22:46:38 +00:00
if ( ! filter_var ( $ip , FILTER_VALIDATE_IP ) || ! preg_match ( '/^(\d{1,5})$/' , $port )) {
2016-10-23 22:59:13 +00:00
break ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-02-27 15:30:59 +00:00
// Can't remove the assigned IP/Port combo
2016-10-23 23:07:29 +00:00
if ( $ip === $allocation -> ip && ( int ) $port === ( int ) $allocation -> port ) {
2016-10-23 22:59:13 +00:00
break ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-10-23 23:07:29 +00:00
$newPorts = true ;
2016-02-27 15:30:59 +00:00
Models\Allocation :: where ( 'ip' , $ip ) -> where ( 'port' , $port ) -> where ( 'assigned_to' , $server -> id ) -> update ([
2016-12-07 22:46:38 +00:00
'assigned_to' => null ,
2016-02-27 15:30:59 +00:00
]);
}
2016-01-03 04:21:22 +00:00
}
2016-02-27 15:30:59 +00:00
// Add Assignments
if ( isset ( $data [ 'add_additional' ])) {
foreach ( $data [ 'add_additional' ] as $id => $combo ) {
list ( $ip , $port ) = explode ( ':' , $combo );
// Invalid, not worth killing the whole thing, we'll just skip over it.
2016-12-07 22:46:38 +00:00
if ( ! filter_var ( $ip , FILTER_VALIDATE_IP ) || ! preg_match ( '/^(\d{1,5})$/' , $port )) {
2016-10-23 22:59:13 +00:00
break ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-02-27 15:30:59 +00:00
// Don't allow double port assignments
if ( Models\Allocation :: where ( 'port' , $port ) -> where ( 'assigned_to' , $server -> id ) -> count () !== 0 ) {
2016-10-23 22:59:13 +00:00
break ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-10-23 23:07:29 +00:00
$newPorts = true ;
2016-02-27 15:30:59 +00:00
Models\Allocation :: where ( 'ip' , $ip ) -> where ( 'port' , $port ) -> whereNull ( 'assigned_to' ) -> update ([
2016-12-07 22:46:38 +00:00
'assigned_to' => $server -> id ,
2016-02-27 15:30:59 +00:00
]);
}
2016-01-03 04:21:22 +00:00
}
2016-02-27 15:30:59 +00:00
// Loop All Assignments
$additionalAssignments = [];
$assignments = Models\Allocation :: where ( 'assigned_to' , $server -> id ) -> get ();
foreach ( $assignments as & $assignment ) {
if ( array_key_exists (( string ) $assignment -> ip , $additionalAssignments )) {
2016-12-07 22:46:38 +00:00
array_push ( $additionalAssignments [( string ) $assignment -> ip ], ( int ) $assignment -> port );
2016-02-27 15:30:59 +00:00
} else {
2016-12-07 22:46:38 +00:00
$additionalAssignments [( string ) $assignment -> ip ] = [( int ) $assignment -> port ];
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
}
2016-09-14 22:36:12 +00:00
if ( $newPorts === true ) {
$newBuild [ 'ports|overwrite' ] = $additionalAssignments ;
}
2016-02-27 15:30:59 +00:00
// @TODO: verify that server can be set to this much memory without
// going over node limits.
2016-10-23 23:07:29 +00:00
if ( isset ( $data [ 'memory' ]) && $server -> memory !== ( int ) $data [ 'memory' ]) {
2016-02-27 15:30:59 +00:00
$server -> memory = $data [ 'memory' ];
2016-10-23 23:07:29 +00:00
$newBuild [ 'memory' ] = ( int ) $server -> memory ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-10-23 23:07:29 +00:00
if ( isset ( $data [ 'swap' ]) && $server -> swap !== ( int ) $data [ 'swap' ]) {
2016-02-27 15:30:59 +00:00
$server -> swap = $data [ 'swap' ];
2016-10-23 23:07:29 +00:00
$newBuild [ 'swap' ] = ( int ) $server -> swap ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-02-27 15:30:59 +00:00
// @TODO: verify that server can be set to this much disk without
// going over node limits.
2016-10-23 23:07:29 +00:00
if ( isset ( $data [ 'disk' ]) && $server -> disk !== ( int ) $data [ 'disk' ]) {
2016-02-27 15:30:59 +00:00
$server -> disk = $data [ 'disk' ];
2016-10-23 23:07:29 +00:00
$newBuild [ 'disk' ] = ( int ) $server -> disk ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-10-23 23:07:29 +00:00
if ( isset ( $data [ 'cpu' ]) && $server -> cpu !== ( int ) $data [ 'cpu' ]) {
2016-02-27 15:30:59 +00:00
$server -> cpu = $data [ 'cpu' ];
2016-10-23 23:07:29 +00:00
$newBuild [ 'cpu' ] = ( int ) $server -> cpu ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-10-23 23:07:29 +00:00
if ( isset ( $data [ 'io' ]) && $server -> io !== ( int ) $data [ 'io' ]) {
2016-02-27 15:30:59 +00:00
$server -> io = $data [ 'io' ];
2016-10-23 23:07:29 +00:00
$newBuild [ 'io' ] = ( int ) $server -> io ;
2016-02-27 15:30:59 +00:00
}
2016-01-03 04:21:22 +00:00
2016-08-31 20:09:23 +00:00
// Try save() here so if it fails we haven't contacted the daemon
// This won't be committed unless the HTTP request succeedes anyways
$server -> save ();
2016-12-07 22:46:38 +00:00
if ( ! empty ( $newBuild )) {
2016-10-23 23:07:29 +00:00
$node = Models\Node :: getByID ( $server -> node );
$client = Models\Node :: guzzleRequest ( $server -> node );
2016-09-14 22:36:12 +00:00
2016-10-23 23:07:29 +00:00
$client -> request ( 'PATCH' , '/server' , [
'headers' => [
'X-Access-Server' => $server -> uuid ,
2016-12-07 22:46:38 +00:00
'X-Access-Token' => $node -> daemonSecret ,
2016-10-23 23:07:29 +00:00
],
'json' => [
2016-12-07 22:46:38 +00:00
'build' => $newBuild ,
],
2016-10-23 23:07:29 +00:00
]);
}
2016-08-31 20:09:23 +00:00
2016-01-03 04:21:22 +00:00
DB :: commit ();
2016-12-07 22:46:38 +00:00
2016-01-03 04:21:22 +00:00
return true ;
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
DB :: rollBack ();
2016-08-16 23:20:58 +00:00
throw new DisplayException ( 'An error occured while attempting to update the configuration.' , $ex );
2016-01-23 02:43:56 +00:00
} catch ( \Exception $ex ) {
DB :: rollBack ();
throw $ex ;
2016-01-03 04:21:22 +00:00
}
}
2016-02-13 22:36:03 +00:00
public function updateStartup ( $id , array $data , $admin = false )
2016-01-10 23:57:22 +00:00
{
$server = Models\Server :: findOrFail ( $id );
DB :: beginTransaction ();
2016-02-13 22:29:52 +00:00
try {
2016-02-27 15:30:59 +00:00
// Check the startup
if ( isset ( $data [ 'startup' ])) {
$server -> startup = $data [ 'startup' ];
$server -> save ();
}
// Check those Variables
$variables = Models\ServiceVariables :: select (
'service_variables.*' ,
DB :: raw ( 'COALESCE(server_variables.variable_value, service_variables.default_value) as a_currentValue' )
) -> leftJoin ( 'server_variables' , 'server_variables.variable_id' , '=' , 'service_variables.id' )
-> where ( 'option_id' , $server -> option )
-> get ();
2016-02-13 22:29:52 +00:00
$variableList = [];
if ( $variables ) {
2016-12-07 22:46:38 +00:00
foreach ( $variables as & $variable ) {
2016-02-13 22:29:52 +00:00
// Move on if the new data wasn't even sent
2016-12-07 22:46:38 +00:00
if ( ! isset ( $data [ $variable -> env_variable ])) {
2016-12-12 19:30:57 +00:00
$variableList [] = [
2016-02-13 22:29:52 +00:00
'id' => $variable -> id ,
'env' => $variable -> env_variable ,
2016-12-07 22:46:38 +00:00
'val' => $variable -> a_currentValue ,
2016-12-12 19:30:57 +00:00
];
2016-02-13 22:29:52 +00:00
continue ;
}
// Update Empty but skip validation
if ( empty ( $data [ $variable -> env_variable ])) {
2016-12-12 19:30:57 +00:00
$variableList [] = [
2016-02-13 22:29:52 +00:00
'id' => $variable -> id ,
'env' => $variable -> env_variable ,
2016-12-07 22:46:38 +00:00
'val' => null ,
2016-12-12 19:30:57 +00:00
];
2016-02-13 22:29:52 +00:00
continue ;
}
// Is the variable required?
// @TODO: is this even logical to perform this check?
if ( isset ( $data [ $variable -> env_variable ]) && empty ( $data [ $variable -> env_variable ])) {
if ( $variable -> required === 1 ) {
throw new DisplayException ( 'A required service option variable field (' . $variable -> env_variable . ') was included in this request but was left blank.' );
}
}
// Variable hidden and/or not user editable
2016-12-07 22:46:38 +00:00
if (( $variable -> user_viewable === 0 || $variable -> user_editable === 0 ) && ! $admin ) {
2016-02-13 22:29:52 +00:00
throw new DisplayException ( 'A service option variable field (' . $variable -> env_variable . ') does not exist or you do not have permission to edit it.' );
}
// Check aganist Regex Pattern
2016-12-07 22:46:38 +00:00
if ( ! is_null ( $variable -> regex ) && ! preg_match ( $variable -> regex , $data [ $variable -> env_variable ])) {
2016-02-13 22:29:52 +00:00
throw new DisplayException ( 'Failed to validate service option variable field (' . $variable -> env_variable . ') aganist regex (' . $variable -> regex . ').' );
}
2016-01-10 23:57:22 +00:00
2016-12-12 19:30:57 +00:00
$variableList [] = [
2016-01-10 23:57:22 +00:00
'id' => $variable -> id ,
'env' => $variable -> env_variable ,
2016-12-07 22:46:38 +00:00
'val' => $data [ $variable -> env_variable ],
2016-12-12 19:30:57 +00:00
];
2016-01-10 23:57:22 +00:00
}
}
2016-02-13 22:29:52 +00:00
// Add Variables
2016-12-12 19:30:57 +00:00
$environmentVariables = [
2016-12-07 22:46:38 +00:00
'STARTUP' => $server -> startup ,
2016-12-12 19:30:57 +00:00
];
2016-12-07 22:46:38 +00:00
foreach ( $variableList as $item ) {
2016-12-12 19:30:57 +00:00
$environmentVariables [ $item [ 'env' ]] = $item [ 'val' ];
2016-01-10 23:57:22 +00:00
2016-02-13 22:29:52 +00:00
// Update model or make a new record if it doesn't exist.
$model = Models\ServerVariables :: firstOrNew ([
'variable_id' => $item [ 'id' ],
2016-12-07 22:46:38 +00:00
'server_id' => $server -> id ,
2016-02-13 22:29:52 +00:00
]);
$model -> variable_value = $item [ 'val' ];
$model -> save ();
}
2016-01-10 23:57:22 +00:00
$node = Models\Node :: getByID ( $server -> node );
$client = Models\Node :: guzzleRequest ( $server -> node );
$client -> request ( 'PATCH' , '/server' , [
'headers' => [
'X-Access-Server' => $server -> uuid ,
2016-12-07 22:46:38 +00:00
'X-Access-Token' => $node -> daemonSecret ,
2016-01-10 23:57:22 +00:00
],
'json' => [
'build' => [
2016-12-07 22:46:38 +00:00
'env|overwrite' => $environmentVariables ,
],
],
2016-01-10 23:57:22 +00:00
]);
DB :: commit ();
2016-12-07 22:46:38 +00:00
2016-01-10 23:57:22 +00:00
return true ;
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
DB :: rollBack ();
2016-08-16 23:20:58 +00:00
throw new DisplayException ( 'An error occured while attempting to update the server configuration.' , $ex );
2016-02-13 22:29:52 +00:00
} catch ( \Exception $ex ) {
2016-01-10 23:57:22 +00:00
DB :: rollBack ();
2016-02-13 22:29:52 +00:00
throw $ex ;
2016-01-10 23:57:22 +00:00
}
}
2016-01-04 04:16:03 +00:00
public function deleteServer ( $id , $force )
{
$server = Models\Server :: findOrFail ( $id );
DB :: beginTransaction ();
2016-02-27 15:30:59 +00:00
try {
2016-10-28 00:05:29 +00:00
if ( $force === 'force' || $force === true ) {
$server -> installed = 3 ;
$server -> save ();
}
$server -> delete ();
2017-01-25 00:15:03 +00:00
return DB :: commit ();
2016-10-28 00:05:29 +00:00
} catch ( \Exception $ex ) {
DB :: rollBack ();
throw $ex ;
}
}
2016-12-07 22:46:38 +00:00
public function deleteNow ( $id , $force = false )
{
2016-10-28 00:05:29 +00:00
$server = Models\Server :: withTrashed () -> findOrFail ( $id );
$node = Models\Node :: findOrFail ( $server -> node );
// Handle server being restored previously or
// an accidental queue.
2016-12-07 22:46:38 +00:00
if ( ! $server -> trashed ()) {
2016-10-28 00:05:29 +00:00
return ;
}
DB :: beginTransaction ();
try {
// Unassign Allocations
2016-02-27 15:30:59 +00:00
Models\Allocation :: where ( 'assigned_to' , $server -> id ) -> update ([
2016-12-07 22:46:38 +00:00
'assigned_to' => null ,
2016-02-27 15:30:59 +00:00
]);
2016-01-04 04:16:03 +00:00
2016-02-27 15:30:59 +00:00
// Remove Variables
Models\ServerVariables :: where ( 'server_id' , $server -> id ) -> delete ();
2016-01-04 04:16:03 +00:00
2016-10-28 00:05:29 +00:00
// Remove Permissions (Foreign Key requires before Subusers)
Models\Permission :: where ( 'server_id' , $server -> id ) -> delete ();
2016-02-27 15:30:59 +00:00
// Remove SubUsers
Models\Subuser :: where ( 'server_id' , $server -> id ) -> delete ();
2016-01-04 04:16:03 +00:00
2016-02-27 15:30:59 +00:00
// Remove Downloads
Models\Download :: where ( 'server' , $server -> uuid ) -> delete ();
2016-01-04 04:16:03 +00:00
2016-10-28 00:05:29 +00:00
// Clear Tasks
Models\Task :: where ( 'server' , $server -> id ) -> delete ();
2016-10-23 23:21:57 +00:00
// Delete Databases
2016-10-28 00:05:29 +00:00
// This is the one un-recoverable point where
// transactions will not save us.
2016-10-23 23:21:57 +00:00
$repository = new DatabaseRepository ;
2016-12-07 22:46:38 +00:00
foreach ( Models\Database :: select ( 'id' ) -> where ( 'server_id' , $server -> id ) -> get () as & $database ) {
2016-10-23 23:21:57 +00:00
$repository -> drop ( $database -> id );
}
2016-01-04 04:16:03 +00:00
$client = Models\Node :: guzzleRequest ( $server -> node );
$client -> request ( 'DELETE' , '/servers' , [
'headers' => [
'X-Access-Token' => $node -> daemonSecret ,
2016-12-07 22:46:38 +00:00
'X-Access-Server' => $server -> uuid ,
],
2016-01-04 04:16:03 +00:00
]);
2016-10-28 00:05:29 +00:00
$server -> forceDelete ();
2016-01-04 04:16:03 +00:00
DB :: commit ();
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
2016-10-28 00:05:29 +00:00
// Set installed is set to 3 when force deleting.
if ( $server -> installed === 3 || $force ) {
$server -> forceDelete ();
2016-01-04 04:16:03 +00:00
DB :: commit ();
} else {
DB :: rollBack ();
2016-10-28 00:05:29 +00:00
throw $ex ;
2016-01-04 04:16:03 +00:00
}
} catch ( \Exception $ex ) {
DB :: rollBack ();
throw $ex ;
}
}
2016-10-28 00:05:29 +00:00
public function cancelDeletion ( $id )
{
$server = Models\Server :: withTrashed () -> findOrFail ( $id );
$server -> restore ();
$server -> installed = 1 ;
$server -> save ();
}
2016-01-04 21:09:22 +00:00
public function toggleInstall ( $id )
{
$server = Models\Server :: findOrFail ( $id );
2016-01-23 01:39:16 +00:00
if ( $server -> installed === 2 ) {
throw new DisplayException ( 'This server was marked as having a failed install, you cannot override this.' );
}
2016-01-04 21:09:22 +00:00
$server -> installed = ( $server -> installed === 1 ) ? 0 : 1 ;
2016-12-07 22:46:38 +00:00
2016-01-04 21:09:22 +00:00
return $server -> save ();
}
2016-01-16 05:25:21 +00:00
/**
* Suspends a server instance making it unable to be booted or used by a user .
2016-12-07 22:46:38 +00:00
* @ param int $id
* @ return bool
2016-01-16 05:25:21 +00:00
*/
2016-10-28 00:05:29 +00:00
public function suspend ( $id , $deleted = false )
2016-01-16 05:25:21 +00:00
{
2016-10-28 00:05:29 +00:00
$server = ( $deleted ) ? Models\Server :: withTrashed () -> findOrFail ( $id ) : Models\Server :: findOrFail ( $id );
2016-09-02 01:16:38 +00:00
$node = Models\Node :: findOrFail ( $server -> node );
DB :: beginTransaction ();
try {
2016-09-05 20:21:36 +00:00
// Already suspended, no need to make more requests.
if ( $server -> suspended === 1 ) {
return true ;
}
2016-09-02 01:16:38 +00:00
$server -> suspended = 1 ;
$server -> save ();
$client = Models\Node :: guzzleRequest ( $server -> node );
$client -> request ( 'POST' , '/server/suspend' , [
'headers' => [
'X-Access-Token' => $node -> daemonSecret ,
2016-12-07 22:46:38 +00:00
'X-Access-Server' => $server -> uuid ,
],
2016-09-02 01:16:38 +00:00
]);
return DB :: commit ();
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
DB :: rollBack ();
2016-09-05 20:21:36 +00:00
throw new DisplayException ( 'An error occured while attempting to contact the remote daemon to suspend this server.' , $ex );
2016-09-02 01:16:38 +00:00
} catch ( \Exception $ex ) {
DB :: rollBack ();
throw $ex ;
}
2016-01-16 05:25:21 +00:00
}
/**
* Unsuspends a server instance .
2016-12-07 22:46:38 +00:00
* @ param int $id
* @ return bool
2016-01-16 05:25:21 +00:00
*/
public function unsuspend ( $id )
{
2016-09-02 01:16:38 +00:00
$server = Models\Server :: findOrFail ( $id );
$node = Models\Node :: findOrFail ( $server -> node );
DB :: beginTransaction ();
try {
2016-09-05 20:21:36 +00:00
// Already unsuspended, no need to make more requests.
if ( $server -> suspended === 0 ) {
return true ;
}
2016-09-02 01:16:38 +00:00
$server -> suspended = 0 ;
$server -> save ();
$client = Models\Node :: guzzleRequest ( $server -> node );
$client -> request ( 'POST' , '/server/unsuspend' , [
'headers' => [
'X-Access-Token' => $node -> daemonSecret ,
2016-12-07 22:46:38 +00:00
'X-Access-Server' => $server -> uuid ,
],
2016-09-02 01:16:38 +00:00
]);
return DB :: commit ();
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
DB :: rollBack ();
2016-09-05 20:21:36 +00:00
throw new DisplayException ( 'An error occured while attempting to contact the remote daemon to un-suspend this server.' , $ex );
2016-09-02 01:16:38 +00:00
} catch ( \Exception $ex ) {
DB :: rollBack ();
throw $ex ;
}
2016-01-16 05:25:21 +00:00
}
2016-01-22 04:53:48 +00:00
public function updateSFTPPassword ( $id , $password )
{
$server = Models\Server :: findOrFail ( $id );
$node = Models\Node :: findOrFail ( $server -> node );
$validator = Validator :: make ([
'password' => $password ,
], [
2016-12-07 22:46:38 +00:00
'password' => 'required|regex:/^((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})$/' ,
2016-01-22 04:53:48 +00:00
]);
if ( $validator -> fails ()) {
throw new DisplayValidationException ( json_encode ( $validator -> errors ()));
}
2016-09-02 23:26:48 +00:00
DB :: beginTransaction ();
$server -> sftp_password = Crypt :: encrypt ( $password );
2016-01-22 04:53:48 +00:00
try {
2016-09-02 23:26:48 +00:00
$server -> save ();
2016-01-22 04:53:48 +00:00
$client = Models\Node :: guzzleRequest ( $server -> node );
$client -> request ( 'POST' , '/server/password' , [
'headers' => [
'X-Access-Token' => $node -> daemonSecret ,
2016-12-07 22:46:38 +00:00
'X-Access-Server' => $server -> uuid ,
2016-01-22 04:53:48 +00:00
],
'json' => [
'password' => $password ,
],
]);
2016-09-02 23:26:48 +00:00
DB :: commit ();
2016-12-07 22:46:38 +00:00
2016-01-22 04:53:48 +00:00
return true ;
} catch ( \GuzzleHttp\Exception\TransferException $ex ) {
2016-09-02 23:26:48 +00:00
DB :: rollBack ();
2016-08-16 23:20:58 +00:00
throw new DisplayException ( 'There was an error while attmping to contact the remote service to change the password.' , $ex );
2016-01-22 04:53:48 +00:00
} catch ( \Exception $ex ) {
2016-09-02 23:26:48 +00:00
DB :: rollBack ();
2016-01-22 04:53:48 +00:00
throw $ex ;
}
}
2015-12-14 03:22:16 +00:00
}