refactoring (#116)

- refactoring architecture
- fix incomplete ssh logs
- code editor for scripts in the app
- remove Jobs and SSHCommands
This commit is contained in:
Saeed Vaziry
2024-03-14 20:03:43 +01:00
committed by GitHub
parent cee4a70c3c
commit 428140b931
472 changed files with 24110 additions and 8159 deletions

View File

@ -2,12 +2,9 @@
namespace App\Models;
use App\Enums\BackupFileStatus;
use App\Jobs\Backup\RunBackup;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;
/**
* @property string $type
@ -71,16 +68,4 @@ public function files(): HasMany
{
return $this->hasMany(BackupFile::class, 'backup_id');
}
public function run(): void
{
$file = new BackupFile([
'backup_id' => $this->id,
'name' => Str::of($this->database->name)->slug().'-'.now()->format('YmdHis'),
'status' => BackupFileStatus::CREATING,
]);
$file->save();
dispatch(new RunBackup($file))->onConnection('ssh');
}
}

View File

@ -2,9 +2,6 @@
namespace App\Models;
use App\Enums\BackupFileStatus;
use App\Jobs\Backup\RestoreDatabase;
use App\Jobs\StorageProvider\DeleteFile;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -17,8 +14,6 @@
* @property string $restored_to
* @property Carbon $restored_at
* @property Backup $backup
* @property string $path
* @property string $storage_path
*/
class BackupFile extends AbstractModel
{
@ -56,11 +51,12 @@ protected static function booted(): void
}
});
static::deleted(function (BackupFile $backupFile) {
dispatch(new DeleteFile(
$backupFile->backup->storage,
[$backupFile->storage_path]
));
static::deleting(function (BackupFile $backupFile) {
$provider = $backupFile->backup->storage->provider();
$path = $backupFile->storagePath();
dispatch(function () use ($provider, $path) {
$provider->delete([$path]);
});
});
}
@ -69,21 +65,13 @@ public function backup(): BelongsTo
return $this->belongsTo(Backup::class);
}
public function getPathAttribute(): string
public function path(): string
{
return '/home/'.$this->backup->server->ssh_user.'/'.$this->name.'.zip';
return '/home/'.$this->backup->server->getSshUser().'/'.$this->name.'.zip';
}
public function getStoragePathAttribute(): string
public function storagePath(): string
{
return '/'.$this->name.'.zip';
}
public function restore(Database $database): void
{
$this->status = BackupFileStatus::RESTORING;
$this->restored_to = $database->name;
$this->save();
dispatch(new RestoreDatabase($this, $database))->onConnection('ssh');
}
}

View File

@ -10,7 +10,6 @@
* @property string $command
* @property string $user
* @property string $frequency
* @property string $frequency_label
* @property bool $hidden
* @property string $status
* @property string $crontab
@ -34,10 +33,6 @@ class CronJob extends AbstractModel
'hidden' => 'boolean',
];
protected $appends = [
'frequency_label',
];
public function server(): BelongsTo
{
return $this->belongsTo(Server::class);
@ -57,7 +52,7 @@ public static function crontab(Server $server, string $user): string
return $data;
}
public function getFrequencyLabelAttribute(): string
public function frequencyLabel(): string
{
$labels = [
'* * * * *' => 'Every minute',

View File

@ -2,7 +2,6 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -14,7 +13,6 @@
* @property string $host
* @property string $status
* @property Server $server
* @property string $full_user
*/
class DatabaseUser extends AbstractModel
{
@ -43,14 +41,4 @@ public function server(): BelongsTo
{
return $this->belongsTo(Server::class);
}
public function scopeHasDatabase(Builder $query, string $databaseName): Builder
{
return $query->where('databases', 'like', "%\"$databaseName\"%");
}
public function getFullUserAttribute(): string
{
return $this->username.'@'.$this->host;
}
}

View File

@ -37,10 +37,6 @@ class Deployment extends AbstractModel
'commit_data' => 'json',
];
protected $appends = [
'commit_id_short',
];
public function site(): BelongsTo
{
return $this->belongsTo(Site::class);
@ -55,13 +51,4 @@ public function log(): BelongsTo
{
return $this->belongsTo(ServerLog::class, 'log_id');
}
public function getCommitIdShortAttribute(): string
{
if ($this->commit_id) {
return substr($this->commit_id, 0, 7);
}
return '';
}
}

View File

@ -9,7 +9,6 @@
* @property int $server_id
* @property string $type
* @property string $protocol
* @property string $real_protocol
* @property int $port
* @property string $source
* @property ?string $mask
@ -37,16 +36,12 @@ class FirewallRule extends AbstractModel
'port' => 'integer',
];
protected $appends = [
'real_protocol',
];
public function server(): BelongsTo
{
return $this->belongsTo(Server::class);
}
public function getRealProtocolAttribute(): string
public function getRealProtocol(): string
{
return $this->protocol === 'udp' ? 'udp' : 'tcp';
}

