fix: boarding

fix: error handling
fix: restarting state
This commit is contained in:
Andras Bacsai 2023-09-15 15:34:25 +02:00
parent fcf7c5ddd5
commit da4c2ee60f
71 changed files with 326 additions and 290 deletions

View File

@ -5,6 +5,7 @@
use App\Enums\ActivityTypes; use App\Enums\ActivityTypes;
use App\Enums\ProcessStatus; use App\Enums\ProcessStatus;
use App\Jobs\ApplicationDeploymentJob; use App\Jobs\ApplicationDeploymentJob;
use App\Models\Server;
use Illuminate\Process\ProcessResult; use Illuminate\Process\ProcessResult;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Process;
@ -94,7 +95,7 @@ public function __invoke(): ProcessResult
]); ]);
$this->activity->save(); $this->activity->save();
if ($processResult->exitCode() != 0 && !$this->ignore_errors) { if ($processResult->exitCode() != 0 && !$this->ignore_errors) {
throw new \RuntimeException($processResult->errorOutput()); throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode());
} }
return $processResult; return $processResult;
@ -102,12 +103,11 @@ public function __invoke(): ProcessResult
protected function getCommand(): string protected function getCommand(): string
{ {
$user = $this->activity->getExtraProperty('user'); $server_uuid = $this->activity->getExtraProperty('server_uuid');
$server_ip = $this->activity->getExtraProperty('server_ip');
$port = $this->activity->getExtraProperty('port');
$command = $this->activity->getExtraProperty('command'); $command = $this->activity->getExtraProperty('command');
$server = Server::whereUuid($server_uuid)->firstOrFail();
return generateSshCommand($server_ip, $user, $port, $command); return generateSshCommand($server, $command);
} }
protected function handleOutput(string $type, string $output) protected function handleOutput(string $type, string $output)

View File

@ -27,6 +27,10 @@ public function __invoke(Server $server, bool $async = true): Activity|string
$server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value; $server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
$server->save(); $server->save();
$commands = [ $commands = [
"command -v lsof >/dev/null || echo '####### Installing lsof...'",
"command -v lsof >/dev/null || apt-get update",
"command -v lsof >/dev/null || apt install -y lsof",
"command -v lsof >/dev/null || command -v fuser >/dev/null || apt install -y psmisc",
"echo '####### Creating required Docker networks...'", "echo '####### Creating required Docker networks...'",
...$create_networks_command, ...$create_networks_command,
"cd $proxy_path", "cd $proxy_path",
@ -35,8 +39,11 @@ public function __invoke(Server $server, bool $async = true): Activity|string
'docker compose pull', 'docker compose pull',
"echo '####### Stopping existing coolify-proxy...'", "echo '####### Stopping existing coolify-proxy...'",
'docker compose down -v --remove-orphans', 'docker compose down -v --remove-orphans',
"lsof -nt -i:80 | xargs -r kill -9", "command -v lsof >/dev/null && lsof -nt -i:80 | xargs -r kill -9",
"lsof -nt -i:443 | xargs -r kill -9", "command -v lsof >/dev/null && lsof -nt -i:443 | xargs -r kill -9",
"command -v fuser >/dev/null && fuser -k 80/tcp",
"command -v fuser >/dev/null && fuser -k 443/tcp",
"command -v fuser >/dev/null || command -v lsof >/dev/null || echo '####### Could not kill existing processes listening on port 80 & 443. Please stop the process holding these ports...'",
"systemctl disable nginx > /dev/null 2>&1 || true", "systemctl disable nginx > /dev/null 2>&1 || true",
"systemctl disable apache2 > /dev/null 2>&1 || true", "systemctl disable apache2 > /dev/null 2>&1 || true",
"systemctl disable apache > /dev/null 2>&1 || true", "systemctl disable apache > /dev/null 2>&1 || true",

View File

@ -12,10 +12,8 @@
class CoolifyTaskArgs extends Data class CoolifyTaskArgs extends Data
{ {
public function __construct( public function __construct(
public string $server_ip, public string $server_uuid,
public string $command, public string $command,
public int $port,
public string $user,
public string $type, public string $type,
public ?string $type_uuid = null, public ?string $type_uuid = null,
public ?Model $model = null, public ?Model $model = null,

View File

@ -45,8 +45,11 @@ class Handler extends ExceptionHandler
public function register(): void public function register(): void
{ {
$this->reportable(function (Throwable $e) { $this->reportable(function (Throwable $e) {
if (isDev()) {
return;
}
$this->settings = InstanceSettings::get(); $this->settings = InstanceSettings::get();
if ($this->settings->do_not_track || isDev()) { if ($this->settings->do_not_track) {
return; return;
} }
app('sentry')->configureScope( app('sentry')->configureScope(

View File

@ -14,7 +14,6 @@
use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Throwable;
class Controller extends BaseController class Controller extends BaseController
{ {
@ -153,7 +152,7 @@ public function acceptInvitation()
} else { } else {
abort(401); abort(401);
} }
} catch (Throwable $e) { } catch (\Throwable $e) {
ray($e->getMessage()); ray($e->getMessage());
throw $e; throw $e;
} }
@ -172,7 +171,7 @@ public function revokeInvitation()
} }
$invitation->delete(); $invitation->delete();
return redirect()->route('team.index'); return redirect()->route('team.index');
} catch (Throwable $e) { } catch (\Throwable $e) {
throw $e; throw $e;
} }
} }

View File

@ -9,6 +9,7 @@
use App\Models\Team; use App\Models\Team;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Livewire\Component; use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Index extends Component class Index extends Component
{ {
@ -53,7 +54,8 @@ public function mount()
$this->remoteServerHost = 'coolify-testing-host'; $this->remoteServerHost = 'coolify-testing-host';
} }
} }
public function explanation() { public function explanation()
{
if (isCloud()) { if (isCloud()) {
return $this->setServerType('remote'); return $this->setServerType('remote');
} }
@ -115,7 +117,8 @@ public function selectExistingServer()
$this->getProxyType(); $this->getProxyType();
$this->getProjects(); $this->getProjects();
} }
public function getProxyType() { public function getProxyType()
{
$proxyTypeSet = $this->createdServer->proxy->type; $proxyTypeSet = $this->createdServer->proxy->type;
if (!$proxyTypeSet) { if (!$proxyTypeSet) {
$this->currentState = 'select-proxy'; $this->currentState = 'select-proxy';
@ -153,49 +156,68 @@ public function saveServer()
{ {
$this->validate([ $this->validate([
'remoteServerName' => 'required', 'remoteServerName' => 'required',
'remoteServerHost' => 'required', 'remoteServerHost' => 'required|ip',
'remoteServerPort' => 'required', 'remoteServerPort' => 'required|integer',
'remoteServerUser' => 'required', 'remoteServerUser' => 'required',
]); ]);
$this->privateKey = formatPrivateKey($this->privateKey); $this->privateKey = formatPrivateKey($this->privateKey);
$this->createdPrivateKey = PrivateKey::create([ $this->createdPrivateKey = new PrivateKey();
$this->createdPrivateKey->private_key = $this->privateKey;
$this->createdPrivateKey->name = $this->privateKeyName;
$this->createdPrivateKey->description = $this->privateKeyDescription;
$this->createdPrivateKey->team_id = currentTeam()->id;
$foundServer = Server::whereIp($this->remoteServerHost)->first();
if ($foundServer) {
return $this->emit('error', 'IP address is already in use by another team.');
}
$this->createdServer = new Server();
$this->createdServer->uuid = (string)new Cuid2(7);
$this->createdServer->name = $this->remoteServerName;
$this->createdServer->ip = $this->remoteServerHost;
$this->createdServer->port = $this->remoteServerPort;
$this->createdServer->user = $this->remoteServerUser;
$this->createdServer->description = $this->remoteServerDescription;
$this->createdServer->privateKey = $this->createdPrivateKey;
$this->createdServer->team_id = currentTeam()->id;
ray($this->createdServer);
$this->validateServer();
}
public function validateServer()
{
try {
$customErrorMessage = "Server is not reachable:";
config()->set('coolify.mux_enabled', false);
instant_remote_process(['uptime'], $this->createdServer, true);
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
if (is_null($dockerVersion)) {
throw new \Exception('No Docker Engine or older than 23 version installed.');
}
$customErrorMessage = "Cannot create Server or Private Key. Please try again.";
$createdPrivateKey = PrivateKey::create([
'name' => $this->privateKeyName, 'name' => $this->privateKeyName,
'description' => $this->privateKeyDescription, 'description' => $this->privateKeyDescription,
'private_key' => $this->privateKey, 'private_key' => $this->privateKey,
'team_id' => currentTeam()->id 'team_id' => currentTeam()->id
]); ]);
$this->createdServer = Server::create([ $server = Server::create([
'name' => $this->remoteServerName, 'name' => $this->remoteServerName,
'ip' => $this->remoteServerHost, 'ip' => $this->remoteServerHost,
'port' => $this->remoteServerPort, 'port' => $this->remoteServerPort,
'user' => $this->remoteServerUser, 'user' => $this->remoteServerUser,
'description' => $this->remoteServerDescription, 'description' => $this->remoteServerDescription,
'private_key_id' => $this->createdPrivateKey->id, 'private_key_id' => $createdPrivateKey->id,
'team_id' => currentTeam()->id 'team_id' => currentTeam()->id,
]); ]);
$this->validateServer(); $server->settings->is_reachable = true;
} $server->settings->is_usable = true;
public function validateServer() { $server->settings->save();
try {
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->createdServer);
if (!$uptime) {
throw new \Exception('Server is not reachable.');
} else {
$this->createdServer->settings->update([
'is_reachable' => true,
]);
$this->emit('success', 'Server is reachable.');
}
ray($dockerVersion, $uptime);
if (!$dockerVersion) {
$this->emit('error', 'Docker is not installed on the server.');
$this->currentState = 'install-docker';
return;
}
$this->getProxyType(); $this->getProxyType();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this); return handleError(error: $e, customErrorMessage: $customErrorMessage, livewire: $this);
} }
} }
public function installDocker() public function installDocker()
@ -215,14 +237,16 @@ public function selectProxy(string|null $proxyType = null)
$this->getProjects(); $this->getProjects();
} }
public function getProjects() { public function getProjects()
{
$this->projects = Project::ownedByCurrentTeam(['name'])->get(); $this->projects = Project::ownedByCurrentTeam(['name'])->get();
if ($this->projects->count() > 0) { if ($this->projects->count() > 0) {
$this->selectedExistingProject = $this->projects->first()->id; $this->selectedExistingProject = $this->projects->first()->id;
} }
$this->currentState = 'create-project'; $this->currentState = 'create-project';
} }
public function selectExistingProject() { public function selectExistingProject()
{
$this->createdProject = Project::find($this->selectedExistingProject); $this->createdProject = Project::find($this->selectedExistingProject);
$this->currentState = 'create-resource'; $this->currentState = 'create-resource';
} }

View File

@ -38,7 +38,7 @@ public function delete()
$this->destination->delete(); $this->destination->delete();
return redirect()->route('dashboard'); return redirect()->route('dashboard');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e); return handleError($e);
} }
} }
} }

