Merge branch 'next' into feat/deployment-token

This commit is contained in:
Kael
2024-11-01 16:55:00 +11:00
162 changed files with 1985 additions and 1754 deletions

View File

@@ -53,8 +53,6 @@ jobs:
tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
labels: |
coolify.managed=true
aarch64:
runs-on: [self-hosted, arm64]
@@ -90,8 +88,6 @@ jobs:
tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}-aarch64
labels: |
coolify.managed=true
merge-manifest:
runs-on: ubuntu-latest

View File

@@ -48,8 +48,6 @@ jobs:
tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
labels: |
coolify.managed=true
aarch64:
runs-on: [self-hosted, arm64]
@@ -83,8 +81,6 @@ jobs:
tags: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64
${{ env.GITHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}-aarch64
labels: |
coolify.managed=true
merge-manifest:
runs-on: ubuntu-latest

View File

@@ -39,7 +39,6 @@ class RunRemoteProcess
*/
public function __construct(Activity $activity, bool $hide_from_output = false, bool $ignore_errors = false, $call_event_on_finish = null, $call_event_data = null)
{
if ($activity->getExtraProperty('type') !== ActivityTypes::INLINE->value && $activity->getExtraProperty('type') !== ActivityTypes::COMMAND->value) {
throw new \RuntimeException('Incompatible Activity to run a remote command.');
}

View File

@@ -8,7 +8,6 @@ use App\Models\ApplicationPreview;
use App\Models\Server;
use App\Models\ServiceDatabase;
use App\Notifications\Container\ContainerRestarted;
use App\Notifications\Container\ContainerStopped;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Lorisleiva\Actions\Concerns\AsAction;

View File

@@ -58,9 +58,7 @@ class StartProxy
}
if ($async) {
$activity = remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
return $activity;
return remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
} else {
instant_remote_process($commands, $server);
$server->proxy->set('status', 'running');
@@ -70,6 +68,5 @@ class StartProxy
return 'OK';
}
}
}

View File

@@ -50,7 +50,6 @@ class ConfigureCloudflared
'rm -fr /tmp/cloudflared',
]);
instant_remote_process($commands, $server);
}
}
}

View File

@@ -12,8 +12,6 @@ class RunCommand
public function handle(Server $server, $command)
{
$activity = remote_process(command: [$command], server: $server, ignore_errors: true, type: ActivityTypes::COMMAND->value);
return $activity;
return remote_process(command: [$command], server: $server, ignore_errors: true, type: ActivityTypes::COMMAND->value);
}
}

View File

@@ -5,7 +5,7 @@ namespace App\Actions\Server;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
class InstallLogDrain
class StartLogDrain
{
use AsAction;
@@ -13,12 +13,16 @@ class InstallLogDrain
{
if ($server->settings->is_logdrain_newrelic_enabled) {
$type = 'newrelic';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_highlight_enabled) {
$type = 'highlight';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_axiom_enabled) {
$type = 'axiom';
StopLogDrain::run($server);
} elseif ($server->settings->is_logdrain_custom_enabled) {
$type = 'custom';
StopLogDrain::run($server);
} else {
$type = 'none';
}
@@ -151,6 +155,8 @@ services:
- ./parsers.conf:/parsers.conf
ports:
- 127.0.0.1:24224:24224
labels:
- coolify.managed=true
restart: unless-stopped
');
$readme = base64_encode('# New Relic Log Drain
@@ -202,15 +208,11 @@ Files:
throw new \Exception('Unknown log drain type.');
}
$restart_command = [
"echo 'Stopping old Fluent Bit'",
"cd $config_path && docker compose down --remove-orphans || true",
"echo 'Starting Fluent Bit'",
"cd $config_path && docker compose up -d --remove-orphans",
"cd $config_path && docker compose up -d",
];
$command = array_merge($command, $add_envs_command, $restart_command);
StopLogDrain::run($server);
return instant_remote_process($command, $server);
} catch (\Throwable $e) {
return handleError($e);

View File

@@ -12,7 +12,7 @@ class StopLogDrain
public function handle(Server $server)
{
try {
return instant_remote_process(['docker rm -f coolify-log-drain || true'], $server);
return instant_remote_process(['docker rm -f coolify-log-drain'], $server, false);
} catch (\Throwable $e) {
return handleError($e);
}

View File

@@ -33,8 +33,7 @@ class StartService
$commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} >/dev/null 2>&1 || true";
}
}
$activity = remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
return $activity;
return remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged');
}
}

View File

@@ -64,6 +64,5 @@ class CleanupDatabase extends Command
if ($this->option('yes')) {
$webhooks->delete();
}
}
}

View File

@@ -26,6 +26,5 @@ class CleanupRedis extends Command
collect($queueOverlaps)->each(function ($key) {
Redis::connection()->del($key);
});
}
}

View File

@@ -36,7 +36,6 @@ class CleanupStuckedResources extends Command
private function cleanup_stucked_resources()
{
try {
$servers = Server::all()->filter(function ($server) {
return $server->isFunctional();

View File

@@ -73,7 +73,6 @@ class CloudCleanupSubscriptions extends Command
}
}
}
} catch (\Exception $e) {
$this->error($e->getMessage());
@@ -95,6 +94,5 @@ class CloudCleanupSubscriptions extends Command
]);
}
}
}
}

View File

@@ -25,7 +25,6 @@ class Dev extends Command
return;
}
}
public function generateOpenApi()

View File

@@ -32,7 +32,6 @@ class Init extends Command
$this->servers = Server::all();
if (isCloud()) {
} else {
$this->send_alive_signal();
get_public_ips();
@@ -120,7 +119,6 @@ class Init extends Command
} catch (\Throwable $e) {
echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
}
}
}

View File

@@ -21,6 +21,5 @@ class OpenApi extends Command
$error = preg_replace('/^\h*\v+/m', '', $error);
echo $error;
echo $process->output();
}
}

View File

@@ -3,128 +3,82 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Symfony\Component\Yaml\Yaml;
class ServicesGenerate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
* {@inheritdoc}
*/
protected $signature = 'services:generate';
/**
* The console command description.
*
* @var string
* {@inheritdoc}
*/
protected $description = 'Generate service-templates.yaml based on /templates/compose directory';
/**
* Execute the console command.
*/
public function handle()
public function handle(): int
{
$files = array_diff(scandir(base_path('templates/compose')), ['.', '..']);
$files = array_filter($files, function ($file) {
return strpos($file, '.yaml') !== false;
});
$serviceTemplatesJson = [];
foreach ($files as $file) {
$parsed = $this->process_file($file);
if ($parsed) {
$name = data_get($parsed, 'name');
$parsed = data_forget($parsed, 'name');
$serviceTemplatesJson[$name] = $parsed;
}
}
$serviceTemplatesJson = json_encode($serviceTemplatesJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$serviceTemplatesJson = collect(glob(base_path('templates/compose/*.yaml')))
->mapWithKeys(function ($file): array {
$file = basename($file);
$parsed = $this->processFile($file);
return $parsed === false ? [] : [
Arr::pull($parsed, 'name') => $parsed,
];
})->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
file_put_contents(base_path('templates/service-templates.json'), $serviceTemplatesJson.PHP_EOL);
return self::SUCCESS;
}
private function process_file($file)
private function processFile(string $file): false|array
{
$serviceName = str($file)->before('.yaml')->value();
$content = file_get_contents(base_path("templates/compose/$file"));
// $this->info($content);
$ignore = collect(preg_grep('/^# ignore:/', explode("\n", $content)))->values();
if ($ignore->count() > 0) {
$ignore = (bool) str($ignore[0])->after('# ignore:')->trim()->value();
} else {
$ignore = false;
}
if ($ignore) {
$data = collect(explode(PHP_EOL, $content))->mapWithKeys(function ($line): array {
preg_match('/^#(?<key>.*):(?<value>.*)$/U', $line, $m);
return $m ? [trim($m['key']) => trim($m['value'])] : [];
});
if (str($data->get('ignore'))->toBoolean()) {
$this->info("Ignoring $file");
return;
return false;
}
$this->info("Processing $file");
$documentation = collect(preg_grep('/^# documentation:/', explode("\n", $content)))->values();
if ($documentation->count() > 0) {
$documentation = str($documentation[0])->after('# documentation:')->trim()->value();
$documentation = str($documentation)->append('?utm_source=coolify.io');
} else {
$documentation = 'https://coolify.io/docs';
}
$slogan = collect(preg_grep('/^# slogan:/', explode("\n", $content)))->values();
if ($slogan->count() > 0) {
$slogan = str($slogan[0])->after('# slogan:')->trim()->value();
} else {
$slogan = str($file)->headline()->value();
}
$logo = collect(preg_grep('/^# logo:/', explode("\n", $content)))->values();
if ($logo->count() > 0) {
$logo = str($logo[0])->after('# logo:')->trim()->value();
} else {
$logo = 'svgs/coolify.png';
}
$minversion = collect(preg_grep('/^# minversion:/', explode("\n", $content)))->values();
if ($minversion->count() > 0) {
$minversion = str($minversion[0])->after('# minversion:')->trim()->value();
} else {
$minversion = '0.0.0';
}
$env_file = collect(preg_grep('/^# env_file:/', explode("\n", $content)))->values();
if ($env_file->count() > 0) {
$env_file = str($env_file[0])->after('# env_file:')->trim()->value();
} else {
$env_file = null;
}
$documentation = $data->get('documentation');
$documentation = $documentation ? $documentation.'?utm_source=coolify.io' : 'https://coolify.io/docs';
$tags = collect(preg_grep('/^# tags:/', explode("\n", $content)))->values();
if ($tags->count() > 0) {
$tags = str($tags[0])->after('# tags:')->trim()->explode(',')->map(function ($tag) {
return str($tag)->trim()->lower()->value();
})->values();
} else {
$tags = null;
}
$port = collect(preg_grep('/^# port:/', explode("\n", $content)))->values();
if ($port->count() > 0) {
$port = str($port[0])->after('# port:')->trim()->value();
} else {
$port = null;
}
$json = Yaml::parse($content);
$yaml = base64_encode(Yaml::dump($json, 10, 2));
$compose = base64_encode(Yaml::dump($json, 10, 2));
$tags = str($data->get('tags'))->lower()->explode(',')->map(fn ($tag) => trim($tag))->filter();
$tags = $tags->isEmpty() ? null : $tags->all();
$payload = [
'name' => $serviceName,
'name' => pathinfo($file, PATHINFO_FILENAME),
'documentation' => $documentation,
'slogan' => $slogan,
'compose' => $yaml,
'slogan' => $data->get('slogan', str($file)->headline()),
'compose' => $compose,
'tags' => $tags,
'logo' => $logo,
'minversion' => $minversion,
'logo' => $data->get('logo', 'svgs/coolify.png'),
'minversion' => $data->get('minversion', '0.0.0'),
];
if ($port) {
if ($port = $data->get('port')) {
$payload['port'] = $port;
}
if ($env_file) {
$env_file_content = file_get_contents(base_path("templates/compose/$env_file"));
$env_file_base64 = base64_encode($env_file_content);
$payload['envs'] = $env_file_base64;
if ($envFile = $data->get('env_file')) {
$envFileContent = file_get_contents(base_path("templates/compose/$envFile"));
$payload['envs'] = base64_encode($envFileContent);
}
return $payload;

View File

@@ -12,6 +12,7 @@ use App\Jobs\DockerCleanupJob;
use App\Jobs\PullTemplatesFromCDN;
use App\Jobs\ScheduledTaskJob;
use App\Jobs\ServerCheckJob;
use App\Jobs\ServerCleanupMux;
use App\Jobs\UpdateCoolifyJob;
use App\Models\ScheduledDatabaseBackup;
use App\Models\ScheduledTask;
@@ -120,6 +121,8 @@ class Kernel extends ConsoleKernel
} else {
$schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->timezone($serverTimezone)->onOneServer();
}
// Cleanup multiplexed connections every hour
$schedule->job(new ServerCleanupMux($server))->hourly()->onOneServer();
// Temporary solution until we have better memory management for Sentinel
if ($server->isSentinelEnabled()) {

View File

@@ -1213,7 +1213,6 @@ class ApplicationsController extends Controller
}
return response()->json(['message' => 'Invalid type.'], 400);
}
#[OA\Get(
@@ -1692,9 +1691,8 @@ class ApplicationsController extends Controller
'standalone_postgresql_id',
'standalone_redis_id',
]);
$env = $this->removeSensitiveData($env);
return $env;
return $this->removeSensitiveData($env);
});
return response()->json($envs);
@@ -1869,18 +1867,15 @@ class ApplicationsController extends Controller
return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
} else {
return response()->json([
'message' => 'Environment variable not found.',
], 404);
}
}
return response()->json([
'message' => 'Something is not okay. Are you okay?',
], 500);
}
#[OA\Patch(
@@ -2225,14 +2220,12 @@ class ApplicationsController extends Controller
return response()->json([
'uuid' => $env->uuid,
])->setStatusCode(201);
}
}
return response()->json([
'message' => 'Something went wrong.',
], 500);
}
#[OA\Delete(
@@ -2580,7 +2573,6 @@ class ApplicationsController extends Controller
'deployment_uuid' => $deployment_uuid->toString(),
],
);
}
#[OA\Post(
@@ -2746,7 +2738,6 @@ class ApplicationsController extends Controller
'custom_labels' => 'The custom_labels should be base64 encoded.',
],
], 422);
}
}
if ($request->has('domains') && $server->isProxyShouldRun()) {

View File

@@ -471,7 +471,6 @@ class DatabasesController extends Controller
$request->offsetSet('mysql_conf', $mysqlConf);
}
break;
}
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
if ($validator->fails() || ! empty($extraFields)) {
@@ -506,7 +505,6 @@ class DatabasesController extends Controller
return response()->json([
'message' => 'Database updated.',
]);
}
#[OA\Post(
@@ -1165,7 +1163,6 @@ class DatabasesController extends Controller
}
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
} elseif ($type === NewDatabaseTypes::MARIADB) {
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database'];
$validator = customApiValidator($request->all(), [
@@ -1826,6 +1823,5 @@ class DatabasesController extends Controller
],
200
);
}
}