View File

@ -2,12 +2,8 @@
namespace App\Models;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\DB;
use Throwable;
/**
* @property int $site_id
@ -52,11 +48,6 @@ public function sourceControl(): BelongsTo
return $this->belongsTo(SourceControl::class);
}
public function scopeHasEvent(Builder $query, string $event): Builder
{
return $query->where('events', 'like', "%\"{$event}\"%");
}
public function deployHook(): void
{
$this->update(
@ -64,19 +55,9 @@ public function deployHook(): void
);
}
/**
* @throws Throwable
*/
public function destroyHook(): void
{
DB::beginTransaction();
try {
$this->sourceControl->provider()->destroyHook($this->site->repository, $this->hook_id);
$this->delete();
DB::commit();
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
$this->sourceControl->provider()->destroyHook($this->site->repository, $this->hook_id);
$this->delete();
}
}

View File

@ -2,7 +2,7 @@
namespace App\Models;
use App\Contracts\Notification;
use App\Notifications\NotificationInterface;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\Notifiable;
@ -33,14 +33,14 @@ class NotificationChannel extends AbstractModel
'is_default' => 'boolean',
];
public function provider(): \App\Contracts\NotificationChannel
public function provider(): \App\NotificationChannels\NotificationChannel
{
$class = config('core.notification_channels_providers_class')[$this->provider];
return new $class($this);
}
public static function notifyAll(Notification $notification): void
public static function notifyAll(NotificationInterface $notification): void
{
$channels = self::all();
foreach ($channels as $channel) {

View File

@ -2,11 +2,6 @@
namespace App\Models;
use App\Enums\QueueStatus;
use App\Jobs\Queue\Deploy;
use App\Jobs\Queue\GetLogs;
use App\Jobs\Queue\Manage;
use App\Jobs\Queue\Remove;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -21,8 +16,6 @@
* @property int $redirect_stderr
* @property string $stdout_logfile
* @property string $status
* @property string $log_directory
* @property string $log_file
* @property Server $server
* @property Site $site
*/
@ -73,71 +66,13 @@ public function site(): BelongsTo
return $this->belongsTo(Site::class);
}
public function getLogDirectoryAttribute(): string
public function getLogDirectory(): string
{
return '/home/'.$this->user.'/.logs/workers';
}
public function getLogFileAttribute(): string
public function getLogFile(): string
{
return $this->log_directory.'/'.$this->id.'.log';
}
public function deploy(): void
{
dispatch(new Deploy($this))->onConnection('ssh');
}
private function action(string $type, string $status, string $successStatus, string $failStatus, string $failMessage): void
{
$this->status = $status;
$this->save();
dispatch(new Manage($this, $type, $successStatus, $failStatus, $failMessage))
->onConnection('ssh');
}
public function start(): void
{
$this->action(
'start',
QueueStatus::STARTING,
QueueStatus::RUNNING,
QueueStatus::FAILED,
__('Failed to start')
);
}
public function stop(): void
{
$this->action(
'stop',
QueueStatus::STOPPING,
QueueStatus::STOPPED,
QueueStatus::FAILED,
__('Failed to stop')
);
}
public function restart(): void
{
$this->action(
'restart',
QueueStatus::RESTARTING,
QueueStatus::RUNNING,
QueueStatus::FAILED,
__('Failed to restart')
);
}
public function remove(): void
{
$this->status = QueueStatus::DELETING;
$this->save();
dispatch(new Remove($this))->onConnection('ssh');
}
public function getLogs(): void
{
dispatch(new GetLogs($this))->onConnection('ssh');
return $this->getLogDirectory().'/'.$this->id.'.log';
}
}

View File