View File

@ -72,7 +72,7 @@ public function submit()
$this->createNetworkAndAttachToProxy(); $this->createNetworkAndAttachToProxy();
return redirect()->route('destination.show', $docker->uuid); return redirect()->route('destination.show', $docker->uuid);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }

View File

@ -37,7 +37,7 @@ public function submit()
} }
return redirect()->route('dashboard'); return redirect()->route('dashboard');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -44,7 +44,7 @@ public function submit()
send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io'); send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
$this->emit('success', 'Your message has been sent successfully. We will get in touch with you as soon as possible.'); $this->emit('success', 'Your message has been sent successfully. We will get in touch with you as soon as possible.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function render() public function render()

View File

@ -64,7 +64,7 @@ public function submitFromFields()
$this->team->save(); $this->team->save();
$this->emit('success', 'Settings saved successfully.'); $this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function sendTestNotification() public function sendTestNotification()
@ -83,7 +83,7 @@ public function instantSaveInstance()
$this->team->save(); $this->team->save();
$this->emit('success', 'Settings saved successfully.'); $this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
@ -94,7 +94,7 @@ public function instantSaveResend()
$this->submitResend(); $this->submitResend();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->team->smtp_enabled = false; $this->team->smtp_enabled = false;
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function instantSave() public function instantSave()
@ -104,7 +104,7 @@ public function instantSave()
$this->submit(); $this->submit();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->team->smtp_enabled = false; $this->team->smtp_enabled = false;
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function saveModel() public function saveModel()
@ -130,7 +130,7 @@ public function submit()
$this->emit('success', 'Settings saved successfully.'); $this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->team->smtp_enabled = false; $this->team->smtp_enabled = false;
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function submitResend() public function submitResend()
@ -146,7 +146,7 @@ public function submitResend()
$this->emit('success', 'Settings saved successfully.'); $this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->team->resend_enabled = false; $this->team->resend_enabled = false;
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function copyFromInstanceSettings() public function copyFromInstanceSettings()

View File

@ -25,8 +25,8 @@ public function mount()
{ {
try { try {
$this->public_key = $this->private_key->publicKey(); $this->public_key = $this->private_key->publicKey();
}catch(\Exception $e) { }catch(\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
public function delete() public function delete()
@ -39,7 +39,7 @@ public function delete()
} }
$this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.'); $this->emit('error', 'This private key is in use and cannot be deleted. Please delete all servers, applications, and GitHub/GitLab apps that use this private key before deleting it.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
@ -50,7 +50,7 @@ public function changePrivateKey()
$this->private_key->save(); $this->private_key->save();
refresh_server_connection($this->private_key); refresh_server_connection($this->private_key);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -58,7 +58,7 @@ public function createPrivateKey()
} }
return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]); return redirect()->route('security.private-key.show', ['private_key_uuid' => $private_key->uuid]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -34,7 +34,7 @@ public function submit()
'name' => $this->name, 'name' => $this->name,
]); ]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -29,7 +29,7 @@ public function submit()
]); ]);
return redirect()->route('project.show', $project->uuid); return redirect()->route('project.show', $project->uuid);
} catch (\Throwable $e) { } catch (\Throwable $e) {
general_error_handler($e, $this); return handleError($e, $this);
} finally { } finally {
$this->name = ''; $this->name = '';
} }

View File

@ -32,7 +32,7 @@ public function submit()
'environment_name' => $environment->name, 'environment_name' => $environment->name,
]); ]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
general_error_handler($e, $this); handleError($e, $this);
} finally { } finally {
$this->name = ''; $this->name = '';
} }

View File

@ -65,7 +65,7 @@ public function cancel()
]); ]);
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -160,7 +160,7 @@ public function submit()
$this->application->save(); $this->application->save();
$this->emit('success', 'Application settings updated!'); $this->emit('success', 'Application settings updated!');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -30,7 +30,7 @@ public function load_prs()
$this->pull_requests = $data->sortBy('number')->values(); $this->pull_requests = $data->sortBy('number')->values();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->rate_limit_remaining = 0; $this->rate_limit_remaining = 0;
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
@ -59,7 +59,7 @@ public function deploy(int $pull_request_id, string|null $pull_request_html_url
'environment_name' => $this->parameters['environment_name'], 'environment_name' => $this->parameters['environment_name'],
]); ]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
@ -79,7 +79,7 @@ public function stop(int $pull_request_id)
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete(); ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
$this->application->refresh(); $this->application->refresh();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }

View File

@ -65,7 +65,7 @@ public function loadImages()
]; ];
})->toArray(); })->toArray();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -43,7 +43,7 @@ public function submit(): void
]); ]);
$this->emit('refreshScheduledBackups'); $this->emit('refreshScheduledBackups');
} catch (\Throwable $e) { } catch (\Throwable $e) {
general_error_handler($e, $this); handleError($e, $this);
} finally { } finally {
$this->frequency = ''; $this->frequency = '';
$this->save_s3 = true; $this->save_s3 = true;

View File

@ -35,7 +35,7 @@ public function mount()
public function stop() public function stop()
{ {
remote_process( instant_remote_process(
["docker rm -f {$this->database->uuid}"], ["docker rm -f {$this->database->uuid}"],
$this->database->destination->server $this->database->destination->server
); );
@ -45,7 +45,7 @@ public function stop()
} }
$this->database->status = 'stopped'; $this->database->status = 'stopped';
$this->database->save(); $this->database->save();
$this->emit('refresh'); $this->check_status();
// $this->database->environment->project->team->notify(new StatusChanged($this->database)); // $this->database->environment->project->team->notify(new StatusChanged($this->database));
} }

View File

@ -36,7 +36,7 @@ public function submit()
$this->script['filename'] = $this->filename; $this->script['filename'] = $this->filename;
$this->emitUp('save_init_script', $this->script); $this->emitUp('save_init_script', $this->script);
} catch (Exception $e) { } catch (Exception $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }

View File

@ -5,6 +5,7 @@
use App\Models\StandalonePostgresql; use App\Models\StandalonePostgresql;
use Exception; use Exception;
use Livewire\Component; use Livewire\Component;
use function Aws\filter; use function Aws\filter;
class General extends Component class General extends Component
@ -73,9 +74,9 @@ public function instantSave()
} }
$this->getDbUrl(); $this->getDbUrl();
$this->database->save(); $this->database->save();
} catch(Exception $e) { } catch(\Throwable $e) {
$this->database->is_public = !$this->database->is_public; $this->database->is_public = !$this->database->is_public;
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
@ -140,7 +141,7 @@ public function submit()
$this->database->save(); $this->database->save();
$this->emit('success', 'Database updated successfully.'); $this->emit('success', 'Database updated successfully.');
} catch (Exception $e) { } catch (Exception $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -20,7 +20,7 @@ public function submit()
$this->project->save(); $this->project->save();
$this->emit('saved'); $this->emit('saved');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
} }

View File

@ -165,7 +165,7 @@ public function submit()
'project_uuid' => $project->uuid, 'project_uuid' => $project->uuid,
]); ]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }

View File

@ -118,7 +118,7 @@ public function submit()
'application_uuid' => $application->uuid, 'application_uuid' => $application->uuid,
]); ]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }

View File

@ -76,14 +76,14 @@ public function load_branch()
$this->get_branch(); $this->get_branch();
$this->selected_branch = $this->git_branch; $this->selected_branch = $this->git_branch;
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
if (!$this->branch_found && $this->git_branch == 'main') { if (!$this->branch_found && $this->git_branch == 'main') {
try { try {
$this->git_branch = 'master'; $this->git_branch = 'master';
$this->get_branch(); $this->get_branch();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }
@ -162,7 +162,7 @@ public function submit()
'application_uuid' => $application->uuid, 'application_uuid' => $application->uuid,
]); ]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -41,7 +41,7 @@ public function mount()
// instantCommand("psql {$this->existingPostgresqlUrl} -c 'SELECT 1'"); // instantCommand("psql {$this->existingPostgresqlUrl} -c 'SELECT 1'");
// $this->emit('success', 'Successfully connected to the database.'); // $this->emit('success', 'Successfully connected to the database.');
// } catch (\Throwable $e) { // } catch (\Throwable $e) {
// return general_error_handler($e, $this); // return handleError($e, $this);
// } // }
// } // }
public function setType(string $type) public function setType(string $type)

View File

@ -114,7 +114,7 @@ public function submit($data)
$this->refreshEnvs(); $this->refreshEnvs();
$this->emit('success', 'Environment variable added successfully.'); $this->emit('success', 'Environment variable added successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -54,7 +54,7 @@ public function submit()
$this->resource->save(); $this->resource->save();
$this->emit('success', 'Resource limits updated successfully.'); $this->emit('success', 'Resource limits updated successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -29,7 +29,7 @@ public function submit($data)
$this->emit('success', 'Storage added successfully'); $this->emit('success', 'Storage added successfully');
$this->emit('clearAddStorage'); $this->emit('clearAddStorage');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -33,7 +33,7 @@ public function runCommand()
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true); $activity = remote_process([$this->command], Server::where('uuid', $this->server)->first(), ignore_errors: true);
$this->emit('newMonitorActivity', $activity->id); $this->emit('newMonitorActivity', $activity->id);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e); return handleError($e, $this);
} }
} }
} }

View File

@ -51,12 +51,12 @@ public function installDocker()
public function validateServer() public function validateServer()
{ {
try { try {
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server); ['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
if ($uptime) { if ($uptime) {
$this->uptime = $uptime; $this->uptime = $uptime;
$this->emit('success', 'Server is reachable!'); $this->emit('success', 'Server is reachable.');
} else { } else {
$this->emit('error', 'Server is not reachable'); $this->emit('error', 'Server is not reachable.');
return; return;
} }
if ($dockerVersion) { if ($dockerVersion) {
@ -64,10 +64,10 @@ public function validateServer()
$this->emit('proxyStatusUpdated'); $this->emit('proxyStatusUpdated');
$this->emit('success', 'Docker Engine 23+ is installed!'); $this->emit('success', 'Docker Engine 23+ is installed!');
} else { } else {
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.'); $this->emit('error', 'No Docker Engine or older than 23 version installed.');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, that: $this); return handleError($e, $this, customErrorMessage: "Server is not reachable: ");
} }
} }
@ -82,7 +82,7 @@ public function delete()
$this->server->delete(); $this->server->delete();
return redirect()->route('server.all'); return redirect()->route('server.all');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
public function submit() public function submit()

View File

@ -79,7 +79,7 @@ public function submit()
$server->settings->save(); $server->settings->save();
return redirect()->route('server.show', $server->uuid); return redirect()->route('server.show', $server->uuid);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e); return handleError($e);
} }
} }
} }

View File

@ -56,7 +56,7 @@ public function submit()
setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server); setup_default_redirect_404(redirect_url: $this->server->proxy->redirect_url, server: $this->server);
$this->emit('success', 'Proxy configuration saved.'); $this->emit('success', 'Proxy configuration saved.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e); return handleError($e);
} }
} }
@ -65,7 +65,7 @@ public function reset_proxy_configuration()
try { try {
$this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server, true); $this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server, true);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e); return handleError($e);
} }
} }
@ -75,7 +75,7 @@ public function loadProxyConfiguration()
ray('loadProxyConfiguration'); ray('loadProxyConfiguration');
$this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server); $this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e); return handleError($e);
} }
} }
} }

View File

@ -24,7 +24,7 @@ public function getProxyStatus()
$this->emit('proxyStatusUpdated'); $this->emit('proxyStatusUpdated');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e); return handleError($e);
} }
} }
public function getProxyStatusWithNoti() public function getProxyStatusWithNoti()

View File

@ -18,7 +18,7 @@ public function mount()
return redirect()->route('server.all'); return redirect()->route('server.all');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
public function render() public function render()

View File