View File

@@ -356,7 +356,6 @@ class ProjectController extends Controller
'name' => $project->name,
'description' => $project->description,
])->setStatusCode(201);
}
#[OA\Delete(

View File

@@ -566,9 +566,8 @@ class ServicesController extends Controller
'standalone_postgresql_id',
'standalone_redis_id',
]);
$env = $this->removeSensitiveData($env);
return $env;
return $this->removeSensitiveData($env);
});
return response()->json($envs);
@@ -1238,6 +1237,5 @@ class ServicesController extends Controller
],
200
);
}
}

View File

@@ -5,7 +5,6 @@ namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Storage;
use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException;
use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;

View File

@@ -174,7 +174,6 @@ class Gitea extends Controller
'pull_request_html_url' => $pull_request_html_url,
]);
}
}
queue_application_deployment(
application: $application,

View File

@@ -13,7 +13,6 @@ use App\Models\Webhook;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Sleep;
use Illuminate\Support\Str;
class Stripe extends Controller
@@ -64,22 +63,18 @@ class Stripe extends Controller
$piData = $stripe->paymentIntents->retrieve($pi, []);
$customerId = data_get($piData, 'customer');
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
if (! $subscription) {
Sleep::for(5)->seconds();
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
}
if (! $subscription) {
Sleep::for(5)->seconds();
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
}
if ($subscription) {
$subscriptionId = data_get($subscription, 'stripe_subscription_id');
$stripe->subscriptions->cancel($subscriptionId, []);
$subscription->update([
'stripe_invoice_paid' => false,
]);
}
send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}");
} else {
send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}");
return response("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}", 400);
}
break;
case 'checkout.session.completed':
$clientReferenceId = data_get($data, 'client_reference_id');
@@ -95,7 +90,8 @@ class Stripe extends Controller
$found = $team->members->where('id', $userId)->first();
if (! $found->isAdmin()) {
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
throw new Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.");
return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.", 400);
}
$subscription = Subscription::where('team_id', $teamId)->first();
if ($subscription) {
@@ -123,13 +119,13 @@ class Stripe extends Controller
break;
}
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
if (! $subscription) {
Sleep::for(5)->seconds();
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
}
if ($subscription) {
$subscription->update([
'stripe_invoice_paid' => true,
]);
} else {
return response("No subscription found for customer: {$customerId}", 400);
}
break;
case 'invoice.payment_failed':
$customerId = data_get($data, 'customer');
@@ -167,7 +163,42 @@ class Stripe extends Controller
}
send_internal_notification('Subscription payment failed for customer: '.$customerId);
break;
case 'customer.subscription.created':
$customerId = data_get($data, 'customer');
$subscriptionId = data_get($data, 'id');
$teamId = data_get($data, 'metadata.team_id');
$userId = data_get($data, 'metadata.user_id');
if (! $teamId || ! $userId) {
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
if ($subscription) {
return response("Subscription already exists for customer: {$customerId}", 200);
}
return response('No team id or user id found', 400);
}
$team = Team::find($teamId);
$found = $team->members->where('id', $userId)->first();
if (! $found->isAdmin()) {
send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.");
return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.", 400);
}
$subscription = Subscription::where('team_id', $teamId)->first();
if ($subscription) {
return response("Subscription already exists for team: {$teamId}", 200);
} else {
Subscription::create([
'team_id' => $teamId,
'stripe_subscription_id' => $subscriptionId,
'stripe_customer_id' => $customerId,
'stripe_invoice_paid' => false,
]);
return response('Subscription created');
}
case 'customer.subscription.updated':
$teamId = data_get($data, 'metadata.team_id');
$userId = data_get($data, 'metadata.user_id');
$customerId = data_get($data, 'customer');
$status = data_get($data, 'status');
$subscriptionId = data_get($data, 'items.data.0.subscription');
@@ -177,32 +208,27 @@ class Stripe extends Controller
break;
}
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
if (! $subscription) {
Sleep::for(5)->seconds();
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
}
if (! $subscription) {
if ($status === 'incomplete_expired') {
// send_internal_notification('Subscription incomplete expired for customer: '.$customerId);
return response('Subscription incomplete expired', 200);
}
// send_internal_notification('No subscription found for: '.$customerId);
return response('No subscription found', 400);
if ($teamId) {
$subscription = Subscription::create([
'team_id' => $teamId,
'stripe_subscription_id' => $subscriptionId,
'stripe_customer_id' => $customerId,
'stripe_invoice_paid' => false,
]);
} else {
return response('No subscription and team id found', 400);
}
}
$trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended');
$cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end');
$alreadyCancelAtPeriodEnd = data_get($subscription, 'stripe_cancel_at_period_end');
$feedback = data_get($data, 'cancellation_details.feedback');
$comment = data_get($data, 'cancellation_details.comment');
$lookup_key = data_get($data, 'items.data.0.price.lookup_key');
if (str($lookup_key)->contains('ultimate') || str($lookup_key)->contains('dynamic')) {
if (str($lookup_key)->contains('dynamic')) {
$quantity = data_get($data, 'items.data.0.quantity', 2);
} else {
$quantity = data_get($data, 'items.data.0.quantity', 10);
}
$team = data_get($subscription, 'team');
if ($team) {
$team->update([
@@ -221,28 +247,12 @@ class Stripe extends Controller
$subscription->update([
'stripe_invoice_paid' => false,
]);
// send_internal_notification('Subscription paused or incomplete for customer: '.$customerId);
}
// Trial ended but subscribed, reactive servers
if ($trialEndedAlready && $status === 'active') {
$team = data_get($subscription, 'team');
$team->trialEndedButSubscribed();
}
if ($feedback) {
$reason = "Cancellation feedback for {$customerId}: '".$feedback."'";
if ($comment) {
$reason .= ' with comment: \''.$comment."'";
}
// send_internal_notification($reason);
}
if ($alreadyCancelAtPeriodEnd !== $cancelAtPeriodEnd) {
if ($cancelAtPeriodEnd) {
// send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id);
} else {
// send_internal_notification('customer.subscription.updated for customer: '.$customerId);
}
}
break;
case 'customer.subscription.deleted':
@@ -268,7 +278,7 @@ class Stripe extends Controller
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
$team = data_get($subscription, 'team');
if (! $team) {
throw new Exception('No team found for subscription: '.$subscription->id);
return response('No team found for subscription: '.$subscription->id, 400);
}
SubscriptionTrialEndsSoonJob::dispatch($team);
break;
@@ -277,7 +287,7 @@ class Stripe extends Controller
$subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail();
$team = data_get($subscription, 'team');
if (! $team) {
throw new Exception('No team found for subscription: '.$subscription->id);
return response('No team found for subscription: '.$subscription->id, 400);
}
$team->trialEnded();
$subscription->update([

View File

@@ -31,7 +31,6 @@ class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue
$settings->update(['helper_version' => $latest_version]);
}
}
} catch (\Throwable $e) {
send_internal_notification('CheckHelperImageJob failed with: '.$e->getMessage());
throw $e;

View File

@@ -129,7 +129,6 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
if ($this->postgres_password) {
$this->postgres_password = str($this->postgres_password)->after('POSTGRES_PASSWORD=')->value();
}
} elseif (str($databaseType)->contains('mysql')) {
$this->container_name = "{$this->database->name}-$serviceUuid";
$this->directory_name = $serviceName.'-'.$this->container_name;

View File

@@ -6,7 +6,7 @@ use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy;
use App\Actions\Server\InstallLogDrain;
use App\Actions\Server\StartLogDrain;
use App\Actions\Shared\ComplexStatusCheck;
use App\Models\Application;
use App\Models\ApplicationPreview;
@@ -167,7 +167,6 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
$this->foundServiceDatabaseIds->push($subId);
$this->updateServiceSubStatus($serviceId, $subType, $subId, $containerStatus);
}
} else {
$uuid = $labels->get('com.docker.compose.service');
$type = $labels->get('coolify.type');
@@ -265,7 +264,6 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
}
}
}
private function updateDatabaseStatus(string $databaseUuid, string $containerStatus, bool $tcpProxy = false)
@@ -362,7 +360,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
private function checkLogDrainContainer()
{
if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) {
InstallLogDrain::dispatch($this->server);
StartLogDrain::dispatch($this->server);
}
}
}