@ -2,8 +2,6 @@
namespace App\Models;
use App\Jobs\Redirect\AddToServer;
use App\Jobs\Redirect\DeleteFromServer;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -35,16 +33,4 @@ public function site(): BelongsTo
{
return $this->belongsTo(Site::class);
}
public function addToServer(): void
{
dispatch(new AddToServer($this))->onConnection('ssh');
}
public function deleteFromServer(): void
{
$this->status = 'deleting';
$this->save();
dispatch(new DeleteFromServer($this))->onConnection('ssh');
}
}

View File

@ -2,7 +2,6 @@
namespace App\Models;
use App\Jobs\Script\ExecuteOn;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
@ -36,9 +35,4 @@ public function executions(): HasMany
{
return $this->hasMany(ScriptExecution::class, 'script_id');
}
public function executeOn(Server $server, string $user): void
{
dispatch(new ExecuteOn($this, $server, $user))->onConnection('ssh');
}
}

View File

@ -3,15 +3,12 @@
namespace App\Models;
use App\Actions\Server\CheckConnection;
use App\Actions\Server\RebootServer;
use App\Contracts\ServerType;
use App\Enums\ServerStatus;
use App\Enums\ServiceStatus;
use App\Facades\Notifier;
use App\Facades\SSH;
use App\Jobs\Installation\Upgrade;
use App\Notifications\ServerInstallationStarted;
use App\Support\Testing\SSHFake;
use App\ServerTypes\ServerType;
use App\SSH\Cron\Cron;
use App\SSH\OS\OS;
use App\SSH\Systemd\Systemd;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@ -205,6 +202,22 @@ public function daemons(): HasMany
return $this->queues()->whereNull('site_id');
}
public function sshKeys(): BelongsToMany
{
return $this->belongsToMany(SshKey::class, 'server_ssh_keys')
->withPivot('status')
->withTimestamps();
}
public function getSshUser(): string
{
if ($this->ssh_user) {
return $this->ssh_user;
}
return config('core.ssh_user');
}
public function service($type, $version = null): ?Service
{
/* @var Service $service */
@ -230,6 +243,7 @@ public function defaultService($type): ?Service
// If no default service found, get the first service with status ready or stopped
if (! $service) {
/** @var Service $service */
$service = $this->services()
->where('type', $type)
->whereIn('status', [ServiceStatus::READY, ServiceStatus::STOPPED])
@ -243,24 +257,7 @@ public function defaultService($type): ?Service
return $service;
}
public function getServiceByUnit($unit): ?Service
{
/* @var Service $service */
$service = $this->services()
->where('unit', $unit)
->where('is_default', 1)
->first();
return $service;
}
public function install(): void
{
$this->type()->install();
Notifier::send($this, new ServerInstallationStarted($this));
}
public function ssh(?string $user = null): \App\Helpers\SSH|SSHFake
public function ssh(?string $user = null): mixed
{
return SSH::init($this, $user);
}
@ -283,7 +280,7 @@ public function type(): ServerType
return new $typeClass($this);
}
public function provider(): \App\Contracts\ServerProvider
public function provider(): \App\ServerProviders\ServerProvider
{
$providerClass = config('core.server_providers_class')[$this->provider];
@ -335,32 +332,8 @@ public function php(?string $version = null): ?Service
return $this->service('php', $version);
}
public function sshKeys(): BelongsToMany
{
return $this->belongsToMany(SshKey::class, 'server_ssh_keys')
->withPivot('status')
->withTimestamps();
}
public function getSshUserAttribute(string $value): string
{
if ($value) {
return $value;
}
return config('core.ssh_user');
}
public function sshKey(): array
{
if (app()->environment() == 'testing') {
return [
'public_key' => 'public',
'public_key_path' => '/path',
'private_key_path' => '/path',
];
}
/** @var FilesystemAdapter $storageDisk */
$storageDisk = Storage::disk(config('core.key_pairs_disk'));
@ -371,44 +344,28 @@ public function sshKey(): array
];
}
public function getServiceUnits(): array
{
$units = [];
$services = $this->services;
foreach ($services as $service) {
if ($service->unit) {
$units[] = $service->unit;
}
}
return $units;
}
public function checkConnection(): self
{
return app(CheckConnection::class)->check($this);
}
public function installUpdates(): void
{
$this->available_updates = 0;
$this->security_updates = 0;
$this->save();
dispatch(new Upgrade($this))->onConnection('ssh');
}
public function reboot(): self
{
return app(RebootServer::class)->reboot($this);
}
public function getHostnameAttribute(): string
public function hostname(): string
{
return Str::of($this->name)->slug();
}
public function isReady(): bool
public function os(): OS
{
return $this->status == ServerStatus::READY;
return new OS($this);
}
public function systemd(): Systemd
{
return new Systemd($this);
}
public function cron(): Cron
{
return new Cron($this);
}
}