@ -28,14 +28,14 @@ public function setPrivateKey($newPrivateKeyId)
]); ]);
$this->server->refresh(); $this->server->refresh();
refresh_server_connection($this->server->privateKey); refresh_server_connection($this->server->privateKey);
return general_error_handler($e, that: $this); return handleError($e, $this);
} }
} }
public function checkConnection() public function checkConnection()
{ {
try { try {
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server); ['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
if ($uptime) { if ($uptime) {
$this->emit('success', 'Server is reachable with this private key.'); $this->emit('success', 'Server is reachable with this private key.');
} else { } else {
@ -48,7 +48,7 @@ public function checkConnection()
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.'); $this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.');
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
throw new \Exception($e->getMessage()); return handleError($e, $this);
} }
} }

View File

@ -51,7 +51,7 @@ public function submitFromFields() {
$this->settings->save(); $this->settings->save();
$this->emit('success', 'Settings saved successfully.'); $this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function submitResend() { public function submitResend() {
@ -64,7 +64,7 @@ public function submitResend() {
$this->emit('success', 'Settings saved successfully.'); $this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->settings->resend_enabled = false; $this->settings->resend_enabled = false;
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function instantSaveResend() { public function instantSaveResend() {
@ -72,7 +72,7 @@ public function instantSaveResend() {
$this->settings->smtp_enabled = false; $this->settings->smtp_enabled = false;
$this->submitResend(); $this->submitResend();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function instantSave() public function instantSave()
@ -81,7 +81,7 @@ public function instantSave()
$this->settings->resend_enabled = false; $this->settings->resend_enabled = false;
$this->submit(); $this->submit();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
@ -100,7 +100,7 @@ public function submit()
$this->settings->save(); $this->settings->save();
$this->emit('success', 'Settings saved successfully.'); $this->emit('success', 'Settings saved successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }

View File

@ -52,7 +52,7 @@ public function submit()
$this->validate(); $this->validate();
$this->github_app->save(); $this->github_app->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
@ -66,7 +66,7 @@ public function delete()
$this->github_app->delete(); $this->github_app->delete();
redirect()->route('source.all'); redirect()->route('source.all');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -50,7 +50,7 @@ public function createGitHubApp()
} }
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]); redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -31,7 +31,7 @@ public function cancel()
$this->emit('reloadWindow', 5000); $this->emit('reloadWindow', 5000);
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function resume() public function resume()
@ -66,7 +66,7 @@ public function resume()
$this->emit('reloadWindow', 5000); $this->emit('reloadWindow', 5000);
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
public function stripeCustomerPortal() { public function stripeCustomerPortal() {

View File

@ -32,7 +32,7 @@ public function submit()
refreshSession(); refreshSession();
return redirect()->route('team.index'); return redirect()->route('team.index');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
} }

View File

@ -28,7 +28,7 @@ public function submit()
try { try {
$this->team->save(); $this->team->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
} }

View File

@ -36,7 +36,7 @@ private function generate_invite_link(bool $sendEmail = false)
try { try {
$member_emails = currentTeam()->members()->get()->pluck('email'); $member_emails = currentTeam()->members()->get()->pluck('email');
if ($member_emails->contains($this->email)) { if ($member_emails->contains($this->email)) {
return general_error_handler(that: $this, customErrorMessage: "$this->email is already a member of " . currentTeam()->name . "."); return handleError(livewire: $this, customErrorMessage: "$this->email is already a member of " . currentTeam()->name . ".");
} }
$uuid = new Cuid2(32); $uuid = new Cuid2(32);
$link = url('/') . config('constants.invitation.link.base_url') . $uuid; $link = url('/') . config('constants.invitation.link.base_url') . $uuid;
@ -57,7 +57,7 @@ private function generate_invite_link(bool $sendEmail = false)
if (!is_null($invitation)) { if (!is_null($invitation)) {
$invitationValid = $invitation->isValid(); $invitationValid = $invitation->isValid();
if ($invitationValid) { if ($invitationValid) {
return general_error_handler(that: $this, customErrorMessage: "Pending invitation already exists for $this->email."); return handleError(livewire: $this, customErrorMessage: "Pending invitation already exists for $this->email.");
} else { } else {
$invitation->delete(); $invitation->delete();
} }
@ -91,7 +91,7 @@ private function generate_invite_link(bool $sendEmail = false)
if ($e->getCode() === '23505') { if ($e->getCode() === '23505') {
$error_message = 'Invitation already sent.'; $error_message = 'Invitation already sent.';
} }
return general_error_handler(err: $e, that: $this, customErrorMessage: $error_message); return handleError(error: $e, livewire: $this, customErrorMessage: $error_message);
} }
} }
} }

View File

@ -68,7 +68,7 @@ public function submit()
$this->storage->save(); $this->storage->save();
return redirect()->route('team.storages.show', $this->storage->uuid); return redirect()->route('team.storages.show', $this->storage->uuid);
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
@ -78,7 +78,7 @@ private function test_s3_connection()
$this->storage->testConnection(); $this->storage->testConnection();
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.'); return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
} }

View File

@ -33,7 +33,7 @@ public function test_s3_connection()
$this->storage->testConnection(); $this->storage->testConnection();
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.'); return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
@ -43,7 +43,7 @@ public function delete()
$this->storage->delete(); $this->storage->delete();
return redirect()->route('team.storages.all'); return redirect()->route('team.storages.all');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
@ -56,7 +56,7 @@ public function submit()
$this->storage->save(); $this->storage->save();
$this->emit('success', 'Storage settings saved.'); $this->emit('success', 'Storage settings saved.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler($e, $this); return handleError($e, $this);
} }
} }
} }

View File

@ -38,7 +38,7 @@ public function upgrade()
resolve(UpdateCoolify::class)(true); resolve(UpdateCoolify::class)(true);
Toaster::success("Upgrading to {$this->latestVersion} version..."); Toaster::success("Upgrading to {$this->latestVersion} version...");
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -54,7 +54,7 @@ public function submit()
$this->emit('success', 'Check your email to verify your email address.'); $this->emit('success', 'Check your email to verify your email address.');
dispatch(new SendConfirmationForWaitlistJob($this->email, $waitlist->uuid)); dispatch(new SendConfirmationForWaitlistJob($this->email, $waitlist->uuid));
} catch (\Throwable $e) { } catch (\Throwable $e) {
return general_error_handler(err: $e, that: $this); return handleError($e, $this);
} }
} }
} }

View File