View File

@@ -54,13 +54,9 @@ class ScheduledTaskJob implements ShouldQueue
private function getServerTimezone(): string
{
if ($this->resource instanceof Application) {
$timezone = $this->resource->destination->server->settings->server_timezone;
return $timezone;
return $this->resource->destination->server->settings->server_timezone;
} elseif ($this->resource instanceof Service) {
$timezone = $this->resource->server->settings->server_timezone;
return $timezone;
return $this->resource->server->settings->server_timezone;
}
return 'UTC';
@@ -68,7 +64,6 @@ class ScheduledTaskJob implements ShouldQueue
public function handle(): void
{
try {
$this->task_log = ScheduledTaskExecution::create([
'scheduled_task_id' => $this->task->id,
@@ -76,14 +71,14 @@ class ScheduledTaskJob implements ShouldQueue
$this->server = $this->resource->destination->server;
if ($this->resource->type() == 'application') {
if ($this->resource->type() === 'application') {
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id, 0);
if ($containers->count() > 0) {
$containers->each(function ($container) {
$this->containers[] = str_replace('/', '', $container['Names']);
});
}
} elseif ($this->resource->type() == 'service') {
} elseif ($this->resource->type() === 'service') {
$this->resource->applications()->get()->each(function ($application) {
if (str(data_get($application, 'status'))->contains('running')) {
$this->containers[] = data_get($application, 'name').'-'.data_get($this->resource, 'uuid');

View File

@@ -5,7 +5,7 @@ namespace App\Jobs;
use App\Actions\Docker\GetContainersStatus;
use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy;
use App\Actions\Server\InstallLogDrain;
use App\Actions\Server\StartLogDrain;
use App\Models\Server;
use App\Notifications\Container\ContainerRestarted;
use Illuminate\Bus\Queueable;
@@ -94,11 +94,9 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
}
}
}
} catch (\Throwable $e) {
return handleError($e);
}
}
private function checkLogDrainContainer()
@@ -109,10 +107,10 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
if ($foundLogDrainContainer) {
$status = data_get($foundLogDrainContainer, 'State.Status');
if ($status !== 'running') {
InstallLogDrain::dispatch($this->server);
StartLogDrain::dispatch($this->server);
}
} else {
InstallLogDrain::dispatch($this->server);
StartLogDrain::dispatch($this->server);
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Jobs;
use App\Helpers\SshMultiplexingHelper;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ServerCleanupMux implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public $timeout = 60;
public function backoff(): int
{
return isDev() ? 1 : 3;
}
public function __construct(public Server $server) {}
public function handle()
{
try {
if ($this->server->serverStatus() === false) {
return 'Server is not reachable or not ready.';
}
SshMultiplexingHelper::removeMuxFile($this->server);
} catch (\Throwable $e) {
return handleError($e);
}
}
}

View File

@@ -38,7 +38,6 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue
if (is_null($this->percentage)) {
$this->percentage = $this->server->storageCheck();
loggy('Server storage check percentage: '.$this->percentage);
}
if (! $this->percentage) {
return 'No percentage could be retrieved.';
@@ -59,10 +58,8 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue
} else {
RateLimiter::hit('high-disk-usage:'.$this->server->id, 600);
}
} catch (\Throwable $e) {
return handleError($e);
}
}
}

View File

@@ -41,7 +41,6 @@ class UpdateCoolifyJob implements ShouldBeEncrypted, ShouldQueue
$settings->update(['new_version_available' => false]);
Log::info('Coolify update completed successfully.');
} catch (\Throwable $e) {
Log::error('UpdateCoolifyJob failed: '.$e->getMessage());
// Consider implementing a notification to administrators

View File

@@ -2,7 +2,6 @@
namespace App\Livewire;
use App\Enums\ProcessStatus;
use App\Models\User;
use Livewire\Component;
use Spatie\Activitylog\Models\Activity;

View File

@@ -34,7 +34,7 @@ class Discord extends Component
{
try {
$this->submit();
} catch (\Throwable $e) {
} catch (\Throwable) {
$this->team->discord_enabled = false;
$this->validate();
}

View File

@@ -41,7 +41,7 @@ class Telegram extends Component
{
try {
$this->submit();
} catch (\Throwable $e) {
} catch (\Throwable) {
$this->team->telegram_enabled = false;
$this->validate();
}

View File

@@ -64,7 +64,7 @@ class Show extends Component
{
$this->dispatch('deploymentFinished');
$this->application_deployment_queue->refresh();
if (data_get($this->application_deployment_queue, 'status') == 'finished' || data_get($this->application_deployment_queue, 'status') == 'failed') {
if (data_get($this->application_deployment_queue, 'status') === 'finished' || data_get($this->application_deployment_queue, 'status') === 'failed') {
$this->isKeepAliveOn = false;
}
}

View File

@@ -36,7 +36,7 @@ class Form extends Component
$url = Url::fromString($firstFqdn);
$host = $url->getHost();
$this->preview_url_template = str($this->application->preview_url_template)->replace('{{domain}}', $host);
} catch (\Exception $e) {
} catch (\Exception) {
$this->dispatch('error', 'Invalid FQDN.');
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Livewire\Project\Application;
use App\Actions\Docker\GetContainersStatus;
use App\Models\Application;
use App\Models\ApplicationPreview;
use Carbon\Carbon;
use Illuminate\Process\InvokedProcess;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Process;
@@ -239,7 +240,7 @@ class Previews extends Component
$processes[$containerName] = $this->stopContainer($containerName, $timeout);
}
$startTime = time();
$startTime = Carbon::now()->getTimestamp();
while (count($processes) > 0) {
$finishedProcesses = array_filter($processes, function ($process) {
return ! $process->running();
@@ -249,7 +250,7 @@ class Previews extends Component
$this->removeContainer($containerName, $server);
}
if (time() - $startTime >= $timeout) {
if (Carbon::now()->getTimestamp() - $startTime >= $timeout) {
$this->forceStopRemainingContainers(array_keys($processes), $server);
break;
}

View File

@@ -121,7 +121,7 @@ class BackupEdit extends Component
{
try {
$this->custom_validate();
if ($this->backup->databases_to_backup == '' || $this->backup->databases_to_backup === null) {
if ($this->backup->databases_to_backup === '' || $this->backup->databases_to_backup === null) {
$this->backup->databases_to_backup = null;
}
$this->backup->save();

View File

@@ -119,9 +119,8 @@ class BackupExecutions extends Component
if (! $server) {
return 'UTC';
}
$serverTimezone = $server->settings->server_timezone;
return $serverTimezone;
return $server->settings->server_timezone;
}
public function formatDateInServerTimezone($date)
@@ -130,7 +129,7 @@ class BackupExecutions extends Component
$dateObj = new \DateTime($date);
try {
$dateObj->setTimezone(new \DateTimeZone($serverTimezone));
} catch (\Exception $e) {
} catch (\Exception) {
$dateObj->setTimezone(new \DateTimeZone('UTC'));
}

View File

@@ -77,10 +77,10 @@ class Import extends Component
}
if (
$this->resource->getMorphClass() == \App\Models\StandaloneRedis::class ||
$this->resource->getMorphClass() == \App\Models\StandaloneKeydb::class ||
$this->resource->getMorphClass() == \App\Models\StandaloneDragonfly::class ||
$this->resource->getMorphClass() == \App\Models\StandaloneClickhouse::class
$this->resource->getMorphClass() === \App\Models\StandaloneRedis::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneKeydb::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneDragonfly::class ||
$this->resource->getMorphClass() === \App\Models\StandaloneClickhouse::class
) {
$this->unsupported = true;
}
@@ -88,8 +88,7 @@ class Import extends Component
public function runImport()
{
if ($this->filename == '') {
if ($this->filename === '') {
$this->dispatch('error', 'Please select a file to import.');
return;

View File

@@ -51,7 +51,6 @@ class General extends Component
$this->db_url = $this->database->internal_db_url;
$this->db_url_public = $this->database->external_db_url;
$this->server = data_get($this->database, 'destination.server');
}
public function instantSaveAdvanced()

View File

@@ -57,7 +57,6 @@ class General extends Component
$this->db_url = $this->database->internal_db_url;
$this->db_url_public = $this->database->external_db_url;
$this->server = data_get($this->database, 'destination.server');
}
public function instantSaveAdvanced()

View File

@@ -55,7 +55,6 @@ class General extends Component
$this->db_url = $this->database->internal_db_url;
$this->db_url_public = $this->database->external_db_url;
$this->server = data_get($this->database, 'destination.server');
}
public function instantSaveAdvanced()

View File

@@ -198,7 +198,7 @@ class GithubPrivateRepositoryDeployKey extends Component
$this->git_host = $this->repository_url_parsed->getHost();
$this->git_repository = $this->repository_url_parsed->getSegment(1).'/'.$this->repository_url_parsed->getSegment(2);
if ($this->git_host == 'github.com') {
if ($this->git_host === 'github.com') {
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
return;

View File

@@ -99,7 +99,6 @@ class PublicGitRepository extends Component
$this->base_directory = '/'.$this->base_directory;
}
}
}
public function updatedDockerComposeLocation()
@@ -174,7 +173,7 @@ class PublicGitRepository extends Component
return;
}
if (! $this->branchFound && $this->git_branch == 'main') {
if (! $this->branchFound && $this->git_branch === 'main') {
try {
$this->git_branch = 'master';
$this->getBranch();
@@ -197,7 +196,7 @@ class PublicGitRepository extends Component
} else {
$this->git_branch = 'main';
}
if ($this->git_host == 'github.com') {
if ($this->git_host === 'github.com') {
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
return;

View File

@@ -100,7 +100,6 @@ class Create extends Component
'is_preview' => false,
]);
}
});
}
$service->parse(isNew: true);

View File

@@ -95,7 +95,7 @@ class Database extends Component
$this->database->save();
updateCompose($this->database);
$this->dispatch('success', 'Database saved.');
} catch (\Throwable $e) {
} catch (\Throwable) {
} finally {
$this->dispatch('generateDockerCompose');
}

View File

@@ -48,7 +48,6 @@ class Index extends Component
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function generateDockerCompose()

View File

@@ -76,7 +76,7 @@ class Navbar extends Component
} else {
$this->isDeploymentProgress = false;
}
} catch (\Throwable $e) {
} catch (\Throwable) {
$this->isDeploymentProgress = false;
}
}