View File

@ -15,7 +15,6 @@
* @property string $disk
* @property Server $server
* @property ?Site $site
* @property string $content
*/
class ServerLog extends AbstractModel
{
@ -72,7 +71,7 @@ public function write($buf): void
}
}
public function getContentAttribute(): ?string
public function getContent(): ?string
{
if (Storage::disk($this->disk)->exists($this->name)) {
return Storage::disk($this->disk)->get($this->name);
@ -80,4 +79,17 @@ public function getContentAttribute(): ?string
return '';
}
public static function log(Server $server, string $type, string $content, ?Site $site = null): void
{
$log = new static([
'server_id' => $server->id,
'site_id' => $site?->id,
'name' => $server->id.'-'.strtotime('now').'-'.$type.'.log',
'type' => $type,
'disk' => config('core.logs_disk'),
]);
$log->save();
$log->write($content);
}
}

View File

@ -2,17 +2,16 @@
namespace App\Models;
use App\Contracts\Database;
use App\Contracts\Firewall;
use App\Contracts\ProcessManager;
use App\Contracts\Webserver;
use App\Enums\ServiceStatus;
use App\Exceptions\InstallationFailed;
use App\Jobs\Service\Manage;
use App\ServiceHandlers\PHP;
use App\Actions\Service\Manage;
use App\Exceptions\ServiceInstallationFailed;
use App\SSH\Services\Database\Database as DatabaseHandler;
use App\SSH\Services\Firewall\Firewall as FirewallHandler;
use App\SSH\Services\PHP\PHP as PHPHandler;
use App\SSH\Services\ProcessManager\ProcessManager as ProcessManagerHandler;
use App\SSH\Services\Redis\Redis as RedisHandler;
use App\SSH\Services\Webserver\Webserver as WebserverHandler;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Str;
/**
@ -49,134 +48,49 @@ class Service extends AbstractModel
'is_default' => 'boolean',
];
public static function boot(): void
{
parent::boot();
static::creating(function (Service $service) {
$service->unit = config('core.service_units')[$service->name][$service->server->os][$service->version];
});
}
public function server(): BelongsTo
{
return $this->belongsTo(Server::class);
}
public function handler(): Database|Firewall|Webserver|PHP|ProcessManager
{
public function handler(
): PHPHandler|WebserverHandler|DatabaseHandler|FirewallHandler|ProcessManagerHandler|RedisHandler {
$handler = config('core.service_handlers')[$this->name];
return new $handler($this);
}
public function installer(): mixed
{
$installer = config('core.service_installers')[$this->name];
return new $installer($this);
}
public function uninstaller(): mixed
{
$uninstaller = config('core.service_uninstallers')[$this->name];
return new $uninstaller($this);
}
public function getUnitAttribute($value): ?string
{
if ($value) {
return $value;
}
if (isset(config('core.service_units')[$this->name])) {
$value = config('core.service_units')[$this->name][$this->server->os][$this->version];
if ($value) {
$this->fill(['unit' => $value]);
$this->save();
}
}
return $value;
}
public function install(): void
{
Bus::chain([
$this->installer(),
])->onConnection('ssh-long')->dispatch();
}
/**
* @throws InstallationFailed
* @throws ServiceInstallationFailed
*/
public function validateInstall($result): void
{
if (! Str::contains($result, 'Active: active')) {
throw new InstallationFailed();
throw new ServiceInstallationFailed();
}
}
public function uninstall(): void
{
$this->status = ServiceStatus::UNINSTALLING;
$this->save();
Bus::chain([
$this->uninstaller(),
function () {
$this->delete();
},
])->catch(function () {
$this->status = ServiceStatus::FAILED;
$this->save();
})->onConnection('ssh')->dispatch();
}
public function start(): void
{
$this->action(
'start',
ServiceStatus::STARTING,
ServiceStatus::READY,
ServiceStatus::STOPPED,
__('Failed to start')
);
app(Manage::class)->start($this);
}
public function stop(): void
{
$this->action(
'stop',
ServiceStatus::STOPPING,
ServiceStatus::STOPPED,
ServiceStatus::FAILED,
__('Failed to stop')
);
app(Manage::class)->stop($this);
}
public function restart(): void
{
$this->action(
'restart',
ServiceStatus::RESTARTING,
ServiceStatus::READY,
ServiceStatus::FAILED,
__('Failed to restart')
);
}
public function action(
string $type,
string $status,
string $successStatus,
string $failStatus,
string $failMessage
): void {
$this->status = $status;
$this->save();
dispatch(new Manage($this, $type, $successStatus, $failStatus, $failMessage))
->onConnection('ssh');
}
public function installedVersions(): array
{
$versions = [];
$services = $this->server->services()->where('type', $this->type)->get(['version']);
foreach ($services as $service) {
$versions[] = $service->version;
}
return $versions;
app(Manage::class)->restart($this);
}
}

