Merge branch 'next' into useless-variable-assignments
This commit is contained in:
@@ -1400,13 +1400,13 @@ class Application extends BaseModel
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
if (str($metrics)->contains('error')) {
|
||||
$error = json_decode($metrics, true);
|
||||
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
|
||||
@@ -1415,14 +1415,33 @@ class Application extends BaseModel
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
@@ -1459,7 +1478,7 @@ class Application extends BaseModel
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
public function setConfig($config)
|
||||
{
|
||||
$validator = Validator::make(['config' => $config], [
|
||||
|
||||
@@ -44,7 +44,7 @@ class EnvironmentVariable extends Model
|
||||
'version' => 'string',
|
||||
];
|
||||
|
||||
protected $appends = ['real_value', 'is_shared'];
|
||||
protected $appends = ['real_value', 'is_shared', 'is_really_required'];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
@@ -74,6 +74,9 @@ class EnvironmentVariable extends Model
|
||||
'version' => config('version'),
|
||||
]);
|
||||
});
|
||||
static::saving(function (EnvironmentVariable $environmentVariable) {
|
||||
$environmentVariable->updateIsShared();
|
||||
});
|
||||
}
|
||||
|
||||
public function service()
|
||||
@@ -130,6 +133,13 @@ class EnvironmentVariable extends Model
|
||||
);
|
||||
}
|
||||
|
||||
protected function isReallyRequired(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->is_required && str($this->real_value)->isEmpty(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function isShared(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
@@ -210,4 +220,11 @@ class EnvironmentVariable extends Model
|
||||
set: fn (string $value) => str($value)->trim()->replace(' ', '_')->value,
|
||||
);
|
||||
}
|
||||
|
||||
protected function updateIsShared(): void
|
||||
{
|
||||
$type = str($this->value)->after('{{')->before('.')->value;
|
||||
$isShared = str($this->value)->startsWith('{{'.$type) && str($this->value)->endsWith('}}');
|
||||
$this->is_shared = $isShared;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@ class GithubApp extends BaseModel
|
||||
});
|
||||
}
|
||||
|
||||
public static function ownedByCurrentTeam()
|
||||
{
|
||||
return GithubApp::whereTeamId(currentTeam()->id);
|
||||
}
|
||||
|
||||
public static function public()
|
||||
{
|
||||
return GithubApp::whereTeamId(currentTeam()->id)->whereisPublic(true)->whereNotNull('app_id')->get();
|
||||
|
||||
@@ -9,6 +9,11 @@ class GitlabApp extends BaseModel
|
||||
'app_secret',
|
||||
];
|
||||
|
||||
public static function ownedByCurrentTeam()
|
||||
{
|
||||
return GitlabApp::whereTeamId(currentTeam()->id);
|
||||
}
|
||||
|
||||
public function applications()
|
||||
{
|
||||
return $this->morphMany(Application::class, 'source');
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Jobs\PullHelperImageJob;
|
||||
use App\Notifications\Channels\SendsEmail;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -21,8 +22,23 @@ class InstanceSettings extends Model implements SendsEmail
|
||||
'is_auto_update_enabled' => 'boolean',
|
||||
'auto_update_frequency' => 'string',
|
||||
'update_check_frequency' => 'string',
|
||||
'sentinel_token' => 'encrypted',
|
||||
];
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::updated(function ($settings) {
|
||||
if ($settings->isDirty('helper_version')) {
|
||||
Server::chunkById(100, function ($servers) {
|
||||
foreach ($servers as $server) {
|
||||
PullHelperImageJob::dispatch($server);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public function fqdn(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
@@ -86,16 +102,16 @@ class InstanceSettings extends Model implements SendsEmail
|
||||
return "[{$instanceName}]";
|
||||
}
|
||||
|
||||
public function helperVersion(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function ($value) {
|
||||
if (isDev()) {
|
||||
return 'latest';
|
||||
}
|
||||
// public function helperVersion(): Attribute
|
||||
// {
|
||||
// return Attribute::make(
|
||||
// get: function ($value) {
|
||||
// if (isDev()) {
|
||||
// return 'latest';
|
||||
// }
|
||||
|
||||
return $value;
|
||||
}
|
||||
);
|
||||
}
|
||||
// return $value;
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ class ScheduledDatabaseBackup extends BaseModel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Actions\Server\InstallDocker;
|
||||
use App\Actions\Server\StartSentinel;
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Jobs\PullSentinelImageJob;
|
||||
use App\Jobs\CheckAndStartSentinelJob;
|
||||
use App\Notifications\Server\Reachable;
|
||||
use App\Notifications\Server\Unreachable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
@@ -43,7 +48,7 @@ use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class Server extends BaseModel
|
||||
{
|
||||
use SchemalessAttributesTrait;
|
||||
use SchemalessAttributesTrait, SoftDeletes;
|
||||
|
||||
public static $batch_counter = 0;
|
||||
|
||||
@@ -58,6 +63,7 @@ class Server extends BaseModel
|
||||
$payload['ip'] = str($server->ip)->trim();
|
||||
}
|
||||
$server->forceFill($payload);
|
||||
|
||||
});
|
||||
static::created(function ($server) {
|
||||
ServerSetting::create([
|
||||
@@ -95,7 +101,8 @@ class Server extends BaseModel
|
||||
}
|
||||
}
|
||||
});
|
||||
static::deleting(function ($server) {
|
||||
|
||||
static::forceDeleting(function ($server) {
|
||||
$server->destinations()->each(function ($destination) {
|
||||
$destination->delete();
|
||||
});
|
||||
@@ -103,12 +110,15 @@ class Server extends BaseModel
|
||||
});
|
||||
}
|
||||
|
||||
public $casts = [
|
||||
protected $casts = [
|
||||
'proxy' => SchemalessAttributes::class,
|
||||
'logdrain_axiom_api_key' => 'encrypted',
|
||||
'logdrain_newrelic_license_key' => 'encrypted',
|
||||
'delete_unused_volumes' => 'boolean',
|
||||
'delete_unused_networks' => 'boolean',
|
||||
'unreachable_notification_sent' => 'boolean',
|
||||
'is_build_server' => 'boolean',
|
||||
'force_disabled' => 'boolean',
|
||||
];
|
||||
|
||||
protected $schemalessAttributes = [
|
||||
@@ -127,6 +137,11 @@ class Server extends BaseModel
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
public function type()
|
||||
{
|
||||
return 'server';
|
||||
}
|
||||
|
||||
public static function isReachable()
|
||||
{
|
||||
return Server::ownedByCurrentTeam()->whereRelation('settings', 'is_reachable', true);
|
||||
@@ -209,10 +224,13 @@ respond 404
|
||||
1 => 'https',
|
||||
],
|
||||
'service' => 'noop',
|
||||
'rule' => 'HostRegexp(`{catchall:.*}`)',
|
||||
'rule' => 'HostRegexp(`.+`)',
|
||||
'tls' => [
|
||||
'certResolver' => 'letsencrypt',
|
||||
],
|
||||
'priority' => 1,
|
||||
'middlewares' => [
|
||||
0 => 'redirect-regexp@file',
|
||||
0 => 'redirect-regexp',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -507,24 +525,48 @@ $schema://$host {
|
||||
|
||||
public function forceEnableServer()
|
||||
{
|
||||
$this->settings->update([
|
||||
'force_disabled' => false,
|
||||
]);
|
||||
$this->settings->force_disabled = false;
|
||||
$this->settings->save();
|
||||
}
|
||||
|
||||
public function forceDisableServer()
|
||||
{
|
||||
$this->settings->update([
|
||||
'force_disabled' => true,
|
||||
]);
|
||||
$this->settings->force_disabled = true;
|
||||
$this->settings->save();
|
||||
$sshKeyFileLocation = "id.root@{$this->uuid}";
|
||||
Storage::disk('ssh-keys')->delete($sshKeyFileLocation);
|
||||
Storage::disk('ssh-mux')->delete($this->muxFilename());
|
||||
}
|
||||
|
||||
public function sentinelHeartbeat(bool $isReset = false)
|
||||
{
|
||||
$this->sentinel_updated_at = $isReset ? now()->subMinutes(6000) : now();
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wait time for Sentinel to push before performing an SSH check.
|
||||
*
|
||||
* @return int The wait time in seconds.
|
||||
*/
|
||||
public function waitBeforeDoingSshCheck(): int
|
||||
{
|
||||
$wait = $this->settings->sentinel_push_interval_seconds * 3;
|
||||
if ($wait < 120) {
|
||||
$wait = 120;
|
||||
}
|
||||
|
||||
return $wait;
|
||||
}
|
||||
|
||||
public function isSentinelLive()
|
||||
{
|
||||
return Carbon::parse($this->sentinel_updated_at)->isAfter(now()->subSeconds($this->waitBeforeDoingSshCheck()));
|
||||
}
|
||||
|
||||
public function isSentinelEnabled()
|
||||
{
|
||||
return $this->isMetricsEnabled() || $this->isServerApiEnabled();
|
||||
return ($this->isMetricsEnabled() || $this->isServerApiEnabled()) && ! $this->isBuildServer();
|
||||
}
|
||||
|
||||
public function isMetricsEnabled()
|
||||
@@ -534,49 +576,19 @@ $schema://$host {
|
||||
|
||||
public function isServerApiEnabled()
|
||||
{
|
||||
return $this->settings->is_server_api_enabled;
|
||||
}
|
||||
|
||||
public function checkServerApi()
|
||||
{
|
||||
if ($this->isServerApiEnabled()) {
|
||||
$server_ip = $this->ip;
|
||||
if (isDev()) {
|
||||
if ($this->id === 0) {
|
||||
$server_ip = 'localhost';
|
||||
}
|
||||
}
|
||||
$command = "curl -s http://{$server_ip}:12172/api/health";
|
||||
$process = Process::timeout(5)->run($command);
|
||||
if ($process->failed()) {
|
||||
ray($process->exitCode(), $process->output(), $process->errorOutput());
|
||||
throw new \Exception("Server API is not reachable on http://{$server_ip}:12172");
|
||||
}
|
||||
|
||||
}
|
||||
return $this->settings->is_sentinel_enabled;
|
||||
}
|
||||
|
||||
public function checkSentinel()
|
||||
{
|
||||
// ray("Checking sentinel on server: {$this->name}");
|
||||
if ($this->isSentinelEnabled()) {
|
||||
$sentinel_found = instant_remote_process(['docker inspect coolify-sentinel'], $this, false);
|
||||
$sentinel_found = json_decode($sentinel_found, true);
|
||||
$status = data_get($sentinel_found, '0.State.Status', 'exited');
|
||||
if ($status !== 'running') {
|
||||
// ray('Sentinel is not running, starting it...');
|
||||
PullSentinelImageJob::dispatch($this);
|
||||
} else {
|
||||
// ray('Sentinel is running');
|
||||
}
|
||||
}
|
||||
CheckAndStartSentinelJob::dispatch($this);
|
||||
}
|
||||
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
if ($this->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->metrics_token}\" http://localhost:8888/api/cpu/history?from=$from'"], $this, false);
|
||||
$cpu = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/cpu/history?from=$from'"], $this, false);
|
||||
if (str($cpu)->contains('error')) {
|
||||
$error = json_decode($cpu, true);
|
||||
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
|
||||
@@ -585,17 +597,12 @@ $schema://$host {
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$cpu = str($cpu)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($cpu)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 0);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent];
|
||||
});
|
||||
$cpu = json_decode($cpu, true);
|
||||
$parsedCollection = collect($cpu)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
return $parsedCollection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,7 +610,7 @@ $schema://$host {
|
||||
{
|
||||
if ($this->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$memory = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->metrics_token}\" http://localhost:8888/api/memory/history?from=$from'"], $this, false);
|
||||
$memory = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$this->settings->sentinel_token}\" http://localhost:8888/api/memory/history?from=$from'"], $this, false);
|
||||
if (str($memory)->contains('error')) {
|
||||
$error = json_decode($memory, true);
|
||||
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
|
||||
@@ -612,89 +619,19 @@ $schema://$host {
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$memory = str($memory)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($memory)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $used, $free, $usedPercent] = explode(',', trim($line));
|
||||
$usedPercent = number_format($usedPercent, 0);
|
||||
|
||||
return [(int) $time, (float) $usedPercent];
|
||||
});
|
||||
$memory = json_decode($memory, true);
|
||||
$parsedCollection = collect($memory)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['usedPercent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
public function isServerReady(int $tries = 3)
|
||||
{
|
||||
if ($this->skipServer()) {
|
||||
return false;
|
||||
}
|
||||
$serverUptimeCheckNumber = $this->unreachable_count;
|
||||
if ($this->unreachable_count < $tries) {
|
||||
$serverUptimeCheckNumber = $this->unreachable_count + 1;
|
||||
}
|
||||
if ($this->unreachable_count > $tries) {
|
||||
$serverUptimeCheckNumber = $tries;
|
||||
}
|
||||
|
||||
$serverUptimeCheckNumberMax = $tries;
|
||||
|
||||
// ray('server: ' . $this->name);
|
||||
// ray('serverUptimeCheckNumber: ' . $serverUptimeCheckNumber);
|
||||
// ray('serverUptimeCheckNumberMax: ' . $serverUptimeCheckNumberMax);
|
||||
|
||||
['uptime' => $uptime] = $this->validateConnection();
|
||||
if ($uptime) {
|
||||
if ($this->unreachable_notification_sent === true) {
|
||||
$this->update(['unreachable_notification_sent' => false]);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
|
||||
// Reached max number of retries
|
||||
if ($this->unreachable_notification_sent === false) {
|
||||
ray('Server unreachable, sending notification...');
|
||||
// $this->team?->notify(new Unreachable($this));
|
||||
$this->update(['unreachable_notification_sent' => true]);
|
||||
}
|
||||
if ($this->settings->is_reachable === true) {
|
||||
$this->settings()->update([
|
||||
'is_reachable' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($this->applications() as $application) {
|
||||
$application->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($this->databases() as $database) {
|
||||
$database->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($this->services()->get() as $service) {
|
||||
$apps = $service->applications()->get();
|
||||
$dbs = $service->databases()->get();
|
||||
foreach ($apps as $app) {
|
||||
$app->update(['status' => 'exited']);
|
||||
}
|
||||
foreach ($dbs as $db) {
|
||||
$db->update(['status' => 'exited']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->update([
|
||||
'unreachable_count' => $this->unreachable_count + 1,
|
||||
]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDiskUsage(): ?string
|
||||
{
|
||||
return instant_remote_process(["df /| tail -1 | awk '{ print $5}' | sed 's/%//g'"], $this, false);
|
||||
return instant_remote_process(['df / --output=pcent | tr -cd 0-9'], $this, false);
|
||||
// return instant_remote_process(["df /| tail -1 | awk '{ print $5}' | sed 's/%//g'"], $this, false);
|
||||
}
|
||||
|
||||
public function definedResources()
|
||||
@@ -974,7 +911,8 @@ $schema://$host {
|
||||
|
||||
public function isProxyShouldRun()
|
||||
{
|
||||
if ($this->proxyType() === ProxyTypes::NONE->value || $this->settings->is_build_server) {
|
||||
// TODO: Do we need "|| $this->proxy->force_stop" here?
|
||||
if ($this->proxyType() === ProxyTypes::NONE->value || $this->isBuildServer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1038,39 +976,111 @@ $schema://$host {
|
||||
return data_get($this, 'settings.is_swarm_worker');
|
||||
}
|
||||
|
||||
public function serverStatus(): bool
|
||||
{
|
||||
if ($this->status() === false) {
|
||||
return false;
|
||||
}
|
||||
if ($this->isFunctional() === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function status(): bool
|
||||
{
|
||||
if ($this->skipServer()) {
|
||||
return false;
|
||||
}
|
||||
['uptime' => $uptime] = $this->validateConnection(false);
|
||||
if ($uptime === false) {
|
||||
foreach ($this->applications() as $application) {
|
||||
$application->status = 'exited';
|
||||
$application->save();
|
||||
}
|
||||
foreach ($this->databases() as $database) {
|
||||
$database->status = 'exited';
|
||||
$database->save();
|
||||
}
|
||||
foreach ($this->services() as $service) {
|
||||
$apps = $service->applications()->get();
|
||||
$dbs = $service->databases()->get();
|
||||
foreach ($apps as $app) {
|
||||
$app->status = 'exited';
|
||||
$app->save();
|
||||
}
|
||||
foreach ($dbs as $db) {
|
||||
$db->status = 'exited';
|
||||
$db->save();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isReachableChanged()
|
||||
{
|
||||
$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) {
|
||||
$this->sendReachableNotification();
|
||||
}
|
||||
} else {
|
||||
// If the server is unreachable, send the unreachable notification if it was not sent before
|
||||
if ($unreachableNotificationSent === false) {
|
||||
$this->sendUnreachableNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function sendReachableNotification()
|
||||
{
|
||||
$this->unreachable_notification_sent = false;
|
||||
$this->save();
|
||||
$this->refresh();
|
||||
$this->team->notify(new Reachable($this));
|
||||
}
|
||||
|
||||
public function sendUnreachableNotification()
|
||||
{
|
||||
$this->unreachable_notification_sent = true;
|
||||
$this->save();
|
||||
$this->refresh();
|
||||
$this->team->notify(new Unreachable($this));
|
||||
}
|
||||
|
||||
public function validateConnection($isManualCheck = true)
|
||||
{
|
||||
config()->set('constants.ssh.mux_enabled', ! $isManualCheck);
|
||||
// ray('Manual Check: ' . ($isManualCheck ? 'true' : 'false'));
|
||||
|
||||
$server = Server::find($this->id);
|
||||
if (! $server) {
|
||||
return ['uptime' => false, 'error' => 'Server not found.'];
|
||||
}
|
||||
if ($server->skipServer()) {
|
||||
if ($this->skipServer()) {
|
||||
return ['uptime' => false, 'error' => 'Server skipped.'];
|
||||
}
|
||||
try {
|
||||
// Make sure the private key is stored
|
||||
if ($server->privateKey) {
|
||||
$server->privateKey->storeInFileSystem();
|
||||
if ($this->privateKey) {
|
||||
$this->privateKey->storeInFileSystem();
|
||||
}
|
||||
instant_remote_process(['ls /'], $server);
|
||||
$server->settings()->update([
|
||||
'is_reachable' => true,
|
||||
]);
|
||||
$server->update([
|
||||
'unreachable_count' => 0,
|
||||
]);
|
||||
if (data_get($server, 'unreachable_notification_sent') === true) {
|
||||
$server->update(['unreachable_notification_sent' => false]);
|
||||
instant_remote_process(['ls /'], $this);
|
||||
if ($this->settings->is_reachable === false) {
|
||||
$this->settings->is_reachable = true;
|
||||
$this->settings->save();
|
||||
}
|
||||
|
||||
return ['uptime' => true, 'error' => null];
|
||||
} catch (\Throwable $e) {
|
||||
$server->settings()->update([
|
||||
'is_reachable' => false,
|
||||
]);
|
||||
if ($this->settings->is_reachable === true) {
|
||||
$this->settings->is_reachable = false;
|
||||
$this->settings->save();
|
||||
}
|
||||
|
||||
return ['uptime' => false, 'error' => $e->getMessage()];
|
||||
}
|
||||
@@ -1225,4 +1235,22 @@ $schema://$host {
|
||||
{
|
||||
return str($this->ip)->contains(':');
|
||||
}
|
||||
|
||||
public function restartSentinel(bool $async = true): void
|
||||
{
|
||||
try {
|
||||
if ($async) {
|
||||
StartSentinel::dispatch($this, true);
|
||||
} else {
|
||||
StartSentinel::run($this, true);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
loggy('Error restarting Sentinel: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function url()
|
||||
{
|
||||
return base_url().'/server/'.$this->uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use OpenApi\Attributes as OA;
|
||||
'is_logdrain_newrelic_enabled' => ['type' => 'boolean'],
|
||||
'is_metrics_enabled' => ['type' => 'boolean'],
|
||||
'is_reachable' => ['type' => 'boolean'],
|
||||
'is_server_api_enabled' => ['type' => 'boolean'],
|
||||
'is_sentinel_enabled' => ['type' => 'boolean'],
|
||||
'is_swarm_manager' => ['type' => 'boolean'],
|
||||
'is_swarm_worker' => ['type' => 'boolean'],
|
||||
'is_usable' => ['type' => 'boolean'],
|
||||
@@ -35,9 +35,9 @@ use OpenApi\Attributes as OA;
|
||||
'logdrain_highlight_project_id' => ['type' => 'string'],
|
||||
'logdrain_newrelic_base_uri' => ['type' => 'string'],
|
||||
'logdrain_newrelic_license_key' => ['type' => 'string'],
|
||||
'metrics_history_days' => ['type' => 'integer'],
|
||||
'metrics_refresh_rate_seconds' => ['type' => 'integer'],
|
||||
'metrics_token' => ['type' => 'string'],
|
||||
'sentinel_metrics_history_days' => ['type' => 'integer'],
|
||||
'sentinel_metrics_refresh_rate_seconds' => ['type' => 'integer'],
|
||||
'sentinel_token' => ['type' => 'string'],
|
||||
'docker_cleanup_frequency' => ['type' => 'string'],
|
||||
'docker_cleanup_threshold' => ['type' => 'integer'],
|
||||
'server_id' => ['type' => 'integer'],
|
||||
@@ -53,8 +53,78 @@ class ServerSetting extends Model
|
||||
protected $casts = [
|
||||
'force_docker_cleanup' => 'boolean',
|
||||
'docker_cleanup_threshold' => 'integer',
|
||||
'sentinel_token' => 'encrypted',
|
||||
'is_reachable' => 'boolean',
|
||||
'is_usable' => 'boolean',
|
||||
];
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function ($setting) {
|
||||
try {
|
||||
if (str($setting->sentinel_token)->isEmpty()) {
|
||||
$setting->generateSentinelToken(save: false);
|
||||
}
|
||||
if (str($setting->sentinel_custom_url)->isEmpty()) {
|
||||
$setting->generateSentinelUrl(save: false);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
loggy('Error creating server setting: '.$e->getMessage());
|
||||
}
|
||||
});
|
||||
static::updated(function ($settings) {
|
||||
if (
|
||||
$settings->isDirty('sentinel_token') ||
|
||||
$settings->isDirty('sentinel_custom_url') ||
|
||||
$settings->isDirty('sentinel_metrics_refresh_rate_seconds') ||
|
||||
$settings->isDirty('sentinel_metrics_history_days') ||
|
||||
$settings->isDirty('sentinel_push_interval_seconds')
|
||||
) {
|
||||
$settings->server->restartSentinel();
|
||||
}
|
||||
if ($settings->isDirty('is_reachable')) {
|
||||
$settings->server->isReachableChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function generateSentinelToken(bool $save = true)
|
||||
{
|
||||
$data = [
|
||||
'server_uuid' => $this->server->uuid,
|
||||
];
|
||||
$token = json_encode($data);
|
||||
$encrypted = encrypt($token);
|
||||
$this->sentinel_token = $encrypted;
|
||||
if ($save) {
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function generateSentinelUrl(bool $save = true)
|
||||
{
|
||||
$domain = null;
|
||||
$settings = InstanceSettings::get();
|
||||
if ($this->server->isLocalhost()) {
|
||||
$domain = 'http://host.docker.internal:8000';
|
||||
} elseif ($settings->fqdn) {
|
||||
$domain = $settings->fqdn;
|
||||
} elseif ($settings->public_ipv4) {
|
||||
$domain = 'http://'.$settings->public_ipv4.':8000';
|
||||
} elseif ($settings->public_ipv6) {
|
||||
$domain = 'http://'.$settings->public_ipv6.':8000';
|
||||
}
|
||||
$this->sentinel_custom_url = $domain;
|
||||
loggy('Sentinel URL: '.$domain);
|
||||
if ($save) {
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
public function server()
|
||||
{
|
||||
return $this->belongsTo(Server::class);
|
||||
|
||||
@@ -297,7 +297,7 @@ class Service extends BaseModel
|
||||
'key' => 'CP_DISABLE_HTTPS',
|
||||
'value' => data_get($disable_https, 'value'),
|
||||
'rules' => 'required',
|
||||
'customHelper' => "If you want to use https, set this to 0. Variable name: CP_DISABLE_HTTPS",
|
||||
'customHelper' => 'If you want to use https, set this to 0. Variable name: CP_DISABLE_HTTPS',
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -319,7 +319,7 @@ class Service extends BaseModel
|
||||
if ($password) {
|
||||
$data = $data->merge([
|
||||
'Password' => [
|
||||
'key' => 'LABEL_STUDIO_PASSWORD',
|
||||
'key' => data_get($password, 'key'),
|
||||
'value' => data_get($password, 'value'),
|
||||
'rules' => 'required',
|
||||
'isPassword' => true,
|
||||
@@ -359,7 +359,7 @@ class Service extends BaseModel
|
||||
if ($email) {
|
||||
$data = $data->merge([
|
||||
'Admin Email' => [
|
||||
'key' => 'LANGFUSE_INIT_USER_EMAIL',
|
||||
'key' => data_get($email, 'key'),
|
||||
'value' => data_get($email, 'value'),
|
||||
'rules' => 'required|email',
|
||||
],
|
||||
@@ -370,7 +370,7 @@ class Service extends BaseModel
|
||||
if ($password) {
|
||||
$data = $data->merge([
|
||||
'Admin Password' => [
|
||||
'key' => 'LANGFUSE_INIT_USER_PASSWORD',
|
||||
'key' => data_get($password, 'key'),
|
||||
'value' => data_get($password, 'value'),
|
||||
'rules' => 'required',
|
||||
'isPassword' => true,
|
||||
@@ -384,7 +384,7 @@ class Service extends BaseModel
|
||||
$email = $this->environment_variables()->where('key', 'IN_USER_EMAIL')->first();
|
||||
$data = $data->merge([
|
||||
'Email' => [
|
||||
'key' => 'IN_USER_EMAIL',
|
||||
'key' => data_get($email, 'key'),
|
||||
'value' => data_get($email, 'value'),
|
||||
'rules' => 'required|email',
|
||||
],
|
||||
@@ -392,7 +392,7 @@ class Service extends BaseModel
|
||||
$password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_INVOICENINJAUSER')->first();
|
||||
$data = $data->merge([
|
||||
'Password' => [
|
||||
'key' => 'IN_PASSWORD',
|
||||
'key' => data_get($password, 'key'),
|
||||
'value' => data_get($password, 'value'),
|
||||
'rules' => 'required',
|
||||
'isPassword' => true,
|
||||
@@ -487,7 +487,7 @@ class Service extends BaseModel
|
||||
if ($admin_password) {
|
||||
$data = $data->merge([
|
||||
'Admin Password' => [
|
||||
'key' => 'SERVICE_PASSWORD_TOLGEE',
|
||||
'key' => data_get($admin_password, 'key'),
|
||||
'value' => data_get($admin_password, 'value'),
|
||||
'rules' => 'required',
|
||||
'isPassword' => true,
|
||||
@@ -534,7 +534,7 @@ class Service extends BaseModel
|
||||
if ($admin_password) {
|
||||
$data = $data->merge([
|
||||
'Admin Password' => [
|
||||
'key' => 'SERVICE_PASSWORD_UNLEASH',
|
||||
'key' => data_get($admin_password, 'key'),
|
||||
'value' => data_get($admin_password, 'value'),
|
||||
'rules' => 'required',
|
||||
'isPassword' => true,
|
||||
@@ -557,7 +557,7 @@ class Service extends BaseModel
|
||||
if ($admin_password) {
|
||||
$data = $data->merge([
|
||||
'Admin Password' => [
|
||||
'key' => 'GF_SECURITY_ADMIN_PASSWORD',
|
||||
'key' => data_get($admin_password, 'key'),
|
||||
'value' => data_get($admin_password, 'value'),
|
||||
'rules' => 'required',
|
||||
'isPassword' => true,
|
||||
@@ -919,7 +919,7 @@ class Service extends BaseModel
|
||||
if ($admin_user) {
|
||||
$data = $data->merge([
|
||||
'User' => [
|
||||
'key' => 'SERVICE_USER_ADMIN',
|
||||
'key' => data_get($admin_user, 'key'),
|
||||
'value' => data_get($admin_user, 'value', 'admin'),
|
||||
'readonly' => true,
|
||||
'rules' => 'required',
|
||||
@@ -929,7 +929,7 @@ class Service extends BaseModel
|
||||
if ($admin_password) {
|
||||
$data = $data->merge([
|
||||
'Password' => [
|
||||
'key' => 'SERVICE_PASSWORD_ADMIN',
|
||||
'key' => data_get($admin_password, 'key'),
|
||||
'value' => data_get($admin_password, 'value'),
|
||||
'rules' => 'required',
|
||||
'isPassword' => true,
|
||||
@@ -939,7 +939,7 @@ class Service extends BaseModel
|
||||
if ($admin_email) {
|
||||
$data = $data->merge([
|
||||
'Email' => [
|
||||
'key' => 'ADMIN_EMAIL',
|
||||
'key' => data_get($admin_email, 'key'),
|
||||
'value' => data_get($admin_email, 'value'),
|
||||
'rules' => 'required|email',
|
||||
],
|
||||
@@ -997,8 +997,8 @@ class Service extends BaseModel
|
||||
break;
|
||||
case $image->contains('mysql'):
|
||||
$userVariables = ['SERVICE_USER_MYSQL', 'SERVICE_USER_WORDPRESS', 'MYSQL_USER'];
|
||||
$passwordVariables = ['SERVICE_PASSWORD_MYSQL', 'SERVICE_PASSWORD_WORDPRESS', 'MYSQL_PASSWORD','SERVICE_PASSWORD_64_MYSQL'];
|
||||
$rootPasswordVariables = ['SERVICE_PASSWORD_MYSQLROOT', 'SERVICE_PASSWORD_ROOT','SERVICE_PASSWORD_64_MYSQLROOT'];
|
||||
$passwordVariables = ['SERVICE_PASSWORD_MYSQL', 'SERVICE_PASSWORD_WORDPRESS', 'MYSQL_PASSWORD', 'SERVICE_PASSWORD_64_MYSQL'];
|
||||
$rootPasswordVariables = ['SERVICE_PASSWORD_MYSQLROOT', 'SERVICE_PASSWORD_ROOT', 'SERVICE_PASSWORD_64_MYSQLROOT'];
|
||||
$dbNameVariables = ['MYSQL_DATABASE'];
|
||||
$mysql_user = $this->environment_variables()->whereIn('key', $userVariables)->first();
|
||||
$mysql_password = $this->environment_variables()->whereIn('key', $passwordVariables)->first();
|
||||
@@ -1232,7 +1232,6 @@ class Service extends BaseModel
|
||||
|
||||
public function environment_variables(): HasMany
|
||||
{
|
||||
|
||||
return $this->hasMany(EnvironmentVariable::class)->orderByRaw("LOWER(key) LIKE LOWER('SERVICE%') DESC, LOWER(key) ASC");
|
||||
}
|
||||
|
||||
@@ -1316,4 +1315,20 @@ class Service extends BaseModel
|
||||
|
||||
return $networks;
|
||||
}
|
||||
|
||||
protected function isDeployable(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
$envs = $this->environment_variables()->where('is_required', true)->get();
|
||||
foreach ($envs as $env) {
|
||||
if ($env->is_really_required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,33 +266,48 @@ class StandaloneClickhouse extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
|
||||
@@ -266,33 +266,48 @@ class StandaloneDragonfly extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
|
||||
@@ -266,33 +266,48 @@ class StandaloneKeydb extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
|
||||
@@ -266,33 +266,48 @@ class StandaloneMariadb extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
|
||||
@@ -286,33 +286,48 @@ class StandaloneMongodb extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
|
||||
@@ -267,33 +267,48 @@ class StandaloneMysql extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
|
||||
@@ -268,37 +268,52 @@ class StandalonePostgresql extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,12 @@ class StandaloneRedis extends BaseModel
|
||||
protected function internalDbUrl(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: fn () => "redis://:{$this->redis_password}@{$this->uuid}:6379/0",
|
||||
get: function () {
|
||||
$redis_version = $this->getRedisVersion();
|
||||
$username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
|
||||
|
||||
return "redis://{$username_part}{$this->redis_password}@{$this->uuid}:6379/0";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -219,7 +224,10 @@ class StandaloneRedis extends BaseModel
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
if ($this->is_public && $this->public_port) {
|
||||
return "redis://:{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
$redis_version = $this->getRedisVersion();
|
||||
$username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
|
||||
|
||||
return "redis://{$username_part}{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -227,6 +235,13 @@ class StandaloneRedis extends BaseModel
|
||||
);
|
||||
}
|
||||
|
||||
public function getRedisVersion()
|
||||
{
|
||||
$image_parts = explode(':', $this->image);
|
||||
|
||||
return $image_parts[1] ?? '0.0';
|
||||
}
|
||||
|
||||
public function environment()
|
||||
{
|
||||
return $this->belongsTo(Environment::class);
|
||||
@@ -262,37 +277,81 @@ class StandaloneRedis extends BaseModel
|
||||
return $this->morphMany(ScheduledDatabaseBackup::class, 'database');
|
||||
}
|
||||
|
||||
public function getMetrics(int $mins = 5)
|
||||
public function getCpuMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
if ($server->isMetricsEnabled()) {
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->metrics_token}\" http://localhost:8888/api/container/{$container_name}/metrics/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/cpu/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
$metrics = str($metrics)->explode("\n")->skip(1)->all();
|
||||
$parsedCollection = collect($metrics)->flatMap(function ($item) {
|
||||
return collect(explode("\n", trim($item)))->map(function ($line) {
|
||||
[$time, $cpu_usage_percent, $memory_usage, $memory_usage_percent] = explode(',', trim($line));
|
||||
$cpu_usage_percent = number_format($cpu_usage_percent, 2);
|
||||
|
||||
return [(int) $time, (float) $cpu_usage_percent, (int) $memory_usage];
|
||||
});
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['percent']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function getMemoryMetrics(int $mins = 5)
|
||||
{
|
||||
$server = $this->destination->server;
|
||||
$container_name = $this->uuid;
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$metrics = instant_remote_process(["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" http://localhost:8888/api/container/{$container_name}/memory/history?from=$from'"], $server, false);
|
||||
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') {
|
||||
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
||||
}
|
||||
throw new \Exception($error);
|
||||
}
|
||||
$metrics = json_decode($metrics, true);
|
||||
$parsedCollection = collect($metrics)->map(function ($metric) {
|
||||
return [(int) $metric['time'], (float) $metric['used']];
|
||||
});
|
||||
|
||||
return $parsedCollection->toArray();
|
||||
}
|
||||
|
||||
public function isBackupSolutionAvailable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function redisPassword(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
$password = $this->runtime_environment_variables()->where('key', 'REDIS_PASSWORD')->first();
|
||||
if (! $password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $password->value;
|
||||
},
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
public function redisUsername(): Attribute
|
||||
{
|
||||
return new Attribute(
|
||||
get: function () {
|
||||
$username = $this->runtime_environment_variables()->where('key', 'REDIS_USERNAME')->first();
|
||||
if (! $username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $username->value;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ use OpenApi\Attributes as OA;
|
||||
'smtp_notifications_status_changes' => ['type' => 'boolean', 'description' => 'Whether to send status change notifications via SMTP.'],
|
||||
'smtp_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via SMTP.'],
|
||||
'smtp_notifications_database_backups' => ['type' => 'boolean', 'description' => 'Whether to send database backup notifications via SMTP.'],
|
||||
'smtp_notifications_server_disk_usage' => ['type' => 'boolean', 'description' => 'Whether to send server disk usage notifications via SMTP.'],
|
||||
'discord_enabled' => ['type' => 'boolean', 'description' => 'Whether Discord is enabled or not.'],
|
||||
'discord_webhook_url' => ['type' => 'string', 'description' => 'The Discord webhook URL.'],
|
||||
'discord_notifications_test' => ['type' => 'boolean', 'description' => 'Whether to send test notifications via Discord.'],
|
||||
@@ -41,6 +42,7 @@ use OpenApi\Attributes as OA;
|
||||
'discord_notifications_status_changes' => ['type' => 'boolean', 'description' => 'Whether to send status change notifications via Discord.'],
|
||||
'discord_notifications_database_backups' => ['type' => 'boolean', 'description' => 'Whether to send database backup notifications via Discord.'],
|
||||
'discord_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via Discord.'],
|
||||
'discord_notifications_server_disk_usage' => ['type' => 'boolean', 'description' => 'Whether to send server disk usage notifications via Discord.'],
|
||||
'show_boarding' => ['type' => 'boolean', 'description' => 'Whether to show the boarding screen or not.'],
|
||||
'resend_enabled' => ['type' => 'boolean', 'description' => 'Whether to enable resending or not.'],
|
||||
'resend_api_key' => ['type' => 'string', 'description' => 'The resending API key.'],
|
||||
@@ -56,6 +58,7 @@ use OpenApi\Attributes as OA;
|
||||
'telegram_notifications_deployments_message_thread_id' => ['type' => 'string', 'description' => 'The Telegram deployment message thread ID.'],
|
||||
'telegram_notifications_status_changes_message_thread_id' => ['type' => 'string', 'description' => 'The Telegram status change message thread ID.'],
|
||||
'telegram_notifications_database_backups_message_thread_id' => ['type' => 'string', 'description' => 'The Telegram database backup message thread ID.'],
|
||||
|
||||
'custom_server_limit' => ['type' => 'string', 'description' => 'The custom server limit.'],
|
||||
'telegram_notifications_scheduled_tasks' => ['type' => 'boolean', 'description' => 'Whether to send scheduled task notifications via Telegram.'],
|
||||
'telegram_notifications_scheduled_tasks_thread_id' => ['type' => 'string', 'description' => 'The Telegram scheduled task message thread ID.'],
|
||||
@@ -164,8 +167,12 @@ class Team extends Model implements SendsDiscord, SendsEmail
|
||||
if (currentTeam()->id === 0 && isDev()) {
|
||||
return 9999999;
|
||||
}
|
||||
$team = Team::find(currentTeam()->id);
|
||||
if (! $team) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Team::find(currentTeam()->id)->limits['serverLimit'];
|
||||
return data_get($team, 'limits.serverLimit', 0);
|
||||
}
|
||||
|
||||
public function limits(): Attribute
|
||||
|
||||
@@ -20,6 +20,11 @@ class TeamInvitation extends Model
|
||||
return $this->belongsTo(Team::class);
|
||||
}
|
||||
|
||||
public static function ownedByCurrentTeam()
|
||||
{
|
||||
return TeamInvitation::whereTeamId(currentTeam()->id);
|
||||
}
|
||||
|
||||
public function isValid()
|
||||
{
|
||||
$createdAt = $this->created_at;
|
||||
|
||||
Reference in New Issue
Block a user