View File

@@ -62,32 +62,21 @@ class Danger extends Component
return;
}
switch ($this->resource->type()) {
case 'application':
$this->resourceName = $this->resource->name ?? 'Application';
break;
case 'standalone-postgresql':
case 'standalone-redis':
case 'standalone-mongodb':
case 'standalone-mysql':
case 'standalone-mariadb':
case 'standalone-keydb':
case 'standalone-dragonfly':
case 'standalone-clickhouse':
$this->resourceName = $this->resource->name ?? 'Database';
break;
case 'service':
$this->resourceName = $this->resource->name ?? 'Service';
break;
case 'service-application':
$this->resourceName = $this->resource->name ?? 'Service Application';
break;
case 'service-database':
$this->resourceName = $this->resource->name ?? 'Service Database';
break;
default:
$this->resourceName = 'Unknown Resource';
}
$this->resourceName = match ($this->resource->type()) {
'application' => $this->resource->name ?? 'Application',
'standalone-postgresql',
'standalone-redis',
'standalone-mongodb',
'standalone-mysql',
'standalone-mariadb',
'standalone-keydb',
'standalone-dragonfly',
'standalone-clickhouse' => $this->resource->name ?? 'Database',
'service' => $this->resource->name ?? 'Service',
'service-application' => $this->resource->name ?? 'Service Application',
'service-database' => $this->resource->name ?? 'Service Database',
default => 'Unknown Resource',
};
}
public function delete($password)

View File

@@ -132,7 +132,6 @@ class ExecuteContainerCommand extends Component
}
});
}
}
if ($this->containers->count() > 0) {
$this->container = $this->containers->first();
@@ -155,7 +154,6 @@ class ExecuteContainerCommand extends Component
data_get($this->server, 'name'),
data_get($this->server, 'uuid')
);
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -185,7 +183,6 @@ class ExecuteContainerCommand extends Component
data_get($container, 'container.Names'),
data_get($container, 'server.uuid')
);
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -109,9 +109,7 @@ class Logs extends Component
$this->containers = $this->containers->filter(function ($container) {
return str_contains($container, $this->query['pull_request_id']);
});
}
} catch (\Exception $e) {
return handleError($e, $this);
}

View File

@@ -147,7 +147,6 @@ class ResourceOperations extends Component
return redirect()->to($route);
}
}
public function moveTo($environment_id)

View File