View File

@ -2,27 +2,14 @@
namespace App\Models;
use App\Contracts\SiteType;
use App\Enums\DeploymentStatus;
use App\Enums\SiteStatus;
use App\Enums\SslStatus;
use App\Exceptions\SourceControlIsNotConnected;
use App\Facades\Notifier;
use App\Jobs\Site\Deploy;
use App\Jobs\Site\UpdateBranch;
use App\Notifications\SiteInstallationFailed;
use App\Notifications\SiteInstallationSucceed;
use App\SSHCommands\Website\GetEnvCommand;
use Exception;
use App\SiteTypes\SiteType;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Throwable;
/**
* @property int $server_id
@ -31,7 +18,6 @@
* @property string $domain
* @property array $aliases
* @property string $web_directory
* @property string $web_directory_path
* @property string $path
* @property string $php_version
* @property string $source_control
@ -42,8 +28,6 @@
* @property string $status
* @property int $port
* @property int $progress
* @property bool $auto_deployment
* @property string $url
* @property Server $server
* @property ServerLog[] $logs
* @property Deployment[] $deployments
@ -53,10 +37,6 @@
* @property Queue[] $queues
* @property Ssl[] $ssls
* @property ?Ssl $activeSsl
* @property string $full_repository_url
* @property string $aliases_string
* @property string $deployment_script_text
* @property string $env
* @property string $ssh_key_name
*/
class Site extends AbstractModel
@ -87,16 +67,10 @@ class Site extends AbstractModel
'type_data' => 'json',
'port' => 'integer',
'progress' => 'integer',
'auto_deployment' => 'boolean',
'aliases' => 'array',
'source_control_id' => 'integer',
];
protected $appends = [
'url',
'auto_deployment',
];
public static function boot(): void
{
parent::boot();
@ -186,12 +160,12 @@ public function sourceControl(): SourceControl|HasOne|null|Model
/**
* @throws SourceControlIsNotConnected
*/
public function getFullRepositoryUrlAttribute()
public function getFullRepositoryUrl()
{
return $this->sourceControl()->provider()->fullRepoUrl($this->repository, $this->ssh_key_name);
return $this->sourceControl()->provider()->fullRepoUrl($this->repository, $this->getSshKeyName());
}
public function getAliasesStringAttribute(): string
public function getAliasesString(): string
{
if (count($this->aliases) > 0) {
return implode(' ', $this->aliases);
@ -207,19 +181,6 @@ public function type(): SiteType
return new $typeClass($this);
}
public function install(): void
{
$this->type()->install();
}
public function remove(): void
{
$this->update([
'status' => SiteStatus::DELETING,
]);
$this->type()->delete();
}
public function php(): ?Service
{
if ($this->php_version) {
@ -233,57 +194,7 @@ public function changePHPVersion($version): void
{
$this->php_version = $version;
$this->server->webserver()->handler()->changePHPVersion($this, $version);
}
public function getDeploymentScriptTextAttribute(): string
{
/* @var DeploymentScript $script */
$script = $this->deploymentScript()->firstOrCreate([
'site_id' => $this->id,
], [
'site_id' => $this->id,
'name' => 'default',
]);
return $script->content;
}
/**
* @throws SourceControlIsNotConnected
*/
public function deploy(): Deployment
{
if ($this->sourceControl()) {
$this->sourceControl()->getRepo($this->repository);
}
$deployment = new Deployment([
'site_id' => $this->id,
'deployment_script_id' => $this->deploymentScript->id,
'status' => DeploymentStatus::DEPLOYING,
]);
$lastCommit = $this->sourceControl()->provider()->getLastCommit($this->repository, $this->branch);
if ($lastCommit) {
$deployment->commit_id = $lastCommit['commit_id'];
$deployment->commit_data = $lastCommit['commit_data'];
}
$deployment->save();
dispatch(new Deploy($deployment, $this->path))->onConnection('ssh');
return $deployment;
}
public function getEnvAttribute(): string
{
$typeData = $this->type_data;
if (! isset($typeData['env'])) {
$typeData['env'] = '';
$this->type_data = $typeData;
$this->save();
}
return $typeData['env'];
$this->save();
}
public function activeSsl(): HasOne
@ -293,33 +204,7 @@ public function activeSsl(): HasOne
->orderByDesc('id');
}
public function createFreeSsl(): void
{
$ssl = new Ssl([
'site_id' => $this->id,
'type' => 'letsencrypt',
'expires_at' => now()->addMonths(3),
'status' => SslStatus::CREATING,
]);
$ssl->save();
$ssl->deploy();
}
public function createCustomSsl(string $certificate, string $pk): void
{
$ssl = new Ssl([
'site_id' => $this->id,
'type' => 'custom',
'certificate' => $certificate,
'pk' => $pk,
'expires_at' => '',
'status' => SslStatus::CREATING,
]);
$ssl->save();
$ssl->deploy();
}
public function getUrlAttribute(): string
public function getUrl(): string
{
if ($this->activeSsl) {
return 'https://'.$this->domain;
@ -328,7 +213,7 @@ public function getUrlAttribute(): string
return 'http://'.$this->domain;
}
public function getWebDirectoryPathAttribute(): string
public function getWebDirectoryPath(): string
{
if ($this->web_directory) {
return $this->path.'/'.$this->web_directory;
@ -339,7 +224,6 @@ public function getWebDirectoryPathAttribute(): string
/**
* @throws SourceControlIsNotConnected
* @throws Throwable
*/
public function enableAutoDeployment(): void
{
@ -347,92 +231,50 @@ public function enableAutoDeployment(): void
return;
}
if (! $this->sourceControl()) {
if (! $this->sourceControl()?->getRepo($this->repository)) {
throw new SourceControlIsNotConnected($this->source_control);
}
DB::beginTransaction();
try {
$gitHook = new GitHook([
'site_id' => $this->id,
'source_control_id' => $this->sourceControl()->id,
'secret' => Str::uuid()->toString(),
'actions' => ['deploy'],
'events' => ['push'],
]);
$gitHook->save();
$gitHook->deployHook();
DB::commit();
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
$gitHook = new GitHook([
'site_id' => $this->id,
'source_control_id' => $this->sourceControl()->id,
'secret' => Str::uuid()->toString(),
'actions' => ['deploy'],
'events' => ['push'],
]);
$gitHook->save();
$gitHook->deployHook();
}
/**
* @throws Throwable
* @throws SourceControlIsNotConnected
*/
public function disableAutoDeployment(): void
{
if (! $this->sourceControl()?->getRepo($this->repository)) {
throw new SourceControlIsNotConnected($this->source_control);
}
$this->gitHook?->destroyHook();
}
public function getAutoDeploymentAttribute(): bool
public function isAutoDeployment(): bool
{
return (bool) $this->gitHook;
}
public function updateBranch(string $branch): void
{
dispatch(new UpdateBranch($this, $branch))->onConnection('ssh');
}
public function getSshKeyNameAttribute(): string
public function getSshKeyName(): string
{
return str('site_'.$this->id)->toString();
}
public function installationFinished(): void
{
$this->update([
'status' => SiteStatus::READY,
'progress' => 100,
]);
Notifier::send($this, new SiteInstallationSucceed($this));
}
/**
* @throws Throwable
*/
public function installationFailed(Throwable $e): void
{
$this->update([
'status' => SiteStatus::INSTALLATION_FAILED,
]);
Notifier::send($this, new SiteInstallationFailed($this));
Log::error('install-site-error', [
'error' => (string) $e,
]);
throw $e;
}
public function hasFeature(string $feature): bool
{
return in_array($feature, $this->type()->supportedFeatures());
}
public function isReady(): bool
{
return $this->status === SiteStatus::READY;
}
public function getEnv(): string
{
return $this->server->ssh()->exec(
new GetEnvCommand(
$this->domain
)
);
return $this->server->os()->readFile($this->path.'/.env');
}
}

View File

@ -2,7 +2,7 @@
namespace App\Models;
use App\Contracts\SourceControlProvider;
use App\SourceControlProviders\SourceControlProvider;
use Illuminate\Database\Eloquent\Factories\HasFactory;
/**

View File

@ -2,9 +2,6 @@
namespace App\Models;
use App\Enums\SshKeyStatus;
use App\Jobs\SshKey\DeleteSshKeyFromServer;
use App\Jobs\SshKey\DeploySshKeyToServer;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@ -47,20 +44,4 @@ public function existsOnServer(Server $server): bool
{
return (bool) $this->servers()->where('id', $server->id)->first();
}
public function deployTo(Server $server): void
{
$server->sshKeys()->attach($this, [
'status' => SshKeyStatus::ADDING,
]);
dispatch(new DeploySshKeyToServer($server, $this))->onConnection('ssh');
}
public function deleteFrom(Server $server): void
{
$this->servers()->updateExistingPivot($server->id, [
'status' => SshKeyStatus::DELETING,
]);
dispatch(new DeleteSshKeyFromServer($server, $this))->onConnection('ssh');
}
}

View File

@ -2,9 +2,6 @@
namespace App\Models;
use App\Enums\SslStatus;
use App\Jobs\Ssl\Deploy;
use App\Jobs\Ssl\Remove;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -19,9 +16,6 @@
* @property Carbon $expires_at
* @property string $status
* @property Site $site
* @property string $certs_directory_path
* @property string $certificate_path
* @property string $pk_path
* @property string $ca_path
*/
class Ssl extends AbstractModel
@ -51,7 +45,7 @@ public function site(): BelongsTo
return $this->belongsTo(Site::class);
}
public function getCertsDirectoryPathAttribute(): ?string
public function getCertsDirectoryPath(): ?string
{
if ($this->type == 'letsencrypt') {
return '/etc/letsencrypt/live/'.$this->site->domain;
@ -64,57 +58,45 @@ public function getCertsDirectoryPathAttribute(): ?string
return '';
}
public function getCertificatePathAttribute(): ?string
public function getCertificatePath(): ?string
{
if ($this->type == 'letsencrypt') {
return $this->certificate;
}
if ($this->type == 'custom') {
return $this->certs_directory_path.'/cert.pem';
return $this->getCertsDirectoryPath().'/cert.pem';
}
return '';
}
public function getPkPathAttribute(): ?string
public function getPkPath(): ?string
{
if ($this->type == 'letsencrypt') {
return $this->pk;
}
if ($this->type == 'custom') {
return $this->certs_directory_path.'/privkey.pem';
return $this->getCertsDirectoryPath().'/privkey.pem';
}
return '';
}
public function getCaPathAttribute(): ?string
public function getCaPath(): ?string
{
if ($this->type == 'letsencrypt') {
return $this->ca;
}
if ($this->type == 'custom') {
return $this->certs_directory_path.'/fullchain.pem';
return $this->getCertsDirectoryPath().'/fullchain.pem';
}
return '';
}
public function deploy(): void
{
dispatch(new Deploy($this))->onConnection('ssh');
}
public function remove(): void
{
$this->status = SslStatus::DELETING;
$this->save();
dispatch(new Remove($this))->onConnection('ssh');
}
public function validateSetup(string $result): bool
{
if (! Str::contains($result, 'Successfully received certificate')) {
@ -122,8 +104,8 @@ public function validateSetup(string $result): bool
}
if ($this->type == 'letsencrypt') {
$this->certificate = $this->certs_directory_path.'/fullchain.pem';
$this->pk = $this->certs_directory_path.'/privkey.pem';
$this->certificate = $this->getCertsDirectoryPath().'/fullchain.pem';
$this->pk = $this->getCertsDirectoryPath().'/privkey.pem';
$this->save();
}

View File

@ -33,7 +33,7 @@ public function user(): BelongsTo
return $this->belongsTo(User::class);
}
public function provider(): \App\Contracts\StorageProvider
public function provider(): \App\StorageProviders\StorageProvider
{
$providerClass = config('core.storage_providers_class')[$this->provider];