diff --git a/app/Contracts/Repository/DatabaseRepositoryInterface.php b/app/Contracts/Repository/DatabaseRepositoryInterface.php index e04c5a862..967ca20fb 100644 --- a/app/Contracts/Repository/DatabaseRepositoryInterface.php +++ b/app/Contracts/Repository/DatabaseRepositoryInterface.php @@ -68,9 +68,10 @@ interface DatabaseRepositoryInterface extends RepositoryInterface * @param string $username * @param string $remote * @param string $password + * @param $max_connections * @return bool */ - public function createUser(string $username, string $remote, string $password): bool; + public function createUser(string $username, string $remote, string $password, string $max_connections): bool; /** * Give a specific user access to a given database. diff --git a/app/Http/Requests/Admin/Servers/Databases/StoreServerDatabaseRequest.php b/app/Http/Requests/Admin/Servers/Databases/StoreServerDatabaseRequest.php index ba8b76a83..40a4b06bc 100644 --- a/app/Http/Requests/Admin/Servers/Databases/StoreServerDatabaseRequest.php +++ b/app/Http/Requests/Admin/Servers/Databases/StoreServerDatabaseRequest.php @@ -25,6 +25,7 @@ class StoreServerDatabaseRequest extends AdminFormRequest $query->where('database_host_id', $this->input('database_host_id') ?? 0); }), ], + 'max_connections' => 'nullable', 'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/', 'database_host_id' => 'required|integer|exists:database_hosts,id', ]; diff --git a/app/Models/Database.php b/app/Models/Database.php index 2db45734d..ae20a51c8 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -30,7 +30,7 @@ class Database extends Model * @var array */ protected $fillable = [ - 'server_id', 'database_host_id', 'database', 'username', 'password', 'remote', + 'server_id', 'database_host_id', 'database', 'username', 'password', 'remote', 'max_connections', ]; /** @@ -41,6 +41,7 @@ class Database extends Model protected $casts = [ 'server_id' => 'integer', 'database_host_id' => 'integer', + 'max_connections' => 'integer', ]; /** @@ -51,6 +52,7 @@ class Database extends Model 'database_host_id' => 'required|exists:database_hosts,id', 'database' => 'required|string|alpha_dash|between:3,100', 'username' => 'string|alpha_dash|between:3,100', + 'max_connections' => 'nullable|integer', 'remote' => 'required|string|regex:/^[0-9%.]{1,15}$/', 'password' => 'string', ]; diff --git a/app/Repositories/Eloquent/DatabaseRepository.php b/app/Repositories/Eloquent/DatabaseRepository.php index c26be52f3..df9dbb6ee 100644 --- a/app/Repositories/Eloquent/DatabaseRepository.php +++ b/app/Repositories/Eloquent/DatabaseRepository.php @@ -135,11 +135,16 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor * @param string $username * @param string $remote * @param string $password + * @param $max_connections * @return bool */ - public function createUser(string $username, string $remote, string $password): bool + public function createUser(string $username, string $remote, string $password, $max_connections): bool { - return $this->run(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', $username, $remote, $password)); + if (!$max_connections) { + return $this->run(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', $username, $remote, $password)); + } else { + return $this->run(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\' WITH MAX_USER_CONNECTIONS %s', $username, $remote, $password, $max_connections)); + } } /** diff --git a/app/Services/Databases/DatabaseManagementService.php b/app/Services/Databases/DatabaseManagementService.php index 0f07ad704..b98a757db 100644 --- a/app/Services/Databases/DatabaseManagementService.php +++ b/app/Services/Databases/DatabaseManagementService.php @@ -84,7 +84,8 @@ class DatabaseManagementService $this->repository->createUser( $database->username, $database->remote, - $this->encrypter->decrypt($database->password) + $this->encrypter->decrypt($database->password), + $database->max_connections ); $this->repository->assignUserToDatabase( $database->database, diff --git a/app/Services/Databases/DatabasePasswordService.php b/app/Services/Databases/DatabasePasswordService.php index 6abb0a499..2a9ebcabe 100644 --- a/app/Services/Databases/DatabasePasswordService.php +++ b/app/Services/Databases/DatabasePasswordService.php @@ -71,7 +71,7 @@ class DatabasePasswordService ]); $this->repository->dropUser($database->username, $database->remote); - $this->repository->createUser($database->username, $database->remote, $password); + $this->repository->createUser($database->username, $database->remote, $password, $database->max_connections); $this->repository->assignUserToDatabase($database->database, $database->username, $database->remote); $this->repository->flush(); }); diff --git a/app/Transformers/Api/Application/ServerDatabaseTransformer.php b/app/Transformers/Api/Application/ServerDatabaseTransformer.php index 1cdced612..a88ba6e8c 100644 --- a/app/Transformers/Api/Application/ServerDatabaseTransformer.php +++ b/app/Transformers/Api/Application/ServerDatabaseTransformer.php @@ -56,6 +56,7 @@ class ServerDatabaseTransformer extends BaseTransformer 'database' => $model->database, 'username' => $model->username, 'remote' => $model->remote, + 'max_connections' => $model->max_connections, 'created_at' => Chronos::createFromFormat(Chronos::DEFAULT_TO_STRING_FORMAT, $model->created_at) ->setTimezone(config('app.timezone')) ->toIso8601String(), diff --git a/app/Transformers/Api/Client/DatabaseTransformer.php b/app/Transformers/Api/Client/DatabaseTransformer.php index feb6002eb..8d420ea83 100644 --- a/app/Transformers/Api/Client/DatabaseTransformer.php +++ b/app/Transformers/Api/Client/DatabaseTransformer.php @@ -58,6 +58,7 @@ class DatabaseTransformer extends BaseClientTransformer 'name' => $model->database, 'username' => $model->username, 'connections_from' => $model->remote, + 'max_connections' => $model->max_connections, ]; } diff --git a/database/migrations/2020_04_22_055500_add_max_connections_column.php b/database/migrations/2020_04_22_055500_add_max_connections_column.php new file mode 100644 index 000000000..9af4f4684 --- /dev/null +++ b/database/migrations/2020_04_22_055500_add_max_connections_column.php @@ -0,0 +1,32 @@ +integer('max_connections')->nullable()->default(0)->after('password'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('databases', function (Blueprint $table) { + $table->dropColumn('max_connections'); + }); + } +} diff --git a/resources/scripts/components/server/databases/DatabaseRow.tsx b/resources/scripts/components/server/databases/DatabaseRow.tsx index a80b304c3..9adc38519 100644 --- a/resources/scripts/components/server/databases/DatabaseRow.tsx +++ b/resources/scripts/components/server/databases/DatabaseRow.tsx @@ -51,7 +51,7 @@ export default ({ database, className }: Props) => { addError({ key: 'database:delete', message: httpErrorToHuman(error) }); }); }; - + return ( Database Name Username Connections From + Max Connections @foreach($databases as $database) @@ -107,6 +108,11 @@ {{ $database->database }} {{ $database->username }} {{ $database->remote }} + @if($database->max_connections != null) + {{ $database->max_connections }} + @else + Unlimited + @endif diff --git a/resources/views/admin/servers/view/database.blade.php b/resources/views/admin/servers/view/database.blade.php index 7798487c2..f861008eb 100644 --- a/resources/views/admin/servers/view/database.blade.php +++ b/resources/views/admin/servers/view/database.blade.php @@ -37,6 +37,7 @@ Username Connections From Host + Max Conenctions @foreach($server->databases as $database) @@ -45,6 +46,11 @@ {{ $database->username }} {{ $database->remote }} {{ $database->host->host }}:{{ $database->host->port }} + @if($database->max_connections != null) + {{ $database->max_connections }} + @else + Unlimited + @endif @@ -83,6 +89,11 @@

This should reflect the IP address that connections are allowed from. Uses standard MySQL notation. If unsure leave as %.

+
+ + +

This should reflect the max number of concurrent connections from this user to the database. Leave empty for unlimited.

+