@@ -55,8 +55,8 @@ class Add extends Component
return;
}
if (empty($this->container) || $this->container == 'null') {
if ($this->type == 'service') {
if (empty($this->container) || $this->container === 'null') {
if ($this->type === 'service') {
$this->container = $this->subServiceName;
}
}

View File

@@ -21,10 +21,10 @@ class All extends Component
public function mount()
{
$this->parameters = get_route_parameters();
if ($this->resource->type() == 'service') {
if ($this->resource->type() === 'service') {
$this->containerNames = $this->resource->applications()->pluck('name');
$this->containerNames = $this->containerNames->merge($this->resource->databases()->pluck('name'));
} elseif ($this->resource->type() == 'application') {
} elseif ($this->resource->type() === 'application') {
if ($this->resource->build_pack === 'dockercompose') {
$parsed = $this->resource->parse();
$containers = collect(data_get($parsed, 'services'))->keys();

View File

@@ -54,9 +54,8 @@ class Executions extends Component
if (! $server) {
return 'UTC';
}
$serverTimezone = $server->settings->server_timezone;
return $serverTimezone;
return $server->settings->server_timezone;
}
public function formatDateInServerTimezone($date)
@@ -65,7 +64,7 @@ class Executions extends Component
$dateObj = new \DateTime($date);
try {
$dateObj->setTimezone(new \DateTimeZone($serverTimezone));
} catch (\Exception $e) {
} catch (\Exception) {
$dateObj->setTimezone(new \DateTimeZone('UTC'));
}

View File

@@ -77,7 +77,7 @@ class Show extends Component
try {
$this->task->delete();
if ($this->type == 'application') {
if ($this->type === 'application') {
return redirect()->route('project.application.configuration', $this->parameters, $this->scheduledTaskName);
} else {
return redirect()->route('project.service.configuration', $this->parameters, $this->scheduledTaskName);

View File

@@ -100,7 +100,6 @@ class Add extends Component
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submitFileStorageDirectory()
@@ -127,7 +126,6 @@ class Add extends Component
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submitPersistentVolume()
@@ -144,7 +142,6 @@ class Add extends Component
'mount_path' => $this->mount_path,
'host_path' => $this->host_path,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -26,7 +26,6 @@ class Terminal extends Component
#[On('send-terminal-command')]
public function sendTerminalCommand($isContainer, $identifier, $serverUuid)
{
$server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->firstOrFail();
if ($isContainer) {

View File

@@ -37,7 +37,6 @@ class UploadConfig extends Component
return;
}
}
public function render()

View File

@@ -28,7 +28,7 @@ class Show extends Component
{
try {
$this->private_key = PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail();
} catch (\Throwable $e) {
} catch (\Throwable) {
abort(404);
}
}

View File

@@ -4,45 +4,82 @@ namespace App\Livewire\Server;
use App\Jobs\DockerCleanupJob;
use App\Models\Server;
use Livewire\Attributes\Rule;
use Livewire\Component;
class Advanced extends Component
{
public Server $server;
protected $rules = [
'server.settings.concurrent_builds' => 'required|integer|min:1',
'server.settings.dynamic_timeout' => 'required|integer|min:1',
'server.settings.force_docker_cleanup' => 'required|boolean',
'server.settings.docker_cleanup_frequency' => 'required_if:server.settings.force_docker_cleanup,true|string',
'server.settings.docker_cleanup_threshold' => 'required_if:server.settings.force_docker_cleanup,false|integer|min:1|max:100',
'server.settings.server_disk_usage_notification_threshold' => 'required|integer|min:50|max:100',
'server.settings.delete_unused_volumes' => 'boolean',
'server.settings.delete_unused_networks' => 'boolean',
];
public array $parameters = [];
protected $validationAttributes = [
#[Rule(['integer', 'min:1'])]
public int $concurrentBuilds = 1;
'server.settings.concurrent_builds' => 'Concurrent Builds',
'server.settings.dynamic_timeout' => 'Dynamic Timeout',
'server.settings.force_docker_cleanup' => 'Force Docker Cleanup',
'server.settings.docker_cleanup_frequency' => 'Docker Cleanup Frequency',
'server.settings.docker_cleanup_threshold' => 'Docker Cleanup Threshold',
'server.settings.server_disk_usage_notification_threshold' => 'Server Disk Usage Notification Threshold',
'server.settings.delete_unused_volumes' => 'Delete Unused Volumes',
'server.settings.delete_unused_networks' => 'Delete Unused Networks',
];
#[Rule(['integer', 'min:1'])]
public int $dynamicTimeout = 1;
#[Rule('boolean')]
public bool $forceDockerCleanup = false;
#[Rule('string')]
public string $dockerCleanupFrequency = '*/10 * * * *';
#[Rule(['integer', 'min:1', 'max:99'])]
public int $dockerCleanupThreshold = 10;
#[Rule(['integer', 'min:1', 'max:99'])]
public int $serverDiskUsageNotificationThreshold = 50;
#[Rule('boolean')]
public bool $deleteUnusedVolumes = false;
#[Rule('boolean')]
public bool $deleteUnusedNetworks = false;
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->parameters = get_route_parameters();
$this->syncData();
} catch (\Throwable) {
return redirect()->route('server.show');
}
}
public function syncData(bool $toModel = false)
{
if ($toModel) {
$this->validate();
$this->server->settings->concurrent_builds = $this->concurrentBuilds;
$this->server->settings->dynamic_timeout = $this->dynamicTimeout;
$this->server->settings->force_docker_cleanup = $this->forceDockerCleanup;
$this->server->settings->docker_cleanup_frequency = $this->dockerCleanupFrequency;
$this->server->settings->docker_cleanup_threshold = $this->dockerCleanupThreshold;
$this->server->settings->server_disk_usage_notification_threshold = $this->serverDiskUsageNotificationThreshold;
$this->server->settings->delete_unused_volumes = $this->deleteUnusedVolumes;
$this->server->settings->delete_unused_networks = $this->deleteUnusedNetworks;
$this->server->settings->save();
} else {
$this->concurrentBuilds = $this->server->settings->concurrent_builds;
$this->dynamicTimeout = $this->server->settings->dynamic_timeout;
$this->forceDockerCleanup = $this->server->settings->force_docker_cleanup;
$this->dockerCleanupFrequency = $this->server->settings->docker_cleanup_frequency;
$this->dockerCleanupThreshold = $this->server->settings->docker_cleanup_threshold;
$this->serverDiskUsageNotificationThreshold = $this->server->settings->server_disk_usage_notification_threshold;
$this->deleteUnusedVolumes = $this->server->settings->delete_unused_volumes;
$this->deleteUnusedNetworks = $this->server->settings->delete_unused_networks;
}
}
public function instantSave()
{
try {
$this->validate();
$this->server->settings->save();
$this->syncData(true);
$this->dispatch('success', 'Server updated.');
$this->dispatch('refreshServerShow');
// $this->dispatch('refreshServerShow');
} catch (\Throwable $e) {
$this->server->settings->refresh();
return handleError($e, $this);
}
}
@@ -60,12 +97,11 @@ class Advanced extends Component
public function submit()
{
try {
$frequency = $this->server->settings->docker_cleanup_frequency;
if (empty($frequency) || ! validate_cron_expression($frequency)) {
$this->server->settings->docker_cleanup_frequency = '*/10 * * * *';
throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency. Resetting to default 10 minutes.');
if (! validate_cron_expression($this->dockerCleanupFrequency)) {
$this->dockerCleanupFrequency = $this->server->settings->getOriginal('docker_cleanup_frequency');
throw new \Exception('Invalid Cron / Human expression for Docker Cleanup Frequency.');
}
$this->server->settings->save();
$this->syncData(true);
$this->dispatch('success', 'Server updated.');
} catch (\Throwable $e) {
return handleError($e, $this);

View File

@@ -19,6 +19,15 @@ class Charts extends Component
public bool $poll = true;
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function pollData()
{
if ($this->poll || $this->interval <= 10) {
@@ -40,7 +49,6 @@ class Charts extends Component
$this->dispatch("refreshChartData-{$this->chartId}-memory", [
'seriesData' => $memoryMetrics,
]);
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -3,27 +3,33 @@
namespace App\Livewire\Server;
use App\Models\Server;
use Livewire\Attributes\Rule;
use Livewire\Component;
class CloudflareTunnels extends Component
{
public Server $server;
protected $rules = [
'server.settings.is_cloudflare_tunnel' => 'required|boolean',
];
#[Rule(['required', 'boolean'])]
public bool $isCloudflareTunnelsEnabled;
protected $validationAttributes = [
'server.settings.is_cloudflare_tunnel' => 'Cloudflare Tunnel',
];
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->isCloudflareTunnelsEnabled = $this->server->settings->is_cloudflare_tunnel;
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
try {
$this->validate();
$this->server->settings->is_cloudflare_tunnel = $this->isCloudflareTunnelsEnabled;
$this->server->settings->save();
$this->dispatch('success', 'Server updated.');
$this->dispatch('refreshServerShow');
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -31,6 +37,7 @@ class CloudflareTunnels extends Component
public function manualCloudflareConfig()
{
$this->isCloudflareTunnelsEnabled = true;
$this->server->settings->is_cloudflare_tunnel = true;
$this->server->settings->save();
$this->server->refresh();

View File

@@ -4,6 +4,7 @@ namespace App\Livewire\Server;
use App\Actions\Server\DeleteServer;
use App\Models\InstanceSettings;
use App\Models\Server;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
@@ -13,7 +14,16 @@ class Delete extends Component
{
use AuthorizesRequests;
public $server;
public Server $server;
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function delete($password)
{

View File

@@ -3,27 +3,87 @@
namespace App\Livewire\Server\Destination;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Illuminate\Support\Collection;
use Livewire\Component;
class Show extends Component
{
public ?Server $server = null;
public Server $server;
public $parameters = [];
public Collection $networks;
public function mount()
public function mount(string $server_uuid)
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.index');
}
$this->networks = collect();
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
loggy($this->server);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
private function createNetworkAndAttachToProxy()
{
$connectProxyToDockerNetworks = connectProxyToNetworks($this->server);
instant_remote_process($connectProxyToDockerNetworks, $this->server, false);
}
public function add($name)
{
if ($this->server->isSwarm()) {
$found = $this->server->swarmDockers()->where('network', $name)->first();
if ($found) {
$this->dispatch('error', 'Network already added to this server.');
return;
} else {
SwarmDocker::create([
'name' => $this->server->name.'-'.$name,
'network' => $this->name,
'server_id' => $this->server->id,
]);
}
} else {
$found = $this->server->standaloneDockers()->where('network', $name)->first();
if ($found) {
$this->dispatch('error', 'Network already added to this server.');
return;
} else {
StandaloneDocker::create([
'name' => $this->server->name.'-'.$name,
'network' => $name,
'server_id' => $this->server->id,
]);
}
$this->createNetworkAndAttachToProxy();
}
}
public function scan()
{
if ($this->server->isSwarm()) {
$alreadyAddedNetworks = $this->server->swarmDockers;
} else {
$alreadyAddedNetworks = $this->server->standaloneDockers;
}
$networks = instant_remote_process(['docker network ls --format "{{json .}}"'], $this->server, false);
$this->networks = format_docker_command_output_to_json($networks)->filter(function ($network) {
return $network['Name'] !== 'bridge' && $network['Name'] !== 'host' && $network['Name'] !== 'none';
})->filter(function ($network) use ($alreadyAddedNetworks) {
return ! $alreadyAddedNetworks->contains('network', $network['Name']);
});
if ($this->networks->count() === 0) {
$this->dispatch('success', 'No new destinations found on this server.');
return;
}
$this->dispatch('success', 'Scan done.');
}
public function render()
{
return view('livewire.server.destination.show');

View File

@@ -86,7 +86,6 @@ class Form extends Component
$this->server = $server;
$this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray();
$this->wildcard_domain = $this->server->settings->wildcard_domain;
}
public function checkSyncStatus()
@@ -111,7 +110,7 @@ class Form extends Component
{
if ($field === 'server.settings.docker_cleanup_frequency') {
$frequency = $this->server->settings->docker_cleanup_frequency;
if (empty($frequency) || ! validate_cron_expression($frequency)) {
if (! validate_cron_expression($frequency)) {
$this->dispatch('error', 'Invalid Cron / Human expression for Docker Cleanup Frequency. Resetting to default 10 minutes.');
$this->server->settings->docker_cleanup_frequency = '*/10 * * * *';
}
@@ -169,7 +168,6 @@ class Form extends Component
public function instantSave()
{
try {
$this->validate();
refresh_server_connection($this->server->privateKey);
$this->validateServer(false);

View File

@@ -2,84 +2,94 @@
namespace App\Livewire\Server;
use App\Actions\Server\InstallLogDrain;
use App\Actions\Server\StartLogDrain;
use App\Actions\Server\StopLogDrain;
use App\Models\Server;
use Livewire\Attributes\Rule;
use Livewire\Component;
class LogDrains extends Component
{
public Server $server;
public $parameters = [];
#[Rule(['boolean'])]
public bool $isLogDrainNewRelicEnabled = false;
protected $rules = [
'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean',
'server.settings.logdrain_newrelic_license_key' => 'required|string',
'server.settings.logdrain_newrelic_base_uri' => 'required|string',
'server.settings.is_logdrain_highlight_enabled' => 'required|boolean',
'server.settings.logdrain_highlight_project_id' => 'required|string',
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
'server.settings.logdrain_axiom_api_key' => 'required|string',
'server.settings.is_logdrain_custom_enabled' => 'required|boolean',
'server.settings.logdrain_custom_config' => 'required|string',
'server.settings.logdrain_custom_config_parser' => 'nullable',
];
#[Rule(['boolean'])]
public bool $isLogDrainCustomEnabled = false;
protected $validationAttributes = [
'server.settings.is_logdrain_newrelic_enabled' => 'New Relic log drain',
'server.settings.logdrain_newrelic_license_key' => 'New Relic license key',
'server.settings.logdrain_newrelic_base_uri' => 'New Relic base URI',
'server.settings.is_logdrain_highlight_enabled' => 'Highlight log drain',
'server.settings.logdrain_highlight_project_id' => 'Highlight project ID',
'server.settings.is_logdrain_axiom_enabled' => 'Axiom log drain',
'server.settings.logdrain_axiom_dataset_name' => 'Axiom dataset name',
'server.settings.logdrain_axiom_api_key' => 'Axiom API key',
'server.settings.is_logdrain_custom_enabled' => 'Custom log drain',
'server.settings.logdrain_custom_config' => 'Custom log drain configuration',
'server.settings.logdrain_custom_config_parser' => 'Custom log drain configuration parser',
];
#[Rule(['boolean'])]
public bool $isLogDrainAxiomEnabled = false;
public function mount()
#[Rule(['string', 'nullable'])]
public ?string $logDrainNewRelicLicenseKey = null;
#[Rule(['url', 'nullable'])]
public ?string $logDrainNewRelicBaseUri = null;
#[Rule(['string', 'nullable'])]
public ?string $logDrainAxiomDatasetName = null;
#[Rule(['string', 'nullable'])]
public ?string $logDrainAxiomApiKey = null;
#[Rule(['string', 'nullable'])]
public ?string $logDrainCustomConfig = null;
#[Rule(['string', 'nullable'])]
public ?string $logDrainCustomConfigParser = null;
public function mount(string $server_uuid)
{
$this->parameters = get_route_parameters();
try {
$server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($server)) {
return redirect()->route('server.index');
}
$this->server = $server;
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->syncData();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function configureLogDrain()
public function syncData(bool $toModel = false)
{
if ($toModel) {
$this->validate();
$this->server->settings->is_logdrain_newrelic_enabled = $this->isLogDrainNewRelicEnabled;
$this->server->settings->is_logdrain_axiom_enabled = $this->isLogDrainAxiomEnabled;
$this->server->settings->is_logdrain_custom_enabled = $this->isLogDrainCustomEnabled;
$this->server->settings->logdrain_newrelic_license_key = $this->logDrainNewRelicLicenseKey;
$this->server->settings->logdrain_newrelic_base_uri = $this->logDrainNewRelicBaseUri;
$this->server->settings->logdrain_axiom_dataset_name = $this->logDrainAxiomDatasetName;
$this->server->settings->logdrain_axiom_api_key = $this->logDrainAxiomApiKey;
$this->server->settings->logdrain_custom_config = $this->logDrainCustomConfig;
$this->server->settings->logdrain_custom_config_parser = $this->logDrainCustomConfigParser;
$this->server->settings->save();
} else {
$this->isLogDrainNewRelicEnabled = $this->server->settings->is_logdrain_newrelic_enabled;
$this->isLogDrainAxiomEnabled = $this->server->settings->is_logdrain_axiom_enabled;
$this->isLogDrainCustomEnabled = $this->server->settings->is_logdrain_custom_enabled;
$this->logDrainNewRelicLicenseKey = $this->server->settings->logdrain_newrelic_license_key;
$this->logDrainNewRelicBaseUri = $this->server->settings->logdrain_newrelic_base_uri;
$this->logDrainAxiomDatasetName = $this->server->settings->logdrain_axiom_dataset_name;
$this->logDrainAxiomApiKey = $this->server->settings->logdrain_axiom_api_key;
$this->logDrainCustomConfig = $this->server->settings->logdrain_custom_config;
$this->logDrainCustomConfigParser = $this->server->settings->logdrain_custom_config_parser;
}
}
public function instantSave()
{
try {
InstallLogDrain::run($this->server);
if (! $this->server->isLogDrainEnabled()) {
$this->dispatch('serverRefresh');
$this->dispatch('success', 'Log drain service stopped.');
return;
}
$this->dispatch('serverRefresh');
$this->syncData(true);
if ($this->server->isLogDrainEnabled()) {
StartLogDrain::run($this->server);
$this->dispatch('success', 'Log drain service started.');
} catch (\Throwable $e) {
return handleError($e, $this);
} else {
StopLogDrain::run($this->server);
$this->dispatch('success', 'Log drain service stopped.');
}
}
public function instantSave(string $type)
{
try {
$ok = $this->submit($type);
if (! $ok) {
return;
}
$this->configureLogDrain();
} catch (\Throwable $e) {
return handleError($e, $this);
}
@@ -88,79 +98,10 @@ class LogDrains extends Component
public function submit(string $type)
{
try {
$this->resetErrorBag();
if ($type === 'newrelic') {
$this->validate([
'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean',
'server.settings.logdrain_newrelic_license_key' => 'required|string',
'server.settings.logdrain_newrelic_base_uri' => 'required|string',
]);
$this->server->settings->update([
'is_logdrain_highlight_enabled' => false,
'is_logdrain_axiom_enabled' => false,
'is_logdrain_custom_enabled' => false,
]);
} elseif ($type === 'highlight') {
$this->validate([
'server.settings.is_logdrain_highlight_enabled' => 'required|boolean',
'server.settings.logdrain_highlight_project_id' => 'required|string',
]);
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
'is_logdrain_axiom_enabled' => false,
'is_logdrain_custom_enabled' => false,
]);
} elseif ($type === 'axiom') {
$this->validate([
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
'server.settings.logdrain_axiom_api_key' => 'required|string',
]);
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
'is_logdrain_highlight_enabled' => false,
'is_logdrain_custom_enabled' => false,
]);
} elseif ($type === 'custom') {
$this->validate([
'server.settings.is_logdrain_custom_enabled' => 'required|boolean',
'server.settings.logdrain_custom_config' => 'required|string',
'server.settings.logdrain_custom_config_parser' => 'nullable',
]);
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
'is_logdrain_highlight_enabled' => false,
'is_logdrain_axiom_enabled' => false,
]);
}
if (! $this->server->isLogDrainEnabled()) {
StopLogDrain::dispatch($this->server);
}
$this->server->settings->save();
$this->syncData(true);
$this->dispatch('success', 'Settings saved.');
return true;
} catch (\Throwable $e) {
if ($type === 'newrelic') {
$this->server->settings->update([
'is_logdrain_newrelic_enabled' => false,
]);
} elseif ($type === 'highlight') {
$this->server->settings->update([
'is_logdrain_highlight_enabled' => false,
]);
} elseif ($type === 'axiom') {
$this->server->settings->update([
'is_logdrain_axiom_enabled' => false,
]);
} elseif ($type === 'custom') {
$this->server->settings->update([
'is_logdrain_custom_enabled' => false,
]);
}
handleError($e, $this);
return false;
return handleError($e, $this);
}
}

View File

@@ -8,26 +8,63 @@ use Livewire\Component;
class Show extends Component
{
public ?Server $server = null;
public Server $server;
public $privateKeys = [];
public $parameters = [];
public function mount()
public function mount(string $server_uuid)
{
$this->parameters = get_route_parameters();
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->first();
if (is_null($this->server)) {
return redirect()->route('server.index');
}
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function setPrivateKey($privateKeyId)
{
$ownedPrivateKey = PrivateKey::ownedByCurrentTeam()->find($privateKeyId);
if (is_null($ownedPrivateKey)) {
$this->dispatch('error', 'You are not allowed to use this private key.');
return;
}
$originalPrivateKeyId = $this->server->getOriginal('private_key_id');
try {
$this->server->update(['private_key_id' => $privateKeyId]);
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(justCheckingNewKey: true);
if ($uptime) {
$this->dispatch('success', 'Private key updated successfully.');
} else {
throw new \Exception($error);
}
} catch (\Exception $e) {
$this->server->update(['private_key_id' => $originalPrivateKeyId]);
$this->server->validateConnection();
$this->dispatch('error', $e->getMessage());
}
}
public function checkConnection()
{
try {
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
if ($uptime) {
$this->dispatch('success', 'Server is reachable.');
} else {
$this->dispatch('error', 'Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.$error);
return;
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()
{
return view('livewire.server.private-key.show');

View File

@@ -99,7 +99,6 @@ class Proxy extends Component
} else {
$this->dispatch('traefikDashboardAvailable', false);
}
} catch (\Throwable $e) {
return handleError($e, $this);
}

View File

@@ -6,6 +6,7 @@ use App\Actions\Proxy\CheckProxy;
use App\Actions\Proxy\StartProxy;
use App\Events\ProxyStatusChanged;
use App\Models\Server;
use Carbon\Carbon;
use Illuminate\Process\InvokedProcess;
use Illuminate\Support\Facades\Process;
use Livewire\Component;
@@ -102,9 +103,9 @@ class Deploy extends Component
$process = $this->stopContainer($containerName, $timeout);
$startTime = time();
$startTime = Carbon::now()->getTimestamp();
while ($process->running()) {
if (time() - $startTime >= $timeout) {
if (Carbon::now()->getTimestamp() - $startTime >= $timeout) {
$this->forceStopContainer($containerName);
break;
}

View File

@@ -3,38 +3,203 @@
namespace App\Livewire\Server;
use App\Models\Server;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Attributes\Rule;
use Livewire\Component;
class Show extends Component
{
use AuthorizesRequests;
public Server $server;
public array $parameters;
#[Rule(['required'])]
public string $name;
protected $listeners = ['refreshServerShow'];
#[Rule(['nullable'])]
public ?string $description;
public function mount()
#[Rule(['required'])]
public string $ip;
#[Rule(['required'])]
public string $user;
#[Rule(['required'])]
public string $port;
#[Rule(['nullable'])]
public ?string $validationLogs = null;
#[Rule(['nullable', 'url'])]
public ?string $wildcardDomain;
#[Rule(['required'])]
public bool $isReachable;
#[Rule(['required'])]
public bool $isUsable;
#[Rule(['required'])]
public bool $isSwarmManager;
#[Rule(['required'])]
public bool $isSwarmWorker;
#[Rule(['required'])]
public bool $isBuildServer;
#[Rule(['required'])]
public bool $isMetricsEnabled;
#[Rule(['required'])]
public string $sentinelToken;
#[Rule(['nullable'])]
public ?string $sentinelUpdatedAt;
#[Rule(['required', 'integer', 'min:1'])]
public int $sentinelMetricsRefreshRateSeconds;
#[Rule(['required', 'integer', 'min:1'])]
public int $sentinelMetricsHistoryDays;
#[Rule(['required', 'integer', 'min:10'])]
public int $sentinelPushIntervalSeconds;
#[Rule(['nullable', 'url'])]
public ?string $sentinelCustomUrl;
#[Rule(['required'])]
public bool $isSentinelEnabled;
#[Rule(['required'])]
public bool $isSentinelDebugEnabled;
#[Rule(['required'])]
public string $serverTimezone;
public array $timezones;
public function getListeners()
{
$teamId = auth()->user()->currentTeam()->id;
return [
"echo-private:team.{$teamId},CloudflareTunnelConfigured" => '$refresh',
'refreshServerShow' => '$refresh',
];
}
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid(request()->server_uuid)->firstOrFail();
$this->parameters = get_route_parameters();
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->timezones = collect(timezone_identifiers_list())->sort()->values()->toArray();
$this->syncData();
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function refreshServerShow()
public function syncData(bool $toModel = false)
{
$this->server->refresh();
$this->dispatch('$refresh');
if ($toModel) {
$this->validate();
$this->server->name = $this->name;
$this->server->description = $this->description;
$this->server->ip = $this->ip;
$this->server->user = $this->user;
$this->server->port = $this->port;
$this->server->validation_logs = $this->validationLogs;
$this->server->save();
$this->server->settings->is_swarm_manager = $this->isSwarmManager;
$this->server->settings->is_swarm_worker = $this->isSwarmWorker;
$this->server->settings->is_build_server = $this->isBuildServer;
$this->server->settings->is_metrics_enabled = $this->isMetricsEnabled;
$this->server->settings->sentinel_token = $this->sentinelToken;
$this->server->settings->sentinel_metrics_refresh_rate_seconds = $this->sentinelMetricsRefreshRateSeconds;
$this->server->settings->sentinel_metrics_history_days = $this->sentinelMetricsHistoryDays;
$this->server->settings->sentinel_push_interval_seconds = $this->sentinelPushIntervalSeconds;
$this->server->settings->sentinel_custom_url = $this->sentinelCustomUrl;
$this->server->settings->is_sentinel_enabled = $this->isSentinelEnabled;
$this->server->settings->is_sentinel_debug_enabled = $this->isSentinelDebugEnabled;
$this->server->settings->server_timezone = $this->serverTimezone;
$this->server->settings->save();
} else {
$this->name = $this->server->name;
$this->description = $this->server->description;
$this->ip = $this->server->ip;
$this->user = $this->server->user;
$this->port = $this->server->port;
$this->wildcardDomain = $this->server->settings->wildcard_domain;
$this->isReachable = $this->server->settings->is_reachable;
$this->isUsable = $this->server->settings->is_usable;
$this->isSwarmManager = $this->server->settings->is_swarm_manager;
$this->isSwarmWorker = $this->server->settings->is_swarm_worker;
$this->isBuildServer = $this->server->settings->is_build_server;
$this->isMetricsEnabled = $this->server->settings->is_metrics_enabled;
$this->sentinelToken = $this->server->settings->sentinel_token;
$this->sentinelMetricsRefreshRateSeconds = $this->server->settings->sentinel_metrics_refresh_rate_seconds;
$this->sentinelMetricsHistoryDays = $this->server->settings->sentinel_metrics_history_days;
$this->sentinelPushIntervalSeconds = $this->server->settings->sentinel_push_interval_seconds;
$this->sentinelCustomUrl = $this->server->settings->sentinel_custom_url;
$this->isSentinelEnabled = $this->server->settings->is_sentinel_enabled;
$this->isSentinelDebugEnabled = $this->server->settings->is_sentinel_debug_enabled;
$this->sentinelUpdatedAt = $this->server->settings->updated_at;
$this->serverTimezone = $this->server->settings->server_timezone;
}
}
public function validateServer($install = true)
{
try {
$this->validationLogs = $this->server->validation_logs = null;
$this->server->save();
$this->dispatch('init', $install);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function checkLocalhostConnection()
{
$this->syncData(true);
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
if ($uptime) {
$this->dispatch('success', 'Server is reachable.');
$this->server->settings->is_reachable = $this->isReachable = true;
$this->server->settings->is_usable = $this->isUsable = true;
$this->server->settings->save();
$this->dispatch('proxyStatusUpdated');
} else {
$this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error);
return;
}
}
public function regenerateSentinelToken()
{
try {
$this->server->settings->generateSentinelToken();
$this->dispatch('success', 'Token regenerated & Sentinel restarted.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function instantSave()
{
$this->submit();
}
public function submit()
{
$this->dispatch('serverRefresh', false);
try {
$this->syncData(true);
$this->dispatch('success', 'Server updated');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function render()

View File

@@ -1,68 +0,0 @@
<?php
namespace App\Livewire\Server;
use App\Models\PrivateKey;
use App\Models\Server;
use Livewire\Component;
class ShowPrivateKey extends Component
{
public Server $server;
public $privateKeys;
public $parameters;
public function mount()
{
$this->parameters = get_route_parameters();
}
public function setPrivateKey($privateKeyId)
{
$ownedPrivateKey = PrivateKey::ownedByCurrentTeam()->find($privateKeyId);
if (is_null($ownedPrivateKey)) {
$this->dispatch('error', 'You are not allowed to use this private key.');
return;
}
$originalPrivateKeyId = $this->server->getOriginal('private_key_id');
try {
$this->server->update(['private_key_id' => $privateKeyId]);
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
if ($uptime) {
$this->dispatch('success', 'Private key updated successfully.');
} else {
throw new \Exception('Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.$error);
}
} catch (\Exception $e) {
$this->server->update(['private_key_id' => $originalPrivateKeyId]);
$this->server->validateConnection();
$this->dispatch('error', 'Failed to update private key: '.$e->getMessage());
} finally {
$this->dispatch('refreshServerShow');
$this->server->refresh();
}
}
public function checkConnection()
{
try {
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
if ($uptime) {
$this->dispatch('success', 'Server is reachable.');
} else {
$this->dispatch('error', 'Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.$error);
return;
}
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
$this->dispatch('refreshServerShow');
$this->server->refresh();
}
}
}

View File

@@ -47,7 +47,6 @@ class SettingsEmail extends Component
} else {
return redirect()->route('dashboard');
}
}
public function submitFromFields()

View File

@@ -4,7 +4,6 @@ namespace App\Livewire\Source\Github;
use App\Jobs\GithubAppPermissionJob;
use App\Models\GithubApp;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
class Change extends Component
@@ -141,7 +140,6 @@ class Change extends Component
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submit()

View File

@@ -8,49 +8,16 @@ use Stripe\Stripe;
class PricingPlans extends Component
{
public bool $isTrial = false;
public function mount()
{
$this->isTrial = ! data_get(currentTeam(), 'subscription.stripe_trial_already_ended');
if (config('constants.limits.trial_period') == 0) {
$this->isTrial = false;
}
}
public function subscribeStripe($type)
{
$team = currentTeam();
Stripe::setApiKey(config('subscription.stripe_api_key'));
switch ($type) {
case 'basic-monthly':
$priceId = config('subscription.stripe_price_id_basic_monthly');
break;
case 'basic-yearly':
$priceId = config('subscription.stripe_price_id_basic_yearly');
break;
case 'pro-monthly':
$priceId = config('subscription.stripe_price_id_pro_monthly');
break;
case 'pro-yearly':
$priceId = config('subscription.stripe_price_id_pro_yearly');
break;
case 'ultimate-monthly':
$priceId = config('subscription.stripe_price_id_ultimate_monthly');
break;
case 'ultimate-yearly':
$priceId = config('subscription.stripe_price_id_ultimate_yearly');
break;
case 'dynamic-monthly':
$priceId = config('subscription.stripe_price_id_dynamic_monthly');
break;
case 'dynamic-yearly':
$priceId = config('subscription.stripe_price_id_dynamic_yearly');
break;
default:
$priceId = config('subscription.stripe_price_id_basic_monthly');
break;
}
$priceId = match ($type) {
'dynamic-monthly' => config('subscription.stripe_price_id_dynamic_monthly'),
'dynamic-yearly' => config('subscription.stripe_price_id_dynamic_yearly'),
default => config('subscription.stripe_price_id_dynamic_monthly'),
};
if (! $priceId) {
$this->dispatch('error', 'Price ID not found! Please contact the administrator.');
@@ -62,7 +29,11 @@ class PricingPlans extends Component
'client_reference_id' => auth()->user()->id.':'.currentTeam()->id,
'line_items' => [[
'price' => $priceId,
'quantity' => 1,
'adjustable_quantity' => [
'enabled' => true,
'minimum' => 2,
],
'quantity' => 2,
]],
'tax_id_collection' => [
'enabled' => true,
@@ -70,39 +41,18 @@ class PricingPlans extends Component
'automatic_tax' => [
'enabled' => true,
],
'subscription_data' => [
'metadata' => [
'user_id' => auth()->user()->id,
'team_id' => currentTeam()->id,
],
],
'payment_method_collection' => 'if_required',
'mode' => 'subscription',
'success_url' => route('dashboard', ['success' => true]),
'cancel_url' => route('subscription.index', ['cancelled' => true]),
];
if (str($type)->contains('ultimate')) {
$payload['line_items'][0]['adjustable_quantity'] = [
'enabled' => true,
'minimum' => 10,
];
$payload['line_items'][0]['quantity'] = 10;
}
if (str($type)->contains('dynamic')) {
$payload['line_items'][0]['adjustable_quantity'] = [
'enabled' => true,
'minimum' => 2,
];
$payload['line_items'][0]['quantity'] = 2;
}
if (! data_get($team, 'subscription.stripe_trial_already_ended')) {
if (config('constants.limits.trial_period') > 0) {
$payload['subscription_data'] = [
'trial_period_days' => config('constants.limits.trial_period'),
'trial_settings' => [
'end_behavior' => [
'missing_payment_method' => 'cancel',
],
],
];
}
$payload['payment_method_collection'] = 'if_required';
}
$customer = currentTeam()->subscription?->stripe_customer_id ?? null;
if ($customer) {
$payload['customer'] = $customer;

View File

@@ -47,7 +47,7 @@ class Index extends Component
public function tagUpdated()
{
if ($this->tag == '') {
if ($this->tag === '') {
return;
}
$sanitizedTag = htmlspecialchars($this->tag, ENT_QUOTES, 'UTF-8');

View File

@@ -18,7 +18,7 @@ class Invitations extends Component
$initiation_found->delete();
$this->refreshInvitations();
$this->dispatch('success', 'Invitation revoked.');
} catch (\Exception $e) {
} catch (\Exception) {
return $this->dispatch('error', 'Invitation not found.');
}
}

View File

@@ -23,11 +23,9 @@ class Upgrade extends Component
try {
$this->latestVersion = get_latest_version_of_coolify();
$this->isUpgradeAvailable = data_get(InstanceSettings::get(), 'new_version_available', false);
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function upgrade()

View File

@@ -15,7 +15,6 @@ class VerifyEmail extends Component
$this->rateLimit(1, 300);
auth()->user()->sendVerificationEmail();
$this->dispatch('success', 'Email verification link sent!');
} catch (\Exception $e) {
return handleError($e, $this);
}

View File

@@ -114,7 +114,7 @@ class Application extends BaseModel
protected static function booted()
{
static::saving(function ($application) {
if ($application->fqdn == '') {
if ($application->fqdn === '') {
$application->fqdn = null;
}
$application->forceFill([
@@ -936,7 +936,7 @@ class Application extends BaseModel
$source_html_url_host = $url['host'];
$source_html_url_scheme = $url['scheme'];
if ($this->source->getMorphClass() == \App\Models\GithubApp::class) {
if ($this->source->getMorphClass() === \App\Models\GithubApp::class) {
if ($this->source->is_public) {
$fullRepoUrl = "{$this->source->html_url}/{$customRepository}";
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$customRepository} {$baseDir}";
@@ -1407,7 +1407,7 @@ class Application extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -1431,7 +1431,7 @@ class Application extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -29,7 +29,6 @@ class Environment extends Model
foreach ($shared_variables as $shared_variable) {
$shared_variable->delete();
}
});
}

View File

@@ -156,13 +156,12 @@ class EnvironmentVariable extends Model
private function get_real_environment_variables(?string $environment_variable = null, $resource = null)
{
if ((is_null($environment_variable) && $environment_variable == '') || is_null($resource)) {
if ((is_null($environment_variable) && $environment_variable === '') || is_null($resource)) {
return null;
}
$environment_variable = trim($environment_variable);
$sharedEnvsFound = str($environment_variable)->matchAll('/{{(.*?)}}/');
if ($sharedEnvsFound->isEmpty()) {
return $environment_variable;
}
@@ -202,7 +201,7 @@ class EnvironmentVariable extends Model
private function set_environment_variables(?string $environment_variable = null): ?string
{
if (is_null($environment_variable) && $environment_variable == '') {
if (is_null($environment_variable) && $environment_variable === '') {
return null;
}
$environment_variable = trim($environment_variable);

View File

@@ -36,7 +36,6 @@ class InstanceSettings extends Model implements SendsEmail
});
}
});
}
public function fqdn(): Attribute

View File

@@ -72,7 +72,6 @@ class LocalFileVolume extends BaseModel
if ($path && $path != '/' && $path != '.' && $path != '..') {
if ($isFile === 'OK') {
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
} elseif ($isDir === 'OK') {
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
$commands->push("rmdir $path > /dev/null 2>&1 || true");
@@ -113,15 +112,15 @@ class LocalFileVolume extends BaseModel
}
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
if ($isFile == 'OK' && $this->is_directory) {
if ($isFile === 'OK' && $this->is_directory) {
$content = instant_remote_process(["cat $path"], $server, false);
$this->is_directory = false;
$this->content = $content;
$this->save();
FileStorageChanged::dispatch(data_get($server, 'team_id'));
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
} elseif ($isDir == 'OK' && ! $this->is_directory) {
if ($path == '/' || $path == '.' || $path == '..' || $path == '' || str($path)->isEmpty() || is_null($path)) {
} elseif ($isDir === 'OK' && ! $this->is_directory) {
if ($path === '/' || $path === '.' || $path === '..' || $path === '' || str($path)->isEmpty() || is_null($path)) {
$this->is_directory = true;
$this->save();
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
@@ -132,7 +131,7 @@ class LocalFileVolume extends BaseModel
], $server, false);
FileStorageChanged::dispatch(data_get($server, 'team_id'));
}
if ($isDir == 'NOK' && ! $this->is_directory) {
if ($isDir === 'NOK' && ! $this->is_directory) {
$chmod = data_get($this, 'chmod');
$chown = data_get($this, 'chown');
if ($content) {
@@ -148,7 +147,7 @@ class LocalFileVolume extends BaseModel
if ($chmod) {
$commands->push("chmod $chmod $path");
}
} elseif ($isDir == 'NOK' && $this->is_directory) {
} elseif ($isDir === 'NOK' && $this->is_directory) {
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
}

View File

@@ -34,21 +34,15 @@ class ScheduledTask extends BaseModel
{
if ($this->application) {
if ($this->application->destination && $this->application->destination->server) {
$server = $this->application->destination->server;
return $server;
return $this->application->destination->server;
}
} elseif ($this->service) {
if ($this->service->destination && $this->service->destination->server) {
$server = $this->service->destination->server;
return $server;
return $this->service->destination->server;
}
} elseif ($this->database) {
if ($this->database->destination && $this->database->destination->server) {
$server = $this->database->destination->server;
return $server;
return $this->database->destination->server;
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Models;
use App\Actions\Server\InstallDocker;
use App\Actions\Server\StartSentinel;
use App\Enums\ProxyTypes;
use App\Helpers\SshMultiplexingHelper;
use App\Jobs\CheckAndStartSentinelJob;
use App\Notifications\Server\Reachable;
use App\Notifications\Server\Unreachable;
@@ -14,7 +15,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Stringable;
use OpenApi\Attributes as OA;
@@ -63,7 +63,11 @@ class Server extends BaseModel
$payload['ip'] = str($server->ip)->trim();
}
$server->forceFill($payload);
});
static::saved(function ($server) {
if ($server->privateKey->isDirty()) {
refresh_server_connection($server->privateKey);
}
});
static::created(function ($server) {
ServerSetting::create([
@@ -416,7 +420,7 @@ respond 404
"echo '$base64' | base64 -d | tee $file > /dev/null",
], $this);
if (config('app.env') == 'local') {
if (config('app.env') === 'local') {
// ray($yaml);
}
}
@@ -592,17 +596,16 @@ $schema://$host {
if (str($cpu)->contains('error')) {
$error = json_decode($cpu, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
}
$cpu = json_decode($cpu, true);
$parsedCollection = collect($cpu)->map(function ($metric) {
return collect($cpu)->map(function ($metric) {
return [(int) $metric['time'], (float) $metric['percent']];
});
return $parsedCollection;
}
}
@@ -614,7 +617,7 @@ $schema://$host {
if (str($memory)->contains('error')) {
$error = json_decode($memory, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -833,9 +836,7 @@ $schema://$host {
{
return Attribute::make(
get: function ($value) {
$sanitizedValue = preg_replace('/[^A-Za-z0-9\-_]/', '', $value);
return $sanitizedValue;
return preg_replace('/[^A-Za-z0-9\-_]/', '', $value);
}
);
}
@@ -1027,7 +1028,6 @@ $schema://$host {
$this->refresh();
$unreachableNotificationSent = (bool) $this->unreachable_notification_sent;
$isReachable = (bool) $this->settings->is_reachable;
loggy('Server setting is_reachable changed to '.$isReachable.' for server '.$this->id.'. Unreachable notification sent: '.$unreachableNotificationSent);
// If the server is reachable, send the reachable notification if it was sent before
if ($isReachable === true) {
if ($unreachableNotificationSent === true) {
@@ -1057,10 +1057,12 @@ $schema://$host {
$this->team->notify(new Unreachable($this));
}
public function validateConnection($isManualCheck = true)
public function validateConnection(bool $isManualCheck = true, bool $justCheckingNewKey = false)
{
config()->set('constants.ssh.mux_enabled', ! $isManualCheck);
SshMultiplexingHelper::removeMuxFile($this);
if ($this->skipServer()) {
return ['uptime' => false, 'error' => 'Server skipped.'];
}
@@ -1077,6 +1079,9 @@ $schema://$host {
return ['uptime' => true, 'error' => null];
} catch (\Throwable $e) {
if ($justCheckingNewKey) {
return ['uptime' => false, 'error' => 'This key is not valid for this server.'];
}
if ($this->settings->is_reachable === true) {
$this->settings->is_reachable = false;
$this->settings->save();
@@ -1088,9 +1093,7 @@ $schema://$host {
public function installDocker()
{
$activity = InstallDocker::run($this);
return $activity;
return InstallDocker::run($this);
}
public function validateDockerEngine($throwError = false)

View File

@@ -117,7 +117,6 @@ class ServerSetting extends Model
$domain = 'http://'.$settings->public_ipv6.':8000';
}
$this->sentinel_custom_url = $domain;
loggy('Sentinel URL: '.$domain);
if ($save) {
$this->save();
}

View File

@@ -1095,7 +1095,6 @@ class Service extends BaseModel
}
$fields->put('MariaDB', $data->toArray());
break;
}
}
@@ -1304,14 +1303,11 @@ class Service extends BaseModel
} else {
return collect([]);
}
}
public function networks()
{
$networks = getTopLevelNetworks($this);
return $networks;
return getTopLevelNetworks($this);
}
protected function isDeployable(): Attribute

View File

@@ -275,7 +275,7 @@ class StandaloneClickhouse extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -297,7 +297,7 @@ class StandaloneClickhouse extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -275,7 +275,7 @@ class StandaloneDragonfly extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -297,7 +297,7 @@ class StandaloneDragonfly extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -275,7 +275,7 @@ class StandaloneKeydb extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -297,7 +297,7 @@ class StandaloneKeydb extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -275,7 +275,7 @@ class StandaloneMariadb extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -297,7 +297,7 @@ class StandaloneMariadb extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -295,7 +295,7 @@ class StandaloneMongodb extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -317,7 +317,7 @@ class StandaloneMongodb extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -276,7 +276,7 @@ class StandaloneMysql extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -298,7 +298,7 @@ class StandaloneMysql extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -281,7 +281,7 @@ class StandalonePostgresql extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -303,7 +303,7 @@ class StandalonePostgresql extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

View File

@@ -286,7 +286,7 @@ class StandaloneRedis extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);
@@ -308,7 +308,7 @@ class StandaloneRedis extends BaseModel
if (str($metrics)->contains('error')) {
$error = json_decode($metrics, true);
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
if ($error == 'Unauthorized') {
if ($error === 'Unauthorized') {
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
}
throw new \Exception($error);

Some files were not shown because too many files have changed in this diff Show More