@ -177,7 +177,7 @@ private function deploy_simple_dockerfile()
$this->prepare_builder_image(); $this->prepare_builder_image();
$this->execute_remote_command( $this->execute_remote_command(
[ [
$this->execute_in_builder("echo '$dockerfile_base64' | base64 -d > $this->workdir/Dockerfile") executeInDocker($this->deployment_uuid, "echo '$dockerfile_base64' | base64 -d > $this->workdir/Dockerfile")
], ],
); );
$this->build_image_name = Str::lower("{$this->application->git_repository}:build"); $this->build_image_name = Str::lower("{$this->application->git_repository}:build");
@ -302,7 +302,7 @@ private function deploy_pull_request()
$this->stop_running_container(); $this->stop_running_container();
$this->execute_remote_command( $this->execute_remote_command(
["echo -n 'Starting preview deployment.'"], ["echo -n 'Starting preview deployment.'"],
[$this->execute_in_builder("docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true], [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
); );
} }
@ -324,16 +324,12 @@ private function prepare_builder_image()
"hidden" => true, "hidden" => true,
], ],
[ [
"command" => $this->execute_in_builder("mkdir -p {$this->workdir}") "command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}")
], ],
); );
} }
private function execute_in_builder(string $command)
{
return "docker exec {$this->deployment_uuid} bash -c '{$command}'";
// return "docker exec {$this->deployment_uuid} bash -c '{$command} |& tee -a /proc/1/fd/1; [ \$PIPESTATUS -eq 0 ] || exit \$PIPESTATUS'";
}
private function clone_repository() private function clone_repository()
{ {
@ -345,7 +341,7 @@ private function clone_repository()
$this->importing_git_repository() $this->importing_git_repository()
], ],
[ [
$this->execute_in_builder("cd {$this->workdir} && git rev-parse HEAD"), executeInDocker($this->deployment_uuid, "cd {$this->workdir} && git rev-parse HEAD"),
"hidden" => true, "hidden" => true,
"save" => "git_commit_sha" "save" => "git_commit_sha"
], ],
@ -372,13 +368,13 @@ private function importing_git_repository()
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->workdir}"; $git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->workdir}";
$git_clone_command = $this->set_git_import_settings($git_clone_command); $git_clone_command = $this->set_git_import_settings($git_clone_command);
$commands->push($this->execute_in_builder($git_clone_command)); $commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
} else { } else {
$github_access_token = generate_github_installation_token($this->source); $github_access_token = generate_github_installation_token($this->source);
$commands->push($this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}")); $commands->push(executeInDocker($this->deployment_uuid, "git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}"));
} }
if ($this->pull_request_id !== 0) { if ($this->pull_request_id !== 0) {
$commands->push($this->execute_in_builder("cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name")); $commands->push(executeInDocker($this->deployment_uuid, "cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
} }
return $commands->implode(' && '); return $commands->implode(' && ');
} }
@ -388,10 +384,10 @@ private function importing_git_repository()
$git_clone_command = "GIT_SSH_COMMAND=\"ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_full_url} {$this->workdir}"; $git_clone_command = "GIT_SSH_COMMAND=\"ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_full_url} {$this->workdir}";
$git_clone_command = $this->set_git_import_settings($git_clone_command); $git_clone_command = $this->set_git_import_settings($git_clone_command);
$commands = collect([ $commands = collect([
$this->execute_in_builder("mkdir -p /root/.ssh"), executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh"),
$this->execute_in_builder("echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa"), executeInDocker($this->deployment_uuid, "echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa"),
$this->execute_in_builder("chmod 600 /root/.ssh/id_rsa"), executeInDocker($this->deployment_uuid, "chmod 600 /root/.ssh/id_rsa"),
$this->execute_in_builder($git_clone_command) executeInDocker($this->deployment_uuid, $git_clone_command)
]); ]);
return $commands->implode(' && '); return $commands->implode(' && ');
} }
@ -414,7 +410,7 @@ private function set_git_import_settings($git_clone_command)
private function cleanup_git() private function cleanup_git()
{ {
$this->execute_remote_command( $this->execute_remote_command(
[$this->execute_in_builder("rm -fr {$this->workdir}/.git")], [executeInDocker($this->deployment_uuid, "rm -fr {$this->workdir}/.git")],
); );
} }
@ -425,8 +421,8 @@ private function generate_nixpacks_confs()
"echo -n 'Generating nixpacks configuration.'", "echo -n 'Generating nixpacks configuration.'",
], ],
[$this->nixpacks_build_cmd()], [$this->nixpacks_build_cmd()],
[$this->execute_in_builder("cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")], [executeInDocker($this->deployment_uuid, "cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
[$this->execute_in_builder("rm -f {$this->workdir}/.nixpacks/Dockerfile")] [executeInDocker($this->deployment_uuid, "rm -f {$this->workdir}/.nixpacks/Dockerfile")]
); );
} }
@ -444,7 +440,7 @@ private function nixpacks_build_cmd()
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\""; $nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
} }
$nixpacks_command .= " {$this->workdir}"; $nixpacks_command .= " {$this->workdir}";
return $this->execute_in_builder($nixpacks_command); return executeInDocker($this->deployment_uuid, $nixpacks_command);
} }
private function generate_env_variables() private function generate_env_variables()
@ -522,7 +518,7 @@ private function generate_compose_file()
} }
$this->docker_compose = Yaml::dump($docker_compose, 10); $this->docker_compose = Yaml::dump($docker_compose, 10);
$this->docker_compose_base64 = base64_encode($this->docker_compose); $this->docker_compose_base64 = base64_encode($this->docker_compose);
$this->execute_remote_command([$this->execute_in_builder("echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]); $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
} }
private function generate_local_persistent_volumes() private function generate_local_persistent_volumes()
@ -679,7 +675,7 @@ private function build_image()
if ($this->application->settings->is_static) { if ($this->application->settings->is_static) {
$this->execute_remote_command([ $this->execute_remote_command([
$this->execute_in_builder("docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true executeInDocker($this->deployment_uuid, "docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
]); ]);
$dockerfile = base64_encode("FROM {$this->application->static_image} $dockerfile = base64_encode("FROM {$this->application->static_image}
@ -706,18 +702,18 @@ private function build_image()
}"); }");
$this->execute_remote_command( $this->execute_remote_command(
[ [
$this->execute_in_builder("echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod") executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod")
], ],
[ [
$this->execute_in_builder("echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf") executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
], ],
[ [
$this->execute_in_builder("docker build --network host -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true executeInDocker($this->deployment_uuid, "docker build --network host -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
] ]
); );
} else { } else {
$this->execute_remote_command([ $this->execute_remote_command([
$this->execute_in_builder("docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true executeInDocker($this->deployment_uuid, "docker build --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
]); ]);
} }
} }
@ -727,7 +723,7 @@ private function stop_running_container()
if ($this->currently_running_container_name) { if ($this->currently_running_container_name) {
$this->execute_remote_command( $this->execute_remote_command(
["echo -n 'Removing old version of your application.'"], ["echo -n 'Removing old version of your application.'"],
[$this->execute_in_builder("docker rm -f $this->currently_running_container_name >/dev/null 2>&1"), "hidden" => true], [executeInDocker($this->deployment_uuid, "docker rm -f $this->currently_running_container_name >/dev/null 2>&1"), "hidden" => true],
); );
} }
} }
@ -736,7 +732,7 @@ private function start_by_compose_file()
{ {
$this->execute_remote_command( $this->execute_remote_command(
["echo -n 'Rolling update started.'"], ["echo -n 'Rolling update started.'"],
[$this->execute_in_builder("docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true], [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
); );
} }
@ -759,7 +755,7 @@ private function generate_build_env_variables()
private function add_build_env_variables_to_dockerfile() private function add_build_env_variables_to_dockerfile()
{ {
$this->execute_remote_command([ $this->execute_remote_command([
$this->execute_in_builder("cat {$this->workdir}/Dockerfile"), "hidden" => true, "save" => 'dockerfile' executeInDocker($this->deployment_uuid, "cat {$this->workdir}/Dockerfile"), "hidden" => true, "save" => 'dockerfile'
]); ]);
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n")); $dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
@ -768,7 +764,7 @@ private function add_build_env_variables_to_dockerfile()
} }
$dockerfile_base64 = base64_encode($dockerfile->implode("\n")); $dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
$this->execute_remote_command([ $this->execute_remote_command([
$this->execute_in_builder("echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}/Dockerfile"), executeInDocker($this->deployment_uuid, "echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}/Dockerfile"),
"hidden" => true "hidden" => true
]); ]);
} }

View File

@ -18,7 +18,6 @@
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Throwable;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
@ -117,7 +116,7 @@ private function backup_standalone_postgresql(): void
$this->backup_status = 'success'; $this->backup_status = 'success';
$this->team->notify(new BackupSuccess($this->backup, $this->database)); $this->team->notify(new BackupSuccess($this->backup, $this->database));
} catch (Throwable $e) { } catch (\Throwable $e) {
$this->backup_status = 'failed'; $this->backup_status = 'failed';
$this->add_to_backup_output($e->getMessage()); $this->add_to_backup_output($e->getMessage());
ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage()); ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage());

View File

