diff --git a/app/Enums/Database.php b/app/Enums/Database.php index 95d7308..e9010a4 100644 --- a/app/Enums/Database.php +++ b/app/Enums/Database.php @@ -13,4 +13,14 @@ final class Database extends Enum const MYSQL80 = 'mysql80'; const MARIADB = 'mariadb'; + + const POSTGRESQL12 = 'postgresql12'; + + const POSTGRESQL13 = 'postgresql13'; + + const POSTGRESQL14 = 'postgresql14'; + + const POSTGRESQL15 = 'postgresql15'; + + const POSTGRESQL16 = 'postgresql16'; } diff --git a/app/SSH/Services/Database/AbstractDatabase.php b/app/SSH/Services/Database/AbstractDatabase.php index 397be36..538d77d 100755 --- a/app/SSH/Services/Database/AbstractDatabase.php +++ b/app/SSH/Services/Database/AbstractDatabase.php @@ -2,6 +2,7 @@ namespace App\SSH\Services\Database; +use App\Models\BackupFile; use App\Models\Server; use App\Models\Service; use App\SSH\HasScripts; @@ -15,6 +16,8 @@ abstract class AbstractDatabase implements Database, ServiceInterface protected Server $server; + abstract protected function getScriptsDir(): string; + public function __construct(Service $service) { $this->service = $service; @@ -29,4 +32,115 @@ public function install(): void $status = $this->server->systemd()->status($this->service->unit); $this->service->validateInstall($status); } + + public function create(string $name): void + { + $this->server->ssh()->exec( + $this->getScript($this->getScriptsDir().'/create.sh', [ + 'name' => $name, + ]), + 'create-database' + ); + } + + public function delete(string $name): void + { + $this->server->ssh()->exec( + $this->getScript($this->getScriptsDir().'/delete.sh', [ + 'name' => $name, + ]), + 'delete-database' + ); + } + + public function createUser(string $username, string $password, string $host): void + { + $this->server->ssh()->exec( + $this->getScript($this->getScriptsDir().'/create-user.sh', [ + 'username' => $username, + 'password' => $password, + 'host' => $host, + ]), + 'create-user' + ); + } + + public function deleteUser(string $username, string $host): void + { + $this->server->ssh()->exec( + $this->getScript($this->getScriptsDir().'/delete-user.sh', [ + 'username' => $username, + 'host' => $host, + ]), + 'delete-user' + ); + } + + public function link(string $username, string $host, array $databases): void + { + $ssh = $this->server->ssh(); + + foreach ($databases as $database) { + $ssh->exec( + $this->getScript($this->getScriptsDir().'/link.sh', [ + 'username' => $username, + 'host' => $host, + 'database' => $database, + ]), + 'link-user-to-database' + ); + } + } + + public function unlink(string $username, string $host): void + { + $this->server->ssh()->exec( + $this->getScript($this->getScriptsDir().'/unlink.sh', [ + 'username' => $username, + 'host' => $host, + ]), + 'unlink-user-from-databases' + ); + } + + public function runBackup(BackupFile $backupFile): void + { + // backup + $this->server->ssh()->exec( + $this->getScript($this->getScriptsDir().'/backup.sh', [ + 'file' => $backupFile->name, + 'database' => $backupFile->backup->database->name, + ]), + 'backup-database' + ); + + // upload to storage + $upload = $backupFile->backup->storage->provider()->ssh($this->server)->upload( + $backupFile->path(), + $backupFile->storagePath(), + ); + + // cleanup + $this->server->ssh()->exec('rm '.$backupFile->name.'.zip'); + + $backupFile->size = $upload['size']; + $backupFile->save(); + } + + public function restoreBackup(BackupFile $backupFile, string $database): void + { + // download + $backupFile->backup->storage->provider()->ssh($this->server)->download( + $backupFile->storagePath(), + $backupFile->name.'.zip', + ); + + $this->server->ssh()->exec( + $this->getScript($this->getScriptsDir().'/restore.sh', [ + 'database' => $database, + 'file' => $backupFile->name, + ]), + 'restore-database' + ); + } } diff --git a/app/SSH/Services/Database/Mariadb.php b/app/SSH/Services/Database/Mariadb.php index e6c9003..813478a 100644 --- a/app/SSH/Services/Database/Mariadb.php +++ b/app/SSH/Services/Database/Mariadb.php @@ -2,7 +2,10 @@ namespace App\SSH\Services\Database; -class Mariadb extends Mysql +class Mariadb extends AbstractDatabase { - // + protected function getScriptsDir(): string + { + return 'mysql'; + } } diff --git a/app/SSH/Services/Database/Mysql.php b/app/SSH/Services/Database/Mysql.php index 0ef31e4..cca160e 100755 --- a/app/SSH/Services/Database/Mysql.php +++ b/app/SSH/Services/Database/Mysql.php @@ -2,121 +2,10 @@ namespace App\SSH\Services\Database; -use App\Models\BackupFile; -use App\SSH\HasScripts; - class Mysql extends AbstractDatabase { - use HasScripts; - - public function create(string $name): void + protected function getScriptsDir(): string { - $this->server->ssh()->exec( - $this->getScript('mysql/create.sh', [ - 'name' => $name, - ]), - 'create-database' - ); - } - - public function delete(string $name): void - { - $this->server->ssh()->exec( - $this->getScript('mysql/delete.sh', [ - 'name' => $name, - ]), - 'delete-database' - ); - } - - public function createUser(string $username, string $password, string $host): void - { - $this->server->ssh()->exec( - $this->getScript('mysql/create-user.sh', [ - 'username' => $username, - 'password' => $password, - 'host' => $host, - ]), - 'create-user' - ); - } - - public function deleteUser(string $username, string $host): void - { - $this->server->ssh()->exec( - $this->getScript('mysql/delete-user.sh', [ - 'username' => $username, - 'host' => $host, - ]), - 'delete-user' - ); - } - - public function link(string $username, string $host, array $databases): void - { - $ssh = $this->server->ssh(); - - foreach ($databases as $database) { - $ssh->exec( - $this->getScript('mysql/link.sh', [ - 'username' => $username, - 'host' => $host, - 'database' => $database, - ]), - 'link-user-to-database' - ); - } - } - - public function unlink(string $username, string $host): void - { - $this->server->ssh()->exec( - $this->getScript('mysql/unlink.sh', [ - 'username' => $username, - 'host' => $host, - ]), - 'unlink-user-from-databases' - ); - } - - public function runBackup(BackupFile $backupFile): void - { - // backup - $this->server->ssh()->exec( - $this->getScript('mysql/backup.sh', [ - 'file' => $backupFile->name, - 'database' => $backupFile->backup->database->name, - ]), - 'backup-database' - ); - - // upload to storage - $upload = $backupFile->backup->storage->provider()->ssh($this->server)->upload( - $backupFile->path(), - $backupFile->storagePath(), - ); - - // cleanup - $this->server->ssh()->exec('rm '.$backupFile->name.'.zip'); - - $backupFile->size = $upload['size']; - $backupFile->save(); - } - - public function restoreBackup(BackupFile $backupFile, string $database): void - { - // download - $backupFile->backup->storage->provider()->ssh($this->server)->download( - $backupFile->storagePath(), - $backupFile->name.'.zip', - ); - - $this->server->ssh()->exec( - $this->getScript('mysql/restore.sh', [ - 'database' => $database, - 'file' => $backupFile->name, - ]), - 'restore-database' - ); + return 'mysql'; } } diff --git a/app/SSH/Services/Database/Postgresql.php b/app/SSH/Services/Database/Postgresql.php new file mode 100644 index 0000000..0f06049 --- /dev/null +++ b/app/SSH/Services/Database/Postgresql.php @@ -0,0 +1,11 @@ + /etc/apt/sources.list.d/pgdg.list' + +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + +sudo DEBIAN_FRONTEND=noninteractive apt-get update -y + +sudo DEBIAN_FRONTEND=noninteractive apt-get install postgresql-12 -y + +systemctl status postgresql + +sudo -u postgres psql -c "SELECT version();" diff --git a/app/SSH/Services/Database/scripts/postgresql/install-13.sh b/app/SSH/Services/Database/scripts/postgresql/install-13.sh new file mode 100644 index 0000000..5945f71 --- /dev/null +++ b/app/SSH/Services/Database/scripts/postgresql/install-13.sh @@ -0,0 +1,11 @@ +sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' + +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + +sudo DEBIAN_FRONTEND=noninteractive apt-get update -y + +sudo DEBIAN_FRONTEND=noninteractive apt-get install postgresql-13 -y + +systemctl status postgresql + +sudo -u postgres psql -c "SELECT version();" diff --git a/app/SSH/Services/Database/scripts/postgresql/install-14.sh b/app/SSH/Services/Database/scripts/postgresql/install-14.sh new file mode 100644 index 0000000..d60cd4f --- /dev/null +++ b/app/SSH/Services/Database/scripts/postgresql/install-14.sh @@ -0,0 +1,11 @@ +sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' + +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + +sudo DEBIAN_FRONTEND=noninteractive apt-get update -y + +sudo DEBIAN_FRONTEND=noninteractive apt-get install postgresql-14 -y + +systemctl status postgresql + +sudo -u postgres psql -c "SELECT version();" diff --git a/app/SSH/Services/Database/scripts/postgresql/install-15.sh b/app/SSH/Services/Database/scripts/postgresql/install-15.sh new file mode 100644 index 0000000..d8de5fa --- /dev/null +++ b/app/SSH/Services/Database/scripts/postgresql/install-15.sh @@ -0,0 +1,11 @@ +sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' + +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + +sudo DEBIAN_FRONTEND=noninteractive apt-get update -y + +sudo DEBIAN_FRONTEND=noninteractive apt-get install postgresql-15 -y + +systemctl status postgresql + +sudo -u postgres psql -c "SELECT version();" diff --git a/app/SSH/Services/Database/scripts/postgresql/install-16.sh b/app/SSH/Services/Database/scripts/postgresql/install-16.sh new file mode 100644 index 0000000..3a1f0c4 --- /dev/null +++ b/app/SSH/Services/Database/scripts/postgresql/install-16.sh @@ -0,0 +1,11 @@ +sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' + +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + +sudo DEBIAN_FRONTEND=noninteractive apt-get update -y + +sudo DEBIAN_FRONTEND=noninteractive apt-get install postgresql-16 -y + +systemctl status postgresql + +sudo -u postgres psql -c "SELECT version();" diff --git a/app/SSH/Services/Database/scripts/postgresql/link.sh b/app/SSH/Services/Database/scripts/postgresql/link.sh new file mode 100755 index 0000000..2459c2e --- /dev/null +++ b/app/SSH/Services/Database/scripts/postgresql/link.sh @@ -0,0 +1,5 @@ +if ! sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE __database__ TO __username__;"; then + echo 'VITO_SSH_ERROR' && exit 1 +fi + +echo "Linking to __database__ finished" diff --git a/app/SSH/Services/Database/scripts/postgresql/restore.sh b/app/SSH/Services/Database/scripts/postgresql/restore.sh new file mode 100644 index 0000000..eaa0896 --- /dev/null +++ b/app/SSH/Services/Database/scripts/postgresql/restore.sh @@ -0,0 +1,11 @@ +if ! DEBIAN_FRONTEND=noninteractive unzip __file__.zip; then + echo 'VITO_SSH_ERROR' && exit 1 +fi + +if ! sudo -u postgres psql -d __database__ -f __file__.sql; then + echo 'VITO_SSH_ERROR' && exit 1 +fi + +if ! rm __file__.sql __file__.zip; then + echo 'VITO_SSH_ERROR' && exit 1 +fi diff --git a/app/SSH/Services/Database/scripts/postgresql/unlink.sh b/app/SSH/Services/Database/scripts/postgresql/unlink.sh new file mode 100755 index 0000000..7c4e3f2 --- /dev/null +++ b/app/SSH/Services/Database/scripts/postgresql/unlink.sh @@ -0,0 +1,10 @@ +USER_TO_REVOKE='__username__' + +DATABASES=$(sudo -u postgres psql -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;") + +for DB in $DATABASES; do + echo "Revoking privileges in database: $DB" + sudo -u postgres psql -d "$DB" -c "REVOKE ALL PRIVILEGES ON DATABASE \"$DB\" FROM $USER_TO_REVOKE;" +done + +echo "Privileges revoked from $USER_TO_REVOKE" diff --git a/app/SSH/Storage/Dropbox.php b/app/SSH/Storage/Dropbox.php index 1186e36..164541b 100644 --- a/app/SSH/Storage/Dropbox.php +++ b/app/SSH/Storage/Dropbox.php @@ -4,6 +4,7 @@ use App\Exceptions\SSHCommandError; use App\SSH\HasScripts; +use Illuminate\Support\Facades\Log; class Dropbox extends AbstractStorage { @@ -23,7 +24,8 @@ public function upload(string $src, string $dest): array $data = json_decode($upload, true); if (isset($data['error'])) { - throw new SSHCommandError('Failed to upload to Dropbox '.$data['error']); + Log::error('Failed to upload to Dropbox', $data); + throw new SSHCommandError('Failed to upload to Dropbox'); } return [ diff --git a/config/core.php b/config/core.php index de10c36..1903bf0 100755 --- a/config/core.php +++ b/config/core.php @@ -18,6 +18,7 @@ use App\SourceControlProviders\Gitlab; use App\SSH\Services\Database\Mariadb; use App\SSH\Services\Database\Mysql; +use App\SSH\Services\Database\Postgresql; use App\SSH\Services\Firewall\Ufw; use App\SSH\Services\PHP\PHP; use App\SSH\Services\ProcessManager\Supervisor; @@ -57,16 +58,42 @@ '8.1', '8.2', ], - 'databases' => ['none', 'mysql57', 'mysql80', 'mariadb'], + 'databases' => [ + 'none', + 'mysql57', + 'mysql80', + 'mariadb', + 'postgresql12', + 'postgresql13', + 'postgresql14', + 'postgresql15', + 'postgresql16', + ], 'databases_name' => [ 'mysql57' => 'mysql', 'mysql80' => 'mysql', 'mariadb' => 'mariadb', + 'postgresql12' => 'postgresql', + 'postgresql13' => 'postgresql', + 'postgresql14' => 'postgresql', + 'postgresql15' => 'postgresql', + 'postgresql16' => 'postgresql', ], 'databases_version' => [ 'mysql57' => '5.7', 'mysql80' => '8.0', 'mariadb' => '10.3', + 'postgresql12' => '12', + 'postgresql13' => '13', + 'postgresql14' => '14', + 'postgresql15' => '15', + 'postgresql16' => '16', + ], + 'database_features' => [ + 'remote' => [ + 'mysql', + 'mariadb', + ], ], /* @@ -126,6 +153,7 @@ 'nginx' => Nginx::class, 'mysql' => Mysql::class, 'mariadb' => Mariadb::class, + 'postgresql' => Postgresql::class, 'redis' => Redis::class, 'php' => PHP::class, 'ufw' => Ufw::class, @@ -168,6 +196,29 @@ '10.3' => 'mariadb', ], ], + 'postgresql' => [ + 'ubuntu_18' => [ + '12' => 'postgresql', + '13' => 'postgresql', + '14' => 'postgresql', + '15' => 'postgresql', + '16' => 'postgresql', + ], + 'ubuntu_20' => [ + '12' => 'postgresql', + '13' => 'postgresql', + '14' => 'postgresql', + '15' => 'postgresql', + '16' => 'postgresql', + ], + 'ubuntu_22' => [ + '12' => 'postgresql', + '13' => 'postgresql', + '14' => 'postgresql', + '15' => 'postgresql', + '16' => 'postgresql', + ], + ], 'php' => [ 'ubuntu_18' => [ '5.6' => 'php5.6-fpm', diff --git a/public/static/images/postgresql.svg b/public/static/images/postgresql.svg new file mode 100644 index 0000000..0bdb3e3 --- /dev/null +++ b/public/static/images/postgresql.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/views/databases/partials/create-database-modal.blade.php b/resources/views/databases/partials/create-database-modal.blade.php index b469ec8..7b5ebd0 100644 --- a/resources/views/databases/partials/create-database-modal.blade.php +++ b/resources/views/databases/partials/create-database-modal.blade.php @@ -65,20 +65,22 @@ class="mt-1 w-full" @enderror -
- -
+ @if (in_array($server->database()?->name, config("core.database_features.remote"))) +
+ +
+ @endif
diff --git a/resources/views/databases/partials/create-database-user-modal.blade.php b/resources/views/databases/partials/create-database-user-modal.blade.php index 960b7e0..4d8eda7 100644 --- a/resources/views/databases/partials/create-database-user-modal.blade.php +++ b/resources/views/databases/partials/create-database-user-modal.blade.php @@ -41,20 +41,22 @@ class="mt-1 w-full" @enderror
-
- -
+ @if (in_array($server->database()?->name, config("core.database_features.remote"))) +
+ +
+ @endif
diff --git a/resources/views/servers/partials/create-server.blade.php b/resources/views/servers/partials/create-server.blade.php index ae7c83b..d3a762f 100644 --- a/resources/views/servers/partials/create-server.blade.php +++ b/resources/views/servers/partials/create-server.blade.php @@ -1,9 +1,10 @@ @php use App\Enums\Database; use App\Enums\Webserver; + use App\Enums\ServerType; @endphp - + {{ __("Create new Server") }} @@ -193,7 +194,7 @@ class="mt-1 block w-full"
- + @foreach (config("core.server_types") as $serverType)
-
+
@foreach (config("core.webservers") as $ws) @@ -219,7 +220,7 @@ class="mt-1 block w-full" @enderror
-
+
@foreach (config("core.databases") as $db) @@ -232,7 +233,7 @@ class="mt-1 block w-full" @enderror
-
+
@foreach (config("core.php_versions") as $p)