@ -4,8 +4,6 @@
use App\Models\Application; use App\Models\Application;
use App\Models\ApplicationPreview; use App\Models\ApplicationPreview;
use App\Notifications\Channels\DiscordChannel;
use App\Notifications\Channels\EmailChannel;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@ -18,13 +16,14 @@ class DeploymentFailed extends Notification implements ShouldQueue
public $tries = 5; public $tries = 5;
public Application $application; public Application $application;
public string $deployment_uuid;
public ?ApplicationPreview $preview = null; public ?ApplicationPreview $preview = null;
public string $deployment_uuid;
public string $application_name; public string $application_name;
public ?string $deployment_url = null;
public string $project_uuid; public string $project_uuid;
public string $environment_name; public string $environment_name;
public ?string $deployment_url = null;
public ?string $fqdn = null; public ?string $fqdn = null;
public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null) public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null)

View File

@ -4,8 +4,6 @@
use App\Models\Application; use App\Models\Application;
use App\Models\ApplicationPreview; use App\Models\ApplicationPreview;
use App\Notifications\Channels\DiscordChannel;
use App\Notifications\Channels\EmailChannel;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@ -18,14 +16,15 @@ class DeploymentSuccess extends Notification implements ShouldQueue
public $tries = 5; public $tries = 5;
public Application $application; public Application $application;
public string $deployment_uuid;
public ApplicationPreview|null $preview = null; public ApplicationPreview|null $preview = null;
public string $deployment_uuid;
public string $application_name; public string $application_name;
public string|null $deployment_url = null;
public string $project_uuid; public string $project_uuid;
public string $environment_name; public string $environment_name;
public string|null $fqdn;
public ?string $deployment_url = null;
public ?string $fqdn;
public function __construct(Application $application, string $deployment_uuid, ApplicationPreview|null $preview = null) public function __construct(Application $application, string $deployment_uuid, ApplicationPreview|null $preview = null)
{ {

View File

@ -2,8 +2,7 @@
namespace App\Notifications\Application; namespace App\Notifications\Application;
use App\Notifications\Channels\DiscordChannel; use App\Models\Application;
use App\Notifications\Channels\EmailChannel;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
@ -15,13 +14,14 @@ class StatusChanged extends Notification implements ShouldQueue
use Queueable; use Queueable;
public $tries = 5; public $tries = 5;
public $application;
public Application $application;
public string $application_name; public string $application_name;
public string|null $application_url = null;
public string $project_uuid; public string $project_uuid;
public string $environment_name; public string $environment_name;
public string|null $fqdn;
public ?string $application_url = null;
public ?string $fqdn;
public function __construct($application) public function __construct($application)
{ {

View File

@ -11,7 +11,7 @@
trait ExecuteRemoteCommand trait ExecuteRemoteCommand
{ {
public string|null $save = null; public ?string $save = null;
public function execute_remote_command(...$commands) public function execute_remote_command(...$commands)
{ {
@ -25,11 +25,8 @@ public function execute_remote_command(...$commands)
throw new \RuntimeException('Server is not set or is not an instance of Server model'); throw new \RuntimeException('Server is not set or is not an instance of Server model');
} }
$ip = data_get($this->server, 'ip');
$user = data_get($this->server, 'user');
$port = data_get($this->server, 'port');
$commandsText->each(function ($single_command) use ($ip, $user, $port) { $commandsText->each(function ($single_command) {
$command = data_get($single_command, 'command') ?? $single_command[0] ?? null; $command = data_get($single_command, 'command') ?? $single_command[0] ?? null;
if ($command === null) { if ($command === null) {
throw new \RuntimeException('Command is not set'); throw new \RuntimeException('Command is not set');
@ -38,7 +35,7 @@ public function execute_remote_command(...$commands)
$ignore_errors = data_get($single_command, 'ignore_errors', false); $ignore_errors = data_get($single_command, 'ignore_errors', false);
$this->save = data_get($single_command, 'save'); $this->save = data_get($single_command, 'save');
$remote_command = generateSshCommand( $ip, $user, $port, $command); $remote_command = generateSshCommand($this->server, $command);
$process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden) { $process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden) {
$output = Str::of($output)->trim(); $output = Str::of($output)->trim();
$new_log_entry = [ $new_log_entry = [

View File

@ -59,6 +59,18 @@ function format_docker_envs_to_json($rawOutput)
return collect([]); return collect([]);
} }
} }
function checkMinimumDockerEngineVersion($dockerVersion) {
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value();
if ($majorDockerVersion <= 22) {
$dockerVersion = null;
}
return $dockerVersion;
}
function executeInDocker(string $containerId, string $command)
{
return "docker exec {$containerId} bash -c '{$command}'";
// return "docker exec {$this->deployment_uuid} bash -c '{$command} |& tee -a /proc/1/fd/1; [ \$PIPESTATUS -eq 0 ] || exit \$PIPESTATUS'";
}
function getApplicationContainerStatus(Application $application) { function getApplicationContainerStatus(Application $application) {
$server = data_get($application,'destination.server'); $server = data_get($application,'destination.server');

View File

@ -36,12 +36,10 @@ function remote_process(
return resolve(PrepareCoolifyTask::class, [ return resolve(PrepareCoolifyTask::class, [
'remoteProcessArgs' => new CoolifyTaskArgs( 'remoteProcessArgs' => new CoolifyTaskArgs(
server_ip: $server->ip, server_uuid: $server->uuid,
command: <<<EOT command: <<<EOT
{$command_string} {$command_string}
EOT, EOT,
port: $server->port,
user: $server->user,
type: $type, type: $type,
type_uuid: $type_uuid, type_uuid: $type_uuid,
model: $model, model: $model,
@ -66,15 +64,14 @@ function addPrivateKeyToSshAgent(Server $server)
Storage::disk('ssh-keys')->makeDirectory('.'); Storage::disk('ssh-keys')->makeDirectory('.');
Storage::disk('ssh-mux')->makeDirectory('.'); Storage::disk('ssh-mux')->makeDirectory('.');
Storage::disk('ssh-keys')->put($sshKeyFileLocation, $server->privateKey->private_key); Storage::disk('ssh-keys')->put($sshKeyFileLocation, $server->privateKey->private_key);
return '/var/www/html/storage/app/ssh/keys/' . $sshKeyFileLocation; $location = '/var/www/html/storage/app/ssh/keys/' . $sshKeyFileLocation;
return $location;
} }
function generateSshCommand(string $server_ip, string $user, string $port, string $command, bool $isMux = true) function generateSshCommand(Server $server, string $command, bool $isMux = true)
{ {
$server = Server::where('ip', $server_ip)->first(); $user = $server->user;
if (!$server) { $port = $server->port;
throw new \Exception("Server with ip {$server_ip} not found");
}
$privateKeyLocation = addPrivateKeyToSshAgent($server); $privateKeyLocation = addPrivateKeyToSshAgent($server);
$timeout = config('constants.ssh.command_timeout'); $timeout = config('constants.ssh.command_timeout');
$connectionTimeout = config('constants.ssh.connection_timeout'); $connectionTimeout = config('constants.ssh.connection_timeout');
@ -95,27 +92,21 @@ function generateSshCommand(string $server_ip, string $user, string $port, strin
. '-o RequestTTY=no ' . '-o RequestTTY=no '
. '-o LogLevel=ERROR ' . '-o LogLevel=ERROR '
. "-p {$port} " . "-p {$port} "
. "{$user}@{$server_ip} " . "{$user}@{$server->ip} "
. " 'bash -se' << \\$delimiter" . PHP_EOL . " 'bash -se' << \\$delimiter" . PHP_EOL
. $command . PHP_EOL . $command . PHP_EOL
. $delimiter; . $delimiter;
// ray($ssh_command); // ray($ssh_command);
return $ssh_command; return $ssh_command;
} }
function instant_remote_process(array $command, Server $server, $throwError = true, $repeat = 1) function instant_remote_process(array $command, Server $server, $throwError = true)
{ {
$command_string = implode("\n", $command); $command_string = implode("\n", $command);
$ssh_command = generateSshCommand($server->ip, $server->user, $server->port, $command_string); $ssh_command = generateSshCommand($server, $command_string);
$process = Process::run($ssh_command); $process = Process::run($ssh_command);
$output = trim($process->output()); $output = trim($process->output());
$exitCode = $process->exitCode(); $exitCode = $process->exitCode();
if ($exitCode !== 0) { if ($exitCode !== 0) {
if ($repeat > 1) {
ray("repeat: ", $repeat);
Sleep::for(200)->milliseconds();
return instant_remote_process($command, $server, $throwError, $repeat - 1);
}
// ray('ERROR OCCURED: ' . $process->errorOutput());
if (!$throwError) { if (!$throwError) {
return null; return null;
} }
@ -161,11 +152,10 @@ function refresh_server_connection(PrivateKey $private_key)
} }
} }
function validateServer(Server $server) function validateServer(Server $server, bool $throwError = false)
{ {
try { try {
refresh_server_connection($server->privateKey); $uptime = instant_remote_process(['uptime'], $server, $throwError);
$uptime = instant_remote_process(['uptime'], $server, false);
if (!$uptime) { if (!$uptime) {
$server->settings->is_reachable = false; $server->settings->is_reachable = false;
return [ return [
@ -175,7 +165,7 @@ function validateServer(Server $server)
} }
$server->settings->is_reachable = true; $server->settings->is_reachable = true;
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, false); $dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $server, $throwError);
if (!$dockerVersion) { if (!$dockerVersion) {
$dockerVersion = null; $dockerVersion = null;
return [ return [
@ -183,9 +173,8 @@ function validateServer(Server $server)
"dockerVersion" => null, "dockerVersion" => null,
]; ];
} }
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value(); $dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
if ($majorDockerVersion <= 22) { if (is_null($dockerVersion)) {
$dockerVersion = null;
$server->settings->is_usable = false; $server->settings->is_usable = false;
} else { } else {
$server->settings->is_usable = true; $server->settings->is_usable = true;

View File

@ -74,7 +74,29 @@ function refreshSession(?Team $team = null): void
}); });
session(['currentTeam' => $team]); session(['currentTeam' => $team]);
} }
function general_error_handler(Throwable | null $err = null, $that = null, $isJson = false, $customErrorMessage = null): mixed function handleError(?Throwable $error = null, ?Livewire\Component $livewire = null, ?string $customErrorMessage = null)
{
ray('handleError');
if ($error instanceof Throwable) {
$message = $error->getMessage();
} else {
$message = null;
}
if ($customErrorMessage) {
$message = $customErrorMessage . ' ' . $message;
}
if ($error instanceof TooManyRequestsException) {
if (isset($livewire)) {
return $livewire->emit('error', "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.");
}
return "Too many requests. Please try again in {$error->secondsUntilAvailable} seconds.";
}
if (isset($livewire)) {
return $livewire->emit('error', $message);
}
throw new RuntimeException($message);
}
function general_error_handler(Throwable $err, Livewire\Component $that = null, $isJson = false, $customErrorMessage = null): mixed
{ {
try { try {
ray($err); ray($err);
@ -95,7 +117,7 @@ function general_error_handler(Throwable | null $err = null, $that = null, $isJs
} }
throw new Exception($customErrorMessage ?? $err->getMessage()); throw new Exception($customErrorMessage ?? $err->getMessage());
} }
} catch (Throwable $e) { } catch (\Throwable $e) {
if ($that) { if ($that) {
return $that->emit('error', $customErrorMessage ?? $e->getMessage()); return $that->emit('error', $customErrorMessage ?? $e->getMessage());
} elseif ($isJson) { } elseif ($isJson) {
@ -122,7 +144,7 @@ function get_latest_version_of_coolify(): string
$response = Http::get('https://cdn.coollabs.io/coolify/versions.json'); $response = Http::get('https://cdn.coollabs.io/coolify/versions.json');
$versions = $response->json(); $versions = $response->json();
return data_get($versions, 'coolify.v4.version'); return data_get($versions, 'coolify.v4.version');
} catch (Throwable $e) { } catch (\Throwable $e) {
//throw $e; //throw $e;
ray($e->getMessage()); ray($e->getMessage());
return '0.0.0'; return '0.0.0';
@ -321,7 +343,8 @@ function setNotificationChannels($notifiable, $event)
} }
return $channels; return $channels;
} }
function parseEnvFormatToArray($env_file_contents) { function parseEnvFormatToArray($env_file_contents)
{
$env_array = array(); $env_array = array();
$lines = explode("\n", $env_file_contents); $lines = explode("\n", $env_file_contents);
foreach ($lines as $line) { foreach ($lines as $line) {
@ -334,8 +357,7 @@ function parseEnvFormatToArray($env_file_contents) {
$value = substr($line, $equals_pos + 1); $value = substr($line, $equals_pos + 1);
if (substr($value, 0, 1) === '"' && substr($value, -1) === '"') { if (substr($value, 0, 1) === '"' && substr($value, -1) === '"') {
$value = substr($value, 1, -1); $value = substr($value, 1, -1);
} } elseif (substr($value, 0, 1) === "'" && substr($value, -1) === "'") {
elseif (substr($value, 0, 1) === "'" && substr($value, -1) === "'") {
$value = substr($value, 1, -1); $value = substr($value, 1, -1);
} }
$env_array[$key] = $value; $env_array[$key] = $value;

View File

@ -30,14 +30,14 @@
* *
* Minimum: 3000 (in milliseconds) * Minimum: 3000 (in milliseconds)
*/ */
'duration' => 5000, 'duration' => 1500,
/** /**
* The horizontal position of each toast. * The horizontal position of each toast.
* *
* Supported: "center", "left" or "right" * Supported: "center", "left" or "right"
*/ */
'position' => 'right', 'position' => 'center',
/** /**
* Whether messages passed as translation keys should be translated automatically. * Whether messages passed as translation keys should be translated automatically.

View File

@ -24,17 +24,17 @@ class="text-xs normal-case hover:no-underline btn btn-sm bg-coollabs-gradient">
<form action="/login" method="POST" class="flex flex-col gap-2"> <form action="/login" method="POST" class="flex flex-col gap-2">
@csrf @csrf
@env('local') @env('local')
<x-forms.input value="test@example.com" type="email" name="email" <x-forms.input value="test@example.com" type="email" name="email" required
label="{{ __('input.email') }}" autofocus /> label="{{ __('input.email') }}" autofocus />
<x-forms.input value="password" type="password" name="password" <x-forms.input value="password" type="password" name="password" required
label="{{ __('input.password') }}" /> label="{{ __('input.password') }}" />
<a href="/forgot-password" class="text-xs"> <a href="/forgot-password" class="text-xs">
{{ __('auth.forgot_password') }}? {{ __('auth.forgot_password') }}?
</a> </a>
@else @else
<x-forms.input type="email" name="email" label="{{ __('input.email') }}" autofocus /> <x-forms.input type="email" name="email" required label="{{ __('input.email') }}" autofocus />
<x-forms.input type="password" name="password" label="{{ __('input.password') }}" /> <x-forms.input type="password" name="password" required label="{{ __('input.password') }}" />
<a href="/forgot-password" class="text-xs"> <a href="/forgot-password" class="text-xs">
{{ __('auth.forgot_password') }}? {{ __('auth.forgot_password') }}?
</a> </a>

View File

@ -11,7 +11,7 @@
<div class="flex-1"></div> <div class="flex-1"></div>
<x-applications.advanced :application="$application" /> <x-applications.advanced :application="$application" />
@if ($application->status === 'running') @if ($application->status !== 'exited')
<button wire:click='deploy' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400"> <button wire:click='deploy' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-warning" viewBox="0 0 24 24" stroke-width="2" <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-warning" viewBox="0 0 24 24" stroke-width="2"
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">

View File

@ -11,7 +11,7 @@
<div class="flex-1"></div> <div class="flex-1"></div>
{{-- <x-applications.advanced :application="$application" /> --}} {{-- <x-applications.advanced :application="$application" /> --}}
@if ($database->status === 'running') @if ($database->status !== 'exited')
<button wire:click='stop' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400"> <button wire:click='stop' class="flex items-center gap-2 cursor-pointer hover:text-white text-neutral-400">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24" stroke-width="2" <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-error" viewBox="0 0 24 24" stroke-width="2"
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">

View File

@ -1,6 +1,6 @@
<x-emails.layout> <x-emails.layout>
Container ({{ $containerName }}) has been restarted automatically on {{$serverName}}, because it was stopped unexpected. Container ({{ $containerName }}) has been restarted automatically on {{$serverName}}, because it was stopped unexpectedly.
@if ($containerName === 'coolify-proxy') @if ($containerName === 'coolify-proxy')
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources. Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.

View File

@ -1,6 +1,6 @@
<x-emails.layout> <x-emails.layout>
Container {{ $containerName }} has been stopped unexpected on {{$serverName}}. Container {{ $containerName }} has been stopped unexpectedly on {{$serverName}}.
@if ($url) @if ($url)
Please check what is going on [here]({{ $url }}). Please check what is going on [here]({{ $url }}).

View File

@ -182,7 +182,7 @@
placeholder="Username to connect to your server. Default is root." label="Username" placeholder="Username to connect to your server. Default is root." label="Username"
id="remoteServerUser" /> id="remoteServerUser" />
</div> </div>
<x-forms.button type="submit">Save</x-forms.button> <x-forms.button type="submit">Check Connection</x-forms.button>
</form> </form>
</x-slot:actions> </x-slot:actions>
<x-slot:explanation> <x-slot:explanation>

View File

@ -14,6 +14,6 @@
</x-forms.button> </x-forms.button>
</form> </form>
<div class="container w-full pt-10 mx-auto"> <div class="container w-full pt-10 mx-auto">
<livewire:activity-monitor header="Logs" /> <livewire:activity-monitor header="Command output" />
</div> </div>
</div> </div>

View File

@ -56,18 +56,18 @@
<div> <div>
<h2>Proxy</h2> <h2>Proxy</h2>
<div class="subtitle">Select a proxy you would like to use on this server.</div> <div class="subtitle">Select a proxy you would like to use on this server.</div>
<div class="flex gap-2"> <div class="grid gap-4">
<x-forms.button class="w-32 box" wire:click="select_proxy('NONE')"> <x-forms.button class="box" wire:click="select_proxy('NONE')">
Custom (None) Custom (None)
</x-forms.button> </x-forms.button>
<x-forms.button class="w-32 box" wire:click="select_proxy('TRAEFIK_V2')"> <x-forms.button class="box" wire:click="select_proxy('TRAEFIK_V2')">
Traefik Traefik
v2 v2
</x-forms.button> </x-forms.button>
<x-forms.button disabled class="w-32 box"> <x-forms.button disabled class="box">
Nginx Nginx
</x-forms.button> </x-forms.button>
<x-forms.button disabled class="w-32 box"> <x-forms.button disabled class="box">
Caddy Caddy
</x-forms.button> </x-forms.button>
</div> </div>

View File

@ -8,7 +8,7 @@
</x-slot:modalBody> </x-slot:modalBody>
</x-modal> </x-modal>
@if (is_null(data_get($server, 'proxy.type')) || data_get($server, 'proxy.type') !== 'NONE') @if (is_null(data_get($server, 'proxy.type')) || data_get($server, 'proxy.type') !== 'NONE')
@if (data_get($server, 'proxy.status') === 'running') @if (data_get($server, 'proxy.status') !== 'exited')
<div class="flex gap-4"> <div class="flex gap-4">
<button> <button>
<a target="_blank" href="http://{{$server->ip}}:8080"> <a target="_blank" href="http://{{$server->ip}}:8080">

View File

@ -31,19 +31,15 @@ class="text-white normal-case btn btn-xs no-animation btn-primary">
</div> </div>
</form> </form>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<details class="border rounded collapse border-coolgray-500 collapse-arrow "> <div class="p-4 border border-coolgray-500">
<summary class="text-xl collapse-title"> <h3>SMTP Server</h3>
<div>SMTP Server</div>
<div class="w-32"> <div class="w-32">
<x-forms.checkbox instantSave id="settings.smtp_enabled" label="Enabled" /> <x-forms.checkbox instantSave id="settings.smtp_enabled" label="Enabled" />
</div> </div>
</summary>
<div class="collapse-content">
<form wire:submit.prevent='submit' class="flex flex-col"> <form wire:submit.prevent='submit' class="flex flex-col">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="flex flex-col w-full gap-2 xl:flex-row"> <div class="flex flex-col w-full gap-2 xl:flex-row">
<x-forms.input required id="settings.smtp_host" placeholder="smtp.mailgun.org" <x-forms.input required id="settings.smtp_host" placeholder="smtp.mailgun.org" label="Host" />
label="Host" />
<x-forms.input required id="settings.smtp_port" placeholder="587" label="Port" /> <x-forms.input required id="settings.smtp_port" placeholder="587" label="Port" />
<x-forms.input id="settings.smtp_encryption" helper="If SMTP uses SSL, set it to 'tls'." <x-forms.input id="settings.smtp_encryption" helper="If SMTP uses SSL, set it to 'tls'."
placeholder="tls" label="Encryption" /> placeholder="tls" label="Encryption" />
@ -62,19 +58,15 @@ class="text-white normal-case btn btn-xs no-animation btn-primary">
</div> </div>
</form> </form>
</div> </div>
</details> <div class="p-4 border border-coolgray-500">
<details class="border rounded collapse border-coolgray-500 collapse-arrow"> <h3>Resend</h3>
<summary class="text-xl collapse-title">
<div>Resend</div>
<div class="w-32"> <div class="w-32">
<x-forms.checkbox instantSave='instantSaveResend' id="settings.resend_enabled" label="Enabled" /> <x-forms.checkbox instantSave='instantSaveResend' id="settings.resend_enabled" label="Enabled" />
</div> </div>
</summary>
<div class="collapse-content">
<form wire:submit.prevent='submitResend' class="flex flex-col"> <form wire:submit.prevent='submitResend' class="flex flex-col">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="flex flex-col w-full gap-2 xl:flex-row"> <div class="flex flex-col w-full gap-2 xl:flex-row">
<x-forms.input type="password" id="settings.resend_api_key" placeholder="API key" <x-forms.input type="password" id="settings.resend_api_key" placeholder="API key" required
label="Host" /> label="Host" />
</div> </div>
</div> </div>
@ -85,6 +77,5 @@ class="text-white normal-case btn btn-xs no-animation btn-primary">
</div> </div>
</form> </form>
</div> </div>
</details>
</div> </div>
</div> </div>

View File

@ -43,7 +43,7 @@
$github_app->save(); $github_app->save();
return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]); return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
} catch (Exception $e) { } catch (Exception $e) {
return general_error_handler(err: $e); return handleError($e);
} }
}); });
@ -59,7 +59,7 @@
} }
return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]); return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
} catch (Exception $e) { } catch (Exception $e) {
return general_error_handler(err: $e); return handleError($e);
} }
}); });
Route::post('/source/github/events', function () { Route::post('/source/github/events', function () {
@ -179,7 +179,7 @@
} }
} catch (Exception $e) { } catch (Exception $e) {
ray($e->getMessage()); ray($e->getMessage());
return general_error_handler(err: $e); return handleError($e);
} }
}); });
Route::get('/waitlist/confirm', function () { Route::get('/waitlist/confirm', function () {