rector: arrrrr
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Actions\Application;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Models\Application;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class StopApplication
|
||||
@@ -23,7 +24,7 @@ class StopApplication
|
||||
if ($server->isSwarm()) {
|
||||
instant_remote_process(["docker stack rm {$application->uuid}"], $server);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$containersToStop = $application->getContainersToStop($previewDeployments);
|
||||
@@ -36,8 +37,10 @@ class StopApplication
|
||||
if ($dockerCleanup) {
|
||||
CleanupDocker::dispatch($server, true);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Application;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class StopApplicationOneServer
|
||||
@@ -13,7 +14,7 @@ class StopApplicationOneServer
|
||||
public function handle(Application $application, Server $server)
|
||||
{
|
||||
if ($application->destination->server->isSwarm()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (! $server->isFunctional()) {
|
||||
return 'Server is not functional';
|
||||
@@ -31,8 +32,10 @@ class StopApplicationOneServer
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\CoolifyTask;
|
||||
|
||||
use App\Data\CoolifyTaskArgs;
|
||||
use App\Jobs\CoolifyTask;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
/**
|
||||
@@ -17,36 +18,36 @@ class PrepareCoolifyTask
|
||||
|
||||
protected CoolifyTaskArgs $remoteProcessArgs;
|
||||
|
||||
public function __construct(CoolifyTaskArgs $remoteProcessArgs)
|
||||
public function __construct(CoolifyTaskArgs $coolifyTaskArgs)
|
||||
{
|
||||
$this->remoteProcessArgs = $remoteProcessArgs;
|
||||
$this->remoteProcessArgs = $coolifyTaskArgs;
|
||||
|
||||
if ($remoteProcessArgs->model) {
|
||||
$properties = $remoteProcessArgs->toArray();
|
||||
if ($coolifyTaskArgs->model instanceof Model) {
|
||||
$properties = $coolifyTaskArgs->toArray();
|
||||
unset($properties['model']);
|
||||
|
||||
$this->activity = activity()
|
||||
->withProperties($properties)
|
||||
->performedOn($remoteProcessArgs->model)
|
||||
->event($remoteProcessArgs->type)
|
||||
->performedOn($coolifyTaskArgs->model)
|
||||
->event($coolifyTaskArgs->type)
|
||||
->log('[]');
|
||||
} else {
|
||||
$this->activity = activity()
|
||||
->withProperties($remoteProcessArgs->toArray())
|
||||
->event($remoteProcessArgs->type)
|
||||
->withProperties($coolifyTaskArgs->toArray())
|
||||
->event($coolifyTaskArgs->type)
|
||||
->log('[]');
|
||||
}
|
||||
}
|
||||
|
||||
public function __invoke(): Activity
|
||||
{
|
||||
$job = new CoolifyTask(
|
||||
$coolifyTask = new CoolifyTask(
|
||||
activity: $this->activity,
|
||||
ignore_errors: $this->remoteProcessArgs->ignore_errors,
|
||||
call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish,
|
||||
call_event_data: $this->remoteProcessArgs->call_event_data,
|
||||
);
|
||||
dispatch($job);
|
||||
dispatch($coolifyTask);
|
||||
$this->activity->refresh();
|
||||
|
||||
return $this->activity;
|
||||
|
@@ -11,7 +11,10 @@ use Illuminate\Process\ProcessResult;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use JsonException;
|
||||
use RuntimeException;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
use Throwable;
|
||||
|
||||
class RunRemoteProcess
|
||||
{
|
||||
@@ -21,9 +24,9 @@ class RunRemoteProcess
|
||||
|
||||
public bool $ignore_errors;
|
||||
|
||||
public $call_event_on_finish = null;
|
||||
public $call_event_on_finish;
|
||||
|
||||
public $call_event_data = null;
|
||||
public $call_event_data;
|
||||
|
||||
protected $time_start;
|
||||
|
||||
@@ -41,7 +44,7 @@ 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.');
|
||||
throw new RuntimeException('Incompatible Activity to run a remote command.');
|
||||
}
|
||||
|
||||
$this->activity = $activity;
|
||||
@@ -63,7 +66,7 @@ class RunRemoteProcess
|
||||
associative: true,
|
||||
flags: JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE
|
||||
);
|
||||
} catch (\JsonException $exception) {
|
||||
} catch (JsonException $exception) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -79,12 +82,12 @@ class RunRemoteProcess
|
||||
|
||||
$status = ProcessStatus::IN_PROGRESS;
|
||||
$timeout = config('constants.ssh.command_timeout');
|
||||
$process = Process::timeout($timeout)->start($this->getCommand(), $this->handleOutput(...));
|
||||
$invokedProcess = Process::timeout($timeout)->start($this->getCommand(), $this->handleOutput(...));
|
||||
$this->activity->properties = $this->activity->properties->merge([
|
||||
'process_id' => $process->id(),
|
||||
'process_id' => $invokedProcess->id(),
|
||||
]);
|
||||
|
||||
$processResult = $process->wait();
|
||||
$processResult = $invokedProcess->wait();
|
||||
// $processResult = Process::timeout($timeout)->run($this->getCommand(), $this->handleOutput(...));
|
||||
if ($this->activity->properties->get('status') === ProcessStatus::ERROR->value) {
|
||||
$status = ProcessStatus::ERROR;
|
||||
@@ -111,7 +114,7 @@ class RunRemoteProcess
|
||||
]);
|
||||
$this->activity->save();
|
||||
if ($processResult->exitCode() != 0 && ! $this->ignore_errors) {
|
||||
throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode());
|
||||
throw new RuntimeException($processResult->errorOutput(), $processResult->exitCode());
|
||||
}
|
||||
if ($this->call_event_on_finish) {
|
||||
try {
|
||||
@@ -124,7 +127,7 @@ class RunRemoteProcess
|
||||
'userId' => $this->activity->causer_id,
|
||||
]));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
Log::error('Error calling event: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
@@ -16,9 +16,9 @@ class StartClickhouse
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandaloneClickhouse $database)
|
||||
public function handle(StandaloneClickhouse $standaloneClickhouse)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standaloneClickhouse;
|
||||
|
||||
$container_name = $this->database->uuid;
|
||||
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||
@@ -103,12 +103,12 @@ class StartClickhouse
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standaloneClickhouse->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standaloneClickhouse->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -25,28 +25,28 @@ class StartDatabase
|
||||
return 'Server is not functional';
|
||||
}
|
||||
switch ($database->getMorphClass()) {
|
||||
case \App\Models\StandalonePostgresql::class:
|
||||
case StandalonePostgresql::class:
|
||||
$activity = StartPostgresql::run($database);
|
||||
break;
|
||||
case \App\Models\StandaloneRedis::class:
|
||||
case StandaloneRedis::class:
|
||||
$activity = StartRedis::run($database);
|
||||
break;
|
||||
case \App\Models\StandaloneMongodb::class:
|
||||
case StandaloneMongodb::class:
|
||||
$activity = StartMongodb::run($database);
|
||||
break;
|
||||
case \App\Models\StandaloneMysql::class:
|
||||
case StandaloneMysql::class:
|
||||
$activity = StartMysql::run($database);
|
||||
break;
|
||||
case \App\Models\StandaloneMariadb::class:
|
||||
case StandaloneMariadb::class:
|
||||
$activity = StartMariadb::run($database);
|
||||
break;
|
||||
case \App\Models\StandaloneKeydb::class:
|
||||
case StandaloneKeydb::class:
|
||||
$activity = StartKeydb::run($database);
|
||||
break;
|
||||
case \App\Models\StandaloneDragonfly::class:
|
||||
case StandaloneDragonfly::class:
|
||||
$activity = StartDragonfly::run($database);
|
||||
break;
|
||||
case \App\Models\StandaloneClickhouse::class:
|
||||
case StandaloneClickhouse::class:
|
||||
$activity = StartClickhouse::run($database);
|
||||
break;
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ class StartDatabaseProxy
|
||||
$server = data_get($database, 'destination.server');
|
||||
$containerName = data_get($database, 'uuid');
|
||||
$proxyContainerName = "{$database->uuid}-proxy";
|
||||
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
|
||||
if ($database->getMorphClass() === ServiceDatabase::class) {
|
||||
$databaseType = $database->databaseType();
|
||||
// $connectPredefined = data_get($database, 'service.connect_to_docker_network');
|
||||
$network = $database->service->uuid;
|
||||
@@ -36,54 +36,54 @@ class StartDatabaseProxy
|
||||
$proxyContainerName = "{$database->service->uuid}-proxy";
|
||||
switch ($databaseType) {
|
||||
case 'standalone-mariadb':
|
||||
$type = \App\Models\StandaloneMariadb::class;
|
||||
$type = StandaloneMariadb::class;
|
||||
$containerName = "mariadb-{$database->service->uuid}";
|
||||
break;
|
||||
case 'standalone-mongodb':
|
||||
$type = \App\Models\StandaloneMongodb::class;
|
||||
$type = StandaloneMongodb::class;
|
||||
$containerName = "mongodb-{$database->service->uuid}";
|
||||
break;
|
||||
case 'standalone-mysql':
|
||||
$type = \App\Models\StandaloneMysql::class;
|
||||
$type = StandaloneMysql::class;
|
||||
$containerName = "mysql-{$database->service->uuid}";
|
||||
break;
|
||||
case 'standalone-postgresql':
|
||||
$type = \App\Models\StandalonePostgresql::class;
|
||||
$type = StandalonePostgresql::class;
|
||||
$containerName = "postgresql-{$database->service->uuid}";
|
||||
break;
|
||||
case 'standalone-redis':
|
||||
$type = \App\Models\StandaloneRedis::class;
|
||||
$type = StandaloneRedis::class;
|
||||
$containerName = "redis-{$database->service->uuid}";
|
||||
break;
|
||||
case 'standalone-keydb':
|
||||
$type = \App\Models\StandaloneKeydb::class;
|
||||
$type = StandaloneKeydb::class;
|
||||
$containerName = "keydb-{$database->service->uuid}";
|
||||
break;
|
||||
case 'standalone-dragonfly':
|
||||
$type = \App\Models\StandaloneDragonfly::class;
|
||||
$type = StandaloneDragonfly::class;
|
||||
$containerName = "dragonfly-{$database->service->uuid}";
|
||||
break;
|
||||
case 'standalone-clickhouse':
|
||||
$type = \App\Models\StandaloneClickhouse::class;
|
||||
$type = StandaloneClickhouse::class;
|
||||
$containerName = "clickhouse-{$database->service->uuid}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($type === \App\Models\StandaloneRedis::class) {
|
||||
if ($type === StandaloneRedis::class) {
|
||||
$internalPort = 6379;
|
||||
} elseif ($type === \App\Models\StandalonePostgresql::class) {
|
||||
} elseif ($type === StandalonePostgresql::class) {
|
||||
$internalPort = 5432;
|
||||
} elseif ($type === \App\Models\StandaloneMongodb::class) {
|
||||
} elseif ($type === StandaloneMongodb::class) {
|
||||
$internalPort = 27017;
|
||||
} elseif ($type === \App\Models\StandaloneMysql::class) {
|
||||
} elseif ($type === StandaloneMysql::class) {
|
||||
$internalPort = 3306;
|
||||
} elseif ($type === \App\Models\StandaloneMariadb::class) {
|
||||
} elseif ($type === StandaloneMariadb::class) {
|
||||
$internalPort = 3306;
|
||||
} elseif ($type === \App\Models\StandaloneKeydb::class) {
|
||||
} elseif ($type === StandaloneKeydb::class) {
|
||||
$internalPort = 6379;
|
||||
} elseif ($type === \App\Models\StandaloneDragonfly::class) {
|
||||
} elseif ($type === StandaloneDragonfly::class) {
|
||||
$internalPort = 6379;
|
||||
} elseif ($type === \App\Models\StandaloneClickhouse::class) {
|
||||
} elseif ($type === StandaloneClickhouse::class) {
|
||||
$internalPort = 9000;
|
||||
}
|
||||
$configuration_dir = database_proxy_dir($database->uuid);
|
||||
|
@@ -16,9 +16,9 @@ class StartDragonfly
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandaloneDragonfly $database)
|
||||
public function handle(StandaloneDragonfly $standaloneDragonfly)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standaloneDragonfly;
|
||||
|
||||
$startCommand = "dragonfly --requirepass {$this->database->dragonfly_password}";
|
||||
|
||||
@@ -100,12 +100,12 @@ class StartDragonfly
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standaloneDragonfly->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standaloneDragonfly->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -17,9 +17,9 @@ class StartKeydb
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandaloneKeydb $database)
|
||||
public function handle(StandaloneKeydb $standaloneKeydb)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standaloneKeydb;
|
||||
|
||||
$startCommand = "keydb-server --requirepass {$this->database->keydb_password} --appendonly yes";
|
||||
|
||||
@@ -92,7 +92,7 @@ class StartKeydb
|
||||
if (count($volume_names) > 0) {
|
||||
$docker_compose['volumes'] = $volume_names;
|
||||
}
|
||||
if (! is_null($this->database->keydb_conf) || ! empty($this->database->keydb_conf)) {
|
||||
if (! is_null($this->database->keydb_conf) || $this->database->keydb_conf !== null) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
'source' => $this->configuration_dir.'/keydb.conf',
|
||||
@@ -110,12 +110,12 @@ class StartKeydb
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standaloneKeydb->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standaloneKeydb->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -16,9 +16,9 @@ class StartMariadb
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandaloneMariadb $database)
|
||||
public function handle(StandaloneMariadb $standaloneMariadb)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standaloneMariadb;
|
||||
|
||||
$container_name = $this->database->uuid;
|
||||
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||
@@ -87,7 +87,7 @@ class StartMariadb
|
||||
if (count($volume_names) > 0) {
|
||||
$docker_compose['volumes'] = $volume_names;
|
||||
}
|
||||
if (! is_null($this->database->mariadb_conf) || ! empty($this->database->mariadb_conf)) {
|
||||
if (! is_null($this->database->mariadb_conf) || $this->database->mariadb_conf !== null) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
'source' => $this->configuration_dir.'/custom-config.cnf',
|
||||
@@ -105,12 +105,12 @@ class StartMariadb
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standaloneMariadb->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standaloneMariadb->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -16,9 +16,9 @@ class StartMongodb
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandaloneMongodb $database)
|
||||
public function handle(StandaloneMongodb $standaloneMongodb)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standaloneMongodb;
|
||||
|
||||
$startCommand = 'mongod';
|
||||
|
||||
@@ -99,7 +99,7 @@ class StartMongodb
|
||||
if (count($volume_names) > 0) {
|
||||
$docker_compose['volumes'] = $volume_names;
|
||||
}
|
||||
if (! is_null($this->database->mongo_conf) || ! empty($this->database->mongo_conf)) {
|
||||
if (! is_null($this->database->mongo_conf) || $this->database->mongo_conf !== null) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
'source' => $this->configuration_dir.'/mongod.conf',
|
||||
@@ -125,12 +125,12 @@ class StartMongodb
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standaloneMongodb->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standaloneMongodb->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -16,9 +16,9 @@ class StartMysql
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandaloneMysql $database)
|
||||
public function handle(StandaloneMysql $standaloneMysql)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standaloneMysql;
|
||||
|
||||
$container_name = $this->database->uuid;
|
||||
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||
@@ -87,7 +87,7 @@ class StartMysql
|
||||
if (count($volume_names) > 0) {
|
||||
$docker_compose['volumes'] = $volume_names;
|
||||
}
|
||||
if (! is_null($this->database->mysql_conf) || ! empty($this->database->mysql_conf)) {
|
||||
if (! is_null($this->database->mysql_conf) || $this->database->mysql_conf !== null) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
'source' => $this->configuration_dir.'/custom-config.cnf',
|
||||
@@ -105,12 +105,12 @@ class StartMysql
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standaloneMysql->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standaloneMysql->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -18,9 +18,9 @@ class StartPostgresql
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandalonePostgresql $database)
|
||||
public function handle(StandalonePostgresql $standalonePostgresql)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standalonePostgresql;
|
||||
$container_name = $this->database->uuid;
|
||||
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||
if (isDev()) {
|
||||
@@ -97,7 +97,6 @@ class StartPostgresql
|
||||
if (count($volume_names) > 0) {
|
||||
$docker_compose['volumes'] = $volume_names;
|
||||
}
|
||||
if (count($this->init_scripts) > 0) {
|
||||
foreach ($this->init_scripts as $init_script) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
@@ -106,7 +105,6 @@ class StartPostgresql
|
||||
'read_only' => true,
|
||||
];
|
||||
}
|
||||
}
|
||||
if (filled($this->database->postgres_conf)) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
@@ -129,12 +127,12 @@ class StartPostgresql
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standalonePostgresql->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standalonePostgresql->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -17,9 +17,9 @@ class StartRedis
|
||||
|
||||
public string $configuration_dir;
|
||||
|
||||
public function handle(StandaloneRedis $database)
|
||||
public function handle(StandaloneRedis $standaloneRedis)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->database = $standaloneRedis;
|
||||
|
||||
$container_name = $this->database->uuid;
|
||||
$this->configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||
@@ -96,7 +96,7 @@ class StartRedis
|
||||
if (count($volume_names) > 0) {
|
||||
$docker_compose['volumes'] = $volume_names;
|
||||
}
|
||||
if (! is_null($this->database->redis_conf) || ! empty($this->database->redis_conf)) {
|
||||
if (! is_null($this->database->redis_conf) || $this->database->redis_conf !== null) {
|
||||
$docker_compose['services'][$container_name]['volumes'][] = [
|
||||
'type' => 'bind',
|
||||
'source' => $this->configuration_dir.'/redis.conf',
|
||||
@@ -114,12 +114,12 @@ class StartRedis
|
||||
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
|
||||
$readme = generate_readme_file($this->database->name, now());
|
||||
$this->commands[] = "echo '{$readme}' > $this->configuration_dir/README.md";
|
||||
$this->commands[] = "echo 'Pulling {$database->image} image.'";
|
||||
$this->commands[] = "echo 'Pulling {$standaloneRedis->image} image.'";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo 'Database started.'";
|
||||
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $standaloneRedis->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
@@ -26,11 +26,9 @@ class StopDatabase
|
||||
}
|
||||
|
||||
$this->stopContainer($database, $database->uuid, 300);
|
||||
if (! $isDeleteOperation) {
|
||||
if ($dockerCleanup) {
|
||||
if (! $isDeleteOperation && $dockerCleanup) {
|
||||
CleanupDocker::dispatch($server, true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($database->is_public) {
|
||||
StopDatabaseProxy::run($database);
|
||||
@@ -43,10 +41,10 @@ class StopDatabase
|
||||
{
|
||||
$server = $database->destination->server;
|
||||
|
||||
$process = Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
|
||||
$invokedProcess = Process::timeout($timeout)->start("docker stop --time=$timeout $containerName");
|
||||
|
||||
$startTime = time();
|
||||
while ($process->running()) {
|
||||
while ($invokedProcess->running()) {
|
||||
if (time() - $startTime >= $timeout) {
|
||||
$this->forceStopContainer($containerName, $server);
|
||||
break;
|
||||
@@ -66,10 +64,4 @@ class StopDatabase
|
||||
{
|
||||
instant_remote_process(command: ["docker rm -f $containerName"], server: $server, throwError: false);
|
||||
}
|
||||
|
||||
private function deleteConnectedNetworks($uuid, $server)
|
||||
{
|
||||
instant_remote_process(["docker network disconnect {$uuid} coolify-proxy"], $server, false);
|
||||
instant_remote_process(["docker network rm {$uuid}"], $server, false);
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ class StopDatabaseProxy
|
||||
{
|
||||
$server = data_get($database, 'destination.server');
|
||||
$uuid = $database->uuid;
|
||||
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
|
||||
if ($database->getMorphClass() === ServiceDatabase::class) {
|
||||
$uuid = $database->service->uuid;
|
||||
$server = data_get($database, 'service.server');
|
||||
}
|
||||
|
@@ -47,20 +47,20 @@ class GetContainersStatus
|
||||
$this->applications = $this->applications->filter(function ($value, $key) use ($skip_these_applications) {
|
||||
return ! $skip_these_applications->pluck('id')->contains($value->id);
|
||||
});
|
||||
if ($this->containers === null) {
|
||||
if (! $this->containers instanceof Collection) {
|
||||
['containers' => $this->containers, 'containerReplicates' => $this->containerReplicates] = $this->server->getContainers();
|
||||
}
|
||||
|
||||
if (is_null($this->containers)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->containerReplicates) {
|
||||
foreach ($this->containerReplicates as $containerReplica) {
|
||||
$name = data_get($containerReplica, 'Name');
|
||||
$this->containers = $this->containers->map(function ($container) use ($name, $containerReplica) {
|
||||
foreach ($this->containerReplicates as $containerReplicate) {
|
||||
$name = data_get($containerReplicate, 'Name');
|
||||
$this->containers = $this->containers->map(function ($container) use ($name, $containerReplicate) {
|
||||
if (data_get($container, 'Spec.Name') === $name) {
|
||||
$replicas = data_get($containerReplica, 'Replicas');
|
||||
$replicas = data_get($containerReplicate, 'Replicas');
|
||||
$running = str($replicas)->explode('/')[0];
|
||||
$total = str($replicas)->explode('/')[1];
|
||||
if ($running === $total) {
|
||||
@@ -102,7 +102,7 @@ class GetContainersStatus
|
||||
if (str($applicationId)->contains('-')) {
|
||||
$applicationId = str($applicationId)->before('-');
|
||||
}
|
||||
$preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
||||
$preview = ApplicationPreview::query()->where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
||||
if ($preview) {
|
||||
$foundApplicationPreviews[] = $preview->id;
|
||||
$statusFromDb = $preview->status;
|
||||
@@ -136,7 +136,7 @@ class GetContainersStatus
|
||||
if ($type === 'service') {
|
||||
$database_id = data_get($labels, 'coolify.service.subId');
|
||||
if ($database_id) {
|
||||
$service_db = ServiceDatabase::where('id', $database_id)->first();
|
||||
$service_db = ServiceDatabase::query()->where('id', $database_id)->first();
|
||||
if ($service_db) {
|
||||
$uuid = data_get($service_db, 'service.uuid');
|
||||
if ($uuid) {
|
||||
@@ -145,9 +145,9 @@ class GetContainersStatus
|
||||
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||
if ($this->server->isSwarm()) {
|
||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||
} else {
|
||||
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||
}
|
||||
|
||||
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||
})->first();
|
||||
if (! $foundTcpProxy) {
|
||||
StartDatabaseProxy::run($service_db);
|
||||
@@ -173,9 +173,9 @@ class GetContainersStatus
|
||||
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||
if ($this->server->isSwarm()) {
|
||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||
} else {
|
||||
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||
}
|
||||
|
||||
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||
})->first();
|
||||
if (! $foundTcpProxy) {
|
||||
StartDatabaseProxy::run($database);
|
||||
@@ -223,16 +223,14 @@ class GetContainersStatus
|
||||
foreach ($apps as $app) {
|
||||
if (in_array("$app->id-$app->name", $foundServices)) {
|
||||
continue;
|
||||
} else {
|
||||
$exitedServices->push($app);
|
||||
}
|
||||
$exitedServices->push($app);
|
||||
}
|
||||
foreach ($dbs as $db) {
|
||||
if (in_array("$db->id-$db->name", $foundServices)) {
|
||||
continue;
|
||||
} else {
|
||||
$exitedServices->push($db);
|
||||
}
|
||||
$exitedServices->push($db);
|
||||
}
|
||||
}
|
||||
$exitedServices = $exitedServices->unique('uuid');
|
||||
@@ -243,18 +241,12 @@ class GetContainersStatus
|
||||
$name = data_get($exitedService, 'name');
|
||||
$fqdn = data_get($exitedService, 'fqdn');
|
||||
if ($name) {
|
||||
if ($fqdn) {
|
||||
$containerName = "$name, available at $fqdn";
|
||||
} else {
|
||||
$containerName = $name;
|
||||
}
|
||||
} else {
|
||||
if ($fqdn) {
|
||||
$containerName = $fqdn ? "$name, available at $fqdn" : $name;
|
||||
} elseif ($fqdn) {
|
||||
$containerName = $fqdn;
|
||||
} else {
|
||||
$containerName = null;
|
||||
}
|
||||
}
|
||||
$projectUuid = data_get($service, 'environment.project.uuid');
|
||||
$serviceUuid = data_get($service, 'uuid');
|
||||
$environmentName = data_get($service, 'environment.name');
|
||||
@@ -269,8 +261,8 @@ class GetContainersStatus
|
||||
}
|
||||
|
||||
$notRunningApplications = $this->applications->pluck('id')->diff($foundApplications);
|
||||
foreach ($notRunningApplications as $applicationId) {
|
||||
$application = $this->applications->where('id', $applicationId)->first();
|
||||
foreach ($notRunningApplications as $notRunningApplication) {
|
||||
$application = $this->applications->where('id', $notRunningApplication)->first();
|
||||
if (str($application->status)->startsWith('exited')) {
|
||||
continue;
|
||||
}
|
||||
@@ -294,8 +286,8 @@ class GetContainersStatus
|
||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||
}
|
||||
$notRunningApplicationPreviews = $previews->pluck('id')->diff($foundApplicationPreviews);
|
||||
foreach ($notRunningApplicationPreviews as $previewId) {
|
||||
$preview = $previews->where('id', $previewId)->first();
|
||||
foreach ($notRunningApplicationPreviews as $notRunningApplicationPreview) {
|
||||
$preview = $previews->where('id', $notRunningApplicationPreview)->first();
|
||||
if (str($preview->status)->startsWith('exited')) {
|
||||
continue;
|
||||
}
|
||||
@@ -319,21 +311,21 @@ class GetContainersStatus
|
||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||
}
|
||||
$notRunningDatabases = $databases->pluck('id')->diff($foundDatabases);
|
||||
foreach ($notRunningDatabases as $database) {
|
||||
$database = $databases->where('id', $database)->first();
|
||||
if (str($database->status)->startsWith('exited')) {
|
||||
foreach ($notRunningDatabases as $notRunningDatabase) {
|
||||
$notRunningDatabase = $databases->where('id', $notRunningDatabase)->first();
|
||||
if (str($notRunningDatabase->status)->startsWith('exited')) {
|
||||
continue;
|
||||
}
|
||||
$database->update(['status' => 'exited']);
|
||||
$notRunningDatabase->update(['status' => 'exited']);
|
||||
|
||||
$name = data_get($database, 'name');
|
||||
$fqdn = data_get($database, 'fqdn');
|
||||
$name = data_get($notRunningDatabase, 'name');
|
||||
$fqdn = data_get($notRunningDatabase, 'fqdn');
|
||||
|
||||
$containerName = $name;
|
||||
|
||||
$projectUuid = data_get($database, 'environment.project.uuid');
|
||||
$environmentName = data_get($database, 'environment.name');
|
||||
$databaseUuid = data_get($database, 'uuid');
|
||||
$projectUuid = data_get($notRunningDatabase, 'environment.project.uuid');
|
||||
$environmentName = data_get($notRunningDatabase, 'environment.name');
|
||||
$databaseUuid = data_get($notRunningDatabase, 'uuid');
|
||||
|
||||
if ($projectUuid && $databaseUuid && $environmentName) {
|
||||
$url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid;
|
||||
@@ -342,5 +334,7 @@ class GetContainersStatus
|
||||
}
|
||||
// $this->server->team?->notify(new ContainerStopped($containerName, $this->server, $url));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -34,10 +34,10 @@ class CreateNewUser implements CreatesNewUsers
|
||||
'password' => ['required', Password::defaults(), 'confirmed'],
|
||||
])->validate();
|
||||
|
||||
if (User::count() == 0) {
|
||||
if (User::query()->count() == 0) {
|
||||
// If this is the first user, make them the root user
|
||||
// Team is already created in the database/seeders/ProductionSeeder.php
|
||||
$user = User::create([
|
||||
$user = User::query()->create([
|
||||
'id' => 0,
|
||||
'name' => $input['name'],
|
||||
'email' => strtolower($input['email']),
|
||||
@@ -50,7 +50,7 @@ class CreateNewUser implements CreatesNewUsers
|
||||
$settings->is_registration_enabled = false;
|
||||
$settings->save();
|
||||
} else {
|
||||
$user = User::create([
|
||||
$user = User::query()->create([
|
||||
'name' => $input['name'],
|
||||
'email' => strtolower($input['email']),
|
||||
'password' => Hash::make($input['password']),
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class CheckConfiguration
|
||||
@@ -25,7 +26,7 @@ class CheckConfiguration
|
||||
$proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value();
|
||||
}
|
||||
if (! $proxy_configuration || is_null($proxy_configuration)) {
|
||||
throw new \Exception('Could not generate proxy configuration');
|
||||
throw new Exception('Could not generate proxy configuration');
|
||||
}
|
||||
|
||||
return $proxy_configuration;
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Proxy;
|
||||
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -32,25 +33,22 @@ class CheckProxy
|
||||
}
|
||||
['uptime' => $uptime, 'error' => $error] = $server->validateConnection();
|
||||
if (! $uptime) {
|
||||
throw new \Exception($error);
|
||||
throw new Exception($error);
|
||||
}
|
||||
if (! $server->isProxyShouldRun()) {
|
||||
if ($fromUI) {
|
||||
throw new \Exception('Proxy should not run. You selected the Custom Proxy.');
|
||||
} else {
|
||||
return false;
|
||||
throw new Exception('Proxy should not run. You selected the Custom Proxy.');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($server->isSwarm()) {
|
||||
$status = getContainerStatus($server, 'coolify-proxy_traefik');
|
||||
$server->proxy->set('status', $status);
|
||||
$server->save();
|
||||
if ($status === 'running') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return $status !== 'running';
|
||||
}
|
||||
$status = getContainerStatus($server, 'coolify-proxy');
|
||||
if ($status === 'running') {
|
||||
$server->proxy->set('status', 'running');
|
||||
@@ -65,9 +63,7 @@ class CheckProxy
|
||||
if ($server->id === 0) {
|
||||
$ip = 'host.docker.internal';
|
||||
}
|
||||
|
||||
$portsToCheck = ['80', '443'];
|
||||
|
||||
try {
|
||||
if ($server->proxyType() !== ProxyTypes::NONE->value) {
|
||||
$proxyCompose = CheckConfiguration::run($server);
|
||||
@@ -88,24 +84,23 @@ class CheckProxy
|
||||
} else {
|
||||
$portsToCheck = [];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
Log::error('Error checking proxy: '.$e->getMessage());
|
||||
}
|
||||
if (count($portsToCheck) === 0) {
|
||||
if ($portsToCheck === []) {
|
||||
return false;
|
||||
}
|
||||
foreach ($portsToCheck as $port) {
|
||||
$connection = @fsockopen($ip, $port);
|
||||
foreach ($portsToCheck as $portToCheck) {
|
||||
$connection = @fsockopen($ip, $portToCheck);
|
||||
if (is_resource($connection) && fclose($connection)) {
|
||||
if ($fromUI) {
|
||||
throw new \Exception("Port $port is in use.<br>You must stop the process using this port.<br>Docs: <a target='_blank' href='https://coolify.io/docs'>https://coolify.io/docs</a><br>Discord: <a target='_blank' href='https://coollabs.io/discord'>https://coollabs.io/discord</a>");
|
||||
} else {
|
||||
return false;
|
||||
throw new Exception("Port {$portToCheck} is in use.<br>You must stop the process using this port.<br>Docs: <a target='_blank' href='https://coolify.io/docs'>https://coolify.io/docs</a><br>Discord: <a target='_blank' href='https://coollabs.io/discord'>https://coollabs.io/discord</a>");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ namespace App\Actions\Proxy;
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Events\ProxyStarted;
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
@@ -22,7 +23,7 @@ class StartProxy
|
||||
$proxy_path = $server->proxyPath();
|
||||
$configuration = CheckConfiguration::run($server);
|
||||
if (! $configuration) {
|
||||
throw new \Exception('Configuration is not synced');
|
||||
throw new Exception('Configuration is not synced');
|
||||
}
|
||||
SaveConfiguration::run($server, $configuration);
|
||||
$docker_compose_yml_base64 = base64_encode($configuration);
|
||||
@@ -38,11 +39,9 @@ class StartProxy
|
||||
"echo 'Successfully started coolify-proxy.'",
|
||||
]);
|
||||
} else {
|
||||
if (isDev()) {
|
||||
if ($proxyType === ProxyTypes::CADDY->value) {
|
||||
if (isDev() && $proxyType === ProxyTypes::CADDY->value) {
|
||||
$proxy_path = '/data/coolify/proxy/caddy';
|
||||
}
|
||||
}
|
||||
$caddyfile = 'import /dynamic/*.caddy';
|
||||
$commands = $commands->merge([
|
||||
"mkdir -p $proxy_path/dynamic",
|
||||
@@ -65,7 +64,7 @@ class StartProxy
|
||||
|
||||
if ($async) {
|
||||
return remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server);
|
||||
} else {
|
||||
}
|
||||
instant_remote_process($commands, $server);
|
||||
$server->proxy->set('status', 'running');
|
||||
$server->proxy->set('type', $proxyType);
|
||||
@@ -75,4 +74,3 @@ class StartProxy
|
||||
return 'OK';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ use App\Events\CloudflareTunnelConfigured;
|
||||
use App\Models\Server;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Throwable;
|
||||
|
||||
class ConfigureCloudflared
|
||||
{
|
||||
@@ -39,7 +40,7 @@ class ConfigureCloudflared
|
||||
'docker compose up -d --remove-orphans',
|
||||
]);
|
||||
instant_remote_process($commands, $server);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$server->settings->is_cloudflare_tunnel = false;
|
||||
$server->settings->save();
|
||||
throw $e;
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\StandaloneDocker;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class InstallDocker
|
||||
@@ -15,7 +16,7 @@ class InstallDocker
|
||||
$dockerVersion = config('constants.docker.minimum_required_version');
|
||||
$supported_os_type = $server->validateOS();
|
||||
if (! $supported_os_type) {
|
||||
throw new \Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
|
||||
throw new Exception('Server OS type is not supported for automated installation. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://coolify.io/docs/installation#manually">documentation</a>.');
|
||||
}
|
||||
$config = base64_encode('{
|
||||
"log-driver": "json-file",
|
||||
@@ -24,9 +25,9 @@ class InstallDocker
|
||||
"max-file": "3"
|
||||
}
|
||||
}');
|
||||
$found = StandaloneDocker::where('server_id', $server->id);
|
||||
if ($found->count() == 0 && $server->id) {
|
||||
StandaloneDocker::create([
|
||||
$builder = StandaloneDocker::query()->where('server_id', $server->id);
|
||||
if ($builder->count() == 0 && $server->id) {
|
||||
StandaloneDocker::query()->create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
@@ -45,7 +46,7 @@ class InstallDocker
|
||||
]);
|
||||
|
||||
return remote_process($command, $server);
|
||||
} else {
|
||||
}
|
||||
if ($supported_os_type->contains('debian')) {
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Prerequisites...'",
|
||||
@@ -73,7 +74,7 @@ class InstallDocker
|
||||
'command -v jq >/dev/null || zypper install -y jq',
|
||||
]);
|
||||
} else {
|
||||
throw new \Exception('Unsupported OS');
|
||||
throw new Exception('Unsupported OS');
|
||||
}
|
||||
$command = $command->merge([
|
||||
"echo 'Installing Docker Engine...'",
|
||||
@@ -106,4 +107,3 @@ class InstallDocker
|
||||
return remote_process($command, $server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ use App\Models\StandaloneMysql;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Models\StandaloneRedis;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Throwable;
|
||||
|
||||
class ResourcesCheck
|
||||
{
|
||||
@@ -23,19 +24,21 @@ class ResourcesCheck
|
||||
{
|
||||
$seconds = 60;
|
||||
try {
|
||||
Application::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
ServiceApplication::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
ServiceDatabase::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandalonePostgresql::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneRedis::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneMongodb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneMysql::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneMariadb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneKeydb::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneDragonfly::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneClickhouse::where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
} catch (\Throwable $e) {
|
||||
Application::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
ServiceApplication::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
ServiceDatabase::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandalonePostgresql::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneRedis::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneMongodb::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneMysql::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneMariadb::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneKeydb::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneDragonfly::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
StandaloneClickhouse::query()->where('last_online_at', '<', now()->subSeconds($seconds))->update(['status' => 'exited']);
|
||||
} catch (Throwable $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ use App\Models\ServiceDatabase;
|
||||
use App\Notifications\Container\ContainerRestarted;
|
||||
use Illuminate\Support\Arr;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Throwable;
|
||||
|
||||
class ServerCheck
|
||||
{
|
||||
@@ -61,11 +62,11 @@ class ServerCheck
|
||||
}
|
||||
|
||||
if (isset($containerReplicates)) {
|
||||
foreach ($containerReplicates as $containerReplica) {
|
||||
$name = data_get($containerReplica, 'Name');
|
||||
$this->containers = $this->containers->map(function ($container) use ($name, $containerReplica) {
|
||||
foreach ($containerReplicates as $containerReplicate) {
|
||||
$name = data_get($containerReplicate, 'Name');
|
||||
$this->containers = $this->containers->map(function ($container) use ($name, $containerReplicate) {
|
||||
if (data_get($container, 'Spec.Name') === $name) {
|
||||
$replicas = data_get($containerReplica, 'Replicas');
|
||||
$replicas = data_get($containerReplicate, 'Replicas');
|
||||
$running = str($replicas)->explode('/')[0];
|
||||
$total = str($replicas)->explode('/')[1];
|
||||
if ($running === $total) {
|
||||
@@ -95,9 +96,9 @@ class ServerCheck
|
||||
$foundProxyContainer = $this->containers->filter(function ($value, $key) {
|
||||
if ($this->server->isSwarm()) {
|
||||
return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
|
||||
} else {
|
||||
return data_get($value, 'Name') === '/coolify-proxy';
|
||||
}
|
||||
|
||||
return data_get($value, 'Name') === '/coolify-proxy';
|
||||
})->first();
|
||||
if (! $foundProxyContainer) {
|
||||
try {
|
||||
@@ -106,7 +107,7 @@ class ServerCheck
|
||||
StartProxy::run($this->server, false);
|
||||
$this->server->team?->notify(new ContainerRestarted('coolify-proxy', $this->server));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
}
|
||||
} else {
|
||||
$this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
|
||||
@@ -116,9 +117,11 @@ class ServerCheck
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function checkLogDrainContainer()
|
||||
@@ -141,13 +144,11 @@ class ServerCheck
|
||||
foreach ($this->containers as $container) {
|
||||
if ($this->isSentinel) {
|
||||
$labels = Arr::undot(data_get($container, 'labels'));
|
||||
} else {
|
||||
if ($this->server->isSwarm()) {
|
||||
} elseif ($this->server->isSwarm()) {
|
||||
$labels = Arr::undot(data_get($container, 'Spec.Labels'));
|
||||
} else {
|
||||
$labels = Arr::undot(data_get($container, 'Config.Labels'));
|
||||
}
|
||||
}
|
||||
$managed = data_get($labels, 'coolify.managed');
|
||||
if (! $managed) {
|
||||
continue;
|
||||
@@ -177,12 +178,12 @@ class ServerCheck
|
||||
if (str($applicationId)->contains('-')) {
|
||||
$applicationId = str($applicationId)->before('-');
|
||||
}
|
||||
$preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
||||
$preview = ApplicationPreview::query()->where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
||||
if ($preview) {
|
||||
$preview->update(['status' => $containerStatus]);
|
||||
}
|
||||
} else {
|
||||
$application = Application::where('id', $applicationId)->first();
|
||||
$application = Application::query()->where('id', $applicationId)->first();
|
||||
if ($application) {
|
||||
$application->update([
|
||||
'status' => $containerStatus,
|
||||
@@ -194,14 +195,14 @@ class ServerCheck
|
||||
// Service
|
||||
$subType = data_get($labels, 'coolify.service.subType');
|
||||
$subId = data_get($labels, 'coolify.service.subId');
|
||||
$service = Service::where('id', $serviceId)->first();
|
||||
$service = Service::query()->where('id', $serviceId)->first();
|
||||
if (! $service) {
|
||||
continue;
|
||||
}
|
||||
if ($subType === 'application') {
|
||||
$service = ServiceApplication::where('id', $subId)->first();
|
||||
$service = ServiceApplication::query()->where('id', $subId)->first();
|
||||
} else {
|
||||
$service = ServiceDatabase::where('id', $subId)->first();
|
||||
$service = ServiceDatabase::query()->where('id', $subId)->first();
|
||||
}
|
||||
if ($service) {
|
||||
$service->update([
|
||||
@@ -214,14 +215,12 @@ class ServerCheck
|
||||
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||
if ($this->isSentinel) {
|
||||
return data_get($value, 'name') === $uuid.'-proxy';
|
||||
} else {
|
||||
|
||||
}
|
||||
if ($this->server->isSwarm()) {
|
||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||
} else {
|
||||
}
|
||||
|
||||
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||
}
|
||||
}
|
||||
})->first();
|
||||
if (! $foundTcpProxy) {
|
||||
StartDatabaseProxy::run($service);
|
||||
@@ -246,14 +245,12 @@ class ServerCheck
|
||||
$foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) {
|
||||
if ($this->isSentinel) {
|
||||
return data_get($value, 'name') === $uuid.'-proxy';
|
||||
} else {
|
||||
}
|
||||
if ($this->server->isSwarm()) {
|
||||
return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid";
|
||||
} else {
|
||||
}
|
||||
|
||||
return data_get($value, 'Name') === "/$uuid-proxy";
|
||||
}
|
||||
}
|
||||
})->first();
|
||||
if (! $foundTcpProxy) {
|
||||
StartDatabaseProxy::run($database);
|
||||
|
@@ -3,7 +3,9 @@
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Throwable;
|
||||
|
||||
class StartLogDrain
|
||||
{
|
||||
@@ -31,9 +33,10 @@ class StartLogDrain
|
||||
try {
|
||||
if ($type === 'none') {
|
||||
return 'No log drain is enabled.';
|
||||
} elseif ($type === 'newrelic') {
|
||||
}
|
||||
if ($type === 'newrelic') {
|
||||
if (! $server->settings->is_logdrain_newrelic_enabled) {
|
||||
throw new \Exception('New Relic log drain is not enabled.');
|
||||
throw new Exception('New Relic log drain is not enabled.');
|
||||
}
|
||||
$config = base64_encode("
|
||||
[SERVICE]
|
||||
@@ -68,7 +71,7 @@ class StartLogDrain
|
||||
");
|
||||
} elseif ($type === 'highlight') {
|
||||
if (! $server->settings->is_logdrain_highlight_enabled) {
|
||||
throw new \Exception('Highlight log drain is not enabled.');
|
||||
throw new Exception('Highlight log drain is not enabled.');
|
||||
}
|
||||
$config = base64_encode('
|
||||
[SERVICE]
|
||||
@@ -89,7 +92,7 @@ class StartLogDrain
|
||||
');
|
||||
} elseif ($type === 'axiom') {
|
||||
if (! $server->settings->is_logdrain_axiom_enabled) {
|
||||
throw new \Exception('Axiom log drain is not enabled.');
|
||||
throw new Exception('Axiom log drain is not enabled.');
|
||||
}
|
||||
$config = base64_encode("
|
||||
[SERVICE]
|
||||
@@ -129,12 +132,12 @@ class StartLogDrain
|
||||
");
|
||||
} elseif ($type === 'custom') {
|
||||
if (! $server->settings->is_logdrain_custom_enabled) {
|
||||
throw new \Exception('Custom log drain is not enabled.');
|
||||
throw new Exception('Custom log drain is not enabled.');
|
||||
}
|
||||
$config = base64_encode($server->settings->logdrain_custom_config);
|
||||
$parsers = base64_encode($server->settings->logdrain_custom_config_parser);
|
||||
} else {
|
||||
throw new \Exception('Unknown log drain type.');
|
||||
throw new Exception('Unknown log drain type.');
|
||||
}
|
||||
if ($type !== 'custom') {
|
||||
$parsers = base64_encode("
|
||||
@@ -207,7 +210,7 @@ Files:
|
||||
"touch $config_path/.env",
|
||||
];
|
||||
} else {
|
||||
throw new \Exception('Unknown log drain type.');
|
||||
throw new Exception('Unknown log drain type.');
|
||||
}
|
||||
$restart_command = [
|
||||
"echo 'Starting Fluent Bit'",
|
||||
@@ -216,7 +219,7 @@ Files:
|
||||
$command = array_merge($command, $add_envs_command, $restart_command);
|
||||
|
||||
return instant_remote_process($command, $server);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class StartSentinel
|
||||
@@ -27,7 +28,7 @@ class StartSentinel
|
||||
$mountDir = '/data/coolify/sentinel';
|
||||
$image = "ghcr.io/coollabsio/sentinel:$version";
|
||||
if (! $endpoint) {
|
||||
throw new \Exception('You should set FQDN in Instance Settings.');
|
||||
throw new Exception('You should set FQDN in Instance Settings.');
|
||||
}
|
||||
$environments = [
|
||||
'TOKEN' => $token,
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use Throwable;
|
||||
|
||||
class StopLogDrain
|
||||
{
|
||||
@@ -13,7 +14,7 @@ class StopLogDrain
|
||||
{
|
||||
try {
|
||||
return instant_remote_process(['docker rm -f coolify-log-drain'], $server, false);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ class UpdateCoolify
|
||||
return;
|
||||
}
|
||||
$settings = instanceSettings();
|
||||
$this->server = Server::find(0);
|
||||
$this->server = Server::query()->find(0);
|
||||
if (! $this->server) {
|
||||
return;
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class ValidateServer
|
||||
@@ -34,7 +35,7 @@ class ValidateServer
|
||||
$server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
throw new \Exception($this->error);
|
||||
throw new Exception($this->error);
|
||||
}
|
||||
$this->supported_os_type = $server->validateOS();
|
||||
if (! $this->supported_os_type) {
|
||||
@@ -42,7 +43,7 @@ class ValidateServer
|
||||
$server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
throw new \Exception($this->error);
|
||||
throw new Exception($this->error);
|
||||
}
|
||||
|
||||
$this->docker_installed = $server->validateDockerEngine();
|
||||
@@ -52,18 +53,17 @@ class ValidateServer
|
||||
$server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
throw new \Exception($this->error);
|
||||
throw new Exception($this->error);
|
||||
}
|
||||
$this->docker_version = $server->validateDockerEngineVersion();
|
||||
|
||||
if ($this->docker_version) {
|
||||
return 'OK';
|
||||
} else {
|
||||
}
|
||||
$this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: <a target="_blank" class="text-black underline dark:text-white" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||
$server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
throw new \Exception($this->error);
|
||||
}
|
||||
throw new Exception($this->error);
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Service;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Models\Service;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
@@ -32,12 +33,11 @@ class DeleteService
|
||||
$storagesToDelete->push($storage);
|
||||
}
|
||||
}
|
||||
foreach ($storagesToDelete as $storage) {
|
||||
$commands[] = "docker volume rm -f $storage->name";
|
||||
foreach ($storagesToDelete as $storageToDelete) {
|
||||
$commands[] = "docker volume rm -f $storageToDelete->name";
|
||||
}
|
||||
|
||||
// Execute volume deletion first, this must be done first otherwise volumes will not be deleted.
|
||||
if (! empty($commands)) {
|
||||
foreach ($commands as $command) {
|
||||
$result = instant_remote_process([$command], $server, false);
|
||||
if ($result !== null && $result !== 0) {
|
||||
@@ -45,15 +45,14 @@ class DeleteService
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($deleteConnectedNetworks) {
|
||||
$service->delete_connected_networks($service->uuid);
|
||||
}
|
||||
|
||||
instant_remote_process(["docker rm -f $service->uuid"], $server, throwError: false);
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception($e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage(), $e->getCode(), $e);
|
||||
} finally {
|
||||
if ($deleteConfigurations) {
|
||||
$service->delete_configurations();
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Actions\Service;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Models\Service;
|
||||
use Exception;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class StopService
|
||||
@@ -29,8 +30,10 @@ class StopService
|
||||
CleanupDocker::dispatch($server, true);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -20,12 +20,11 @@ class ComplexStatusCheck
|
||||
$application->update(['status' => 'exited:unhealthy']);
|
||||
|
||||
continue;
|
||||
} else {
|
||||
}
|
||||
$application->additional_servers()->updateExistingPivot($server->id, ['status' => 'exited:unhealthy']);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$container = instant_remote_process(["docker container inspect $(docker container ls -q --filter 'label=coolify.applicationId={$application->id}' --filter 'label=coolify.pullRequestId=0') --format '{{json .}}'"], $server, false);
|
||||
$container = format_docker_command_output_to_json($container);
|
||||
if ($container->count() === 1) {
|
||||
@@ -44,8 +43,7 @@ class ComplexStatusCheck
|
||||
$additional_server->updateExistingPivot($server->id, ['status' => "$containerStatus:$containerHealth"]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($is_main_server) {
|
||||
} elseif ($is_main_server) {
|
||||
$application->update(['status' => 'exited:unhealthy']);
|
||||
|
||||
continue;
|
||||
@@ -57,4 +55,3 @@ class ComplexStatusCheck
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,20 +9,20 @@ class PullImage
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(Service $resource)
|
||||
public function handle(Service $service)
|
||||
{
|
||||
$resource->saveComposeConfigs();
|
||||
$service->saveComposeConfigs();
|
||||
|
||||
$commands[] = 'cd '.$resource->workdir();
|
||||
$commands[] = "echo 'Saved configuration files to {$resource->workdir()}.'";
|
||||
$commands[] = 'cd '.$service->workdir();
|
||||
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
|
||||
$commands[] = 'docker compose pull';
|
||||
|
||||
$server = data_get($resource, 'server');
|
||||
$server = data_get($service, 'server');
|
||||
|
||||
if (! $server) {
|
||||
return;
|
||||
}
|
||||
|
||||
instant_remote_process($commands, $resource->server);
|
||||
instant_remote_process($commands, $service->server);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class AdminRemoveUser extends Command
|
||||
@@ -46,7 +47,7 @@ class AdminRemoveUser extends Command
|
||||
$team->delete();
|
||||
}
|
||||
$user->delete();
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$this->error('Failed to remove user.');
|
||||
$this->error($e->getMessage());
|
||||
|
||||
|
@@ -15,7 +15,7 @@ class CheckApplicationDeploymentQueue extends Command
|
||||
public function handle()
|
||||
{
|
||||
$seconds = $this->option('seconds');
|
||||
$deployments = ApplicationDeploymentQueue::whereIn('status', [
|
||||
$deployments = ApplicationDeploymentQueue::query()->whereIn('status', [
|
||||
ApplicationDeploymentStatus::IN_PROGRESS,
|
||||
ApplicationDeploymentStatus::QUEUED,
|
||||
])->where('created_at', '<=', now()->subSeconds($seconds))->get();
|
||||
@@ -40,11 +40,11 @@ class CheckApplicationDeploymentQueue extends Command
|
||||
}
|
||||
}
|
||||
|
||||
private function cancelDeployment(ApplicationDeploymentQueue $deployment)
|
||||
private function cancelDeployment(ApplicationDeploymentQueue $applicationDeploymentQueue)
|
||||
{
|
||||
$deployment->update(['status' => ApplicationDeploymentStatus::FAILED]);
|
||||
if ($deployment->server?->isFunctional()) {
|
||||
remote_process(['docker rm -f '.$deployment->deployment_uuid], $deployment->server, false);
|
||||
$applicationDeploymentQueue->update(['status' => ApplicationDeploymentStatus::FAILED]);
|
||||
if ($applicationDeploymentQueue->server?->isFunctional()) {
|
||||
remote_process(['docker rm -f '.$applicationDeploymentQueue->deployment_uuid], $applicationDeploymentQueue->server, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CleanupApplicationDeploymentQueue extends Command
|
||||
@@ -14,9 +15,9 @@ class CleanupApplicationDeploymentQueue extends Command
|
||||
public function handle()
|
||||
{
|
||||
$team_id = $this->option('team-id');
|
||||
$servers = \App\Models\Server::where('team_id', $team_id)->get();
|
||||
$servers = Server::query()->where('team_id', $team_id)->get();
|
||||
foreach ($servers as $server) {
|
||||
$deployments = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->where('server_id', $server->id)->get();
|
||||
$deployments = ApplicationDeploymentQueue::query()->whereIn('status', ['in_progress', 'queued'])->where('server_id', $server->id)->get();
|
||||
foreach ($deployments as $deployment) {
|
||||
$deployment->update(['status' => 'failed']);
|
||||
instant_remote_process(['docker rm -f '.$deployment->deployment_uuid], $server, false);
|
||||
|
@@ -18,19 +18,14 @@ class CleanupDatabase extends Command
|
||||
} else {
|
||||
echo "Running database cleanup in dry-run mode...\n";
|
||||
}
|
||||
if (isCloud()) {
|
||||
// Later on we can increase this to 180 days or dynamically set
|
||||
$keep_days = $this->option('keep-days') ?? 60;
|
||||
} else {
|
||||
$keep_days = $this->option('keep-days') ?? 60;
|
||||
}
|
||||
$keep_days = isCloud() ? $this->option('keep-days') ?? 60 : $this->option('keep-days') ?? 60;
|
||||
echo "Keep days: $keep_days\n";
|
||||
// Cleanup failed jobs table
|
||||
$failed_jobs = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(1));
|
||||
$count = $failed_jobs->count();
|
||||
$builder = DB::table('failed_jobs')->where('failed_at', '<', now()->subDays(1));
|
||||
$count = $builder->count();
|
||||
echo "Delete $count entries from failed_jobs.\n";
|
||||
if ($this->option('yes')) {
|
||||
$failed_jobs->delete();
|
||||
$builder->delete();
|
||||
}
|
||||
|
||||
// Cleanup sessions table
|
||||
|
@@ -21,6 +21,7 @@ use App\Models\StandaloneMysql;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Models\StandaloneRedis;
|
||||
use Illuminate\Console\Command;
|
||||
use Throwable;
|
||||
|
||||
class CleanupStuckedResources extends Command
|
||||
{
|
||||
@@ -42,18 +43,18 @@ class CleanupStuckedResources extends Command
|
||||
foreach ($servers as $server) {
|
||||
CleanupHelperContainersJob::dispatch($server);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stucked resources: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$applicationsDeploymentQueue = ApplicationDeploymentQueue::get();
|
||||
$applicationsDeploymentQueue = ApplicationDeploymentQueue::query()->get();
|
||||
foreach ($applicationsDeploymentQueue as $applicationDeploymentQueue) {
|
||||
if (is_null($applicationDeploymentQueue->application)) {
|
||||
echo "Deleting stuck application deployment queue: {$applicationDeploymentQueue->id}\n";
|
||||
$applicationDeploymentQueue->delete();
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck application deployment queue: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -62,18 +63,18 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck application: {$application->name}\n";
|
||||
$application->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck application: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$applicationsPreviews = ApplicationPreview::get();
|
||||
$applicationsPreviews = ApplicationPreview::query()->get();
|
||||
foreach ($applicationsPreviews as $applicationPreview) {
|
||||
if (! data_get($applicationPreview, 'application')) {
|
||||
echo "Deleting stuck application preview: {$applicationPreview->uuid}\n";
|
||||
$applicationPreview->delete();
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck application: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -82,16 +83,16 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck postgresql: {$postgresql->name}\n";
|
||||
$postgresql->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck postgresql: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$redis = StandaloneRedis::withTrashed()->whereNotNull('deleted_at')->get();
|
||||
foreach ($redis as $redis) {
|
||||
echo "Deleting stuck redis: {$redis->name}\n";
|
||||
$redis->forceDelete();
|
||||
foreach ($redis as $redi) {
|
||||
echo "Deleting stuck redis: {$redi->name}\n";
|
||||
$redi->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck redis: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -100,7 +101,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck keydb: {$keydb->name}\n";
|
||||
$keydb->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck keydb: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -109,7 +110,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck dragonfly: {$dragonfly->name}\n";
|
||||
$dragonfly->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck dragonfly: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -118,7 +119,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck clickhouse: {$clickhouse->name}\n";
|
||||
$clickhouse->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck clickhouse: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -127,7 +128,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck mongodb: {$mongodb->name}\n";
|
||||
$mongodb->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck mongodb: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -136,7 +137,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck mysql: {$mysql->name}\n";
|
||||
$mysql->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck mysql: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -145,7 +146,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck mariadb: {$mariadb->name}\n";
|
||||
$mariadb->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck mariadb: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -154,7 +155,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck service: {$service->name}\n";
|
||||
$service->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck service: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -163,7 +164,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck serviceapp: {$serviceApp->name}\n";
|
||||
$serviceApp->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -172,7 +173,7 @@ class CleanupStuckedResources extends Command
|
||||
echo "Deleting stuck serviceapp: {$serviceDb->name}\n";
|
||||
$serviceDb->forceDelete();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck serviceapp: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -183,7 +184,7 @@ class CleanupStuckedResources extends Command
|
||||
$scheduled_task->delete();
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck scheduledtasks: {$e->getMessage()}\n";
|
||||
}
|
||||
|
||||
@@ -195,7 +196,7 @@ class CleanupStuckedResources extends Command
|
||||
$scheduled_backup->delete();
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning stuck scheduledbackups: {$e->getMessage()}\n";
|
||||
}
|
||||
|
||||
@@ -222,7 +223,7 @@ class CleanupStuckedResources extends Command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in application: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
@@ -247,32 +248,32 @@ class CleanupStuckedResources extends Command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in postgresql: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$redis = StandaloneRedis::all();
|
||||
foreach ($redis as $redis) {
|
||||
if (! data_get($redis, 'environment')) {
|
||||
echo 'Redis without environment: '.$redis->name.'\n';
|
||||
$redis->forceDelete();
|
||||
foreach ($redis as $redi) {
|
||||
if (! data_get($redi, 'environment')) {
|
||||
echo 'Redis without environment: '.$redi->name.'\n';
|
||||
$redi->forceDelete();
|
||||
|
||||
continue;
|
||||
}
|
||||
if (! $redis->destination()) {
|
||||
echo 'Redis without destination: '.$redis->name.'\n';
|
||||
$redis->forceDelete();
|
||||
if (! $redi->destination()) {
|
||||
echo 'Redis without destination: '.$redi->name.'\n';
|
||||
$redi->forceDelete();
|
||||
|
||||
continue;
|
||||
}
|
||||
if (! data_get($redis, 'destination.server')) {
|
||||
echo 'Redis without server: '.$redis->name.'\n';
|
||||
$redis->forceDelete();
|
||||
if (! data_get($redi, 'destination.server')) {
|
||||
echo 'Redis without server: '.$redi->name.'\n';
|
||||
$redi->forceDelete();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in redis: {$e->getMessage()}\n";
|
||||
}
|
||||
|
||||
@@ -298,7 +299,7 @@ class CleanupStuckedResources extends Command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in mongodb: {$e->getMessage()}\n";
|
||||
}
|
||||
|
||||
@@ -324,7 +325,7 @@ class CleanupStuckedResources extends Command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in mysql: {$e->getMessage()}\n";
|
||||
}
|
||||
|
||||
@@ -350,7 +351,7 @@ class CleanupStuckedResources extends Command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in mariadb: {$e->getMessage()}\n";
|
||||
}
|
||||
|
||||
@@ -376,33 +377,33 @@ class CleanupStuckedResources extends Command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in service: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$serviceApplications = ServiceApplication::all();
|
||||
foreach ($serviceApplications as $service) {
|
||||
if (! data_get($service, 'service')) {
|
||||
echo 'ServiceApplication without service: '.$service->name.'\n';
|
||||
$service->forceDelete();
|
||||
foreach ($serviceApplications as $serviceApplication) {
|
||||
if (! data_get($serviceApplication, 'service')) {
|
||||
echo 'ServiceApplication without service: '.$serviceApplication->name.'\n';
|
||||
$serviceApplication->forceDelete();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in serviceApplications: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$serviceDatabases = ServiceDatabase::all();
|
||||
foreach ($serviceDatabases as $service) {
|
||||
if (! data_get($service, 'service')) {
|
||||
echo 'ServiceDatabase without service: '.$service->name.'\n';
|
||||
$service->forceDelete();
|
||||
foreach ($serviceDatabases as $serviceDatabase) {
|
||||
if (! data_get($serviceDatabase, 'service')) {
|
||||
echo 'ServiceDatabase without service: '.$serviceDatabase->name.'\n';
|
||||
$serviceDatabase->forceDelete();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in ServiceDatabases: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ class CleanupUnreachableServers extends Command
|
||||
public function handle()
|
||||
{
|
||||
echo "Running unreachable server cleanup...\n";
|
||||
$servers = Server::where('unreachable_count', 3)->where('unreachable_notification_sent', true)->where('updated_at', '<', now()->subDays(7))->get();
|
||||
$servers = Server::query()->where('unreachable_count', 3)->where('unreachable_notification_sent', true)->where('updated_at', '<', now()->subDays(7))->get();
|
||||
if ($servers->count() > 0) {
|
||||
foreach ($servers as $server) {
|
||||
echo "Cleanup unreachable server ($server->id) with name $server->name";
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Team;
|
||||
use Illuminate\Console\Command;
|
||||
use Stripe\StripeClient;
|
||||
|
||||
class CloudCheckSubscription extends Command
|
||||
{
|
||||
@@ -26,19 +27,19 @@ class CloudCheckSubscription extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
|
||||
$activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->get();
|
||||
foreach ($activeSubscribers as $team) {
|
||||
$stripeSubscriptionId = $team->subscription->stripe_subscription_id;
|
||||
$stripeInvoicePaid = $team->subscription->stripe_invoice_paid;
|
||||
$stripeCustomerId = $team->subscription->stripe_customer_id;
|
||||
$stripeClient = new StripeClient(config('subscription.stripe_api_key'));
|
||||
$activeSubscribers = Team::query()->whereRelation('subscription', 'stripe_invoice_paid', true)->get();
|
||||
foreach ($activeSubscribers as $activeSubscriber) {
|
||||
$stripeSubscriptionId = $activeSubscriber->subscription->stripe_subscription_id;
|
||||
$stripeInvoicePaid = $activeSubscriber->subscription->stripe_invoice_paid;
|
||||
$stripeCustomerId = $activeSubscriber->subscription->stripe_customer_id;
|
||||
if (! $stripeSubscriptionId) {
|
||||
echo "Team {$team->id} has no subscription, but invoice status is: {$stripeInvoicePaid}\n";
|
||||
echo "Team {$activeSubscriber->id} has no subscription, but invoice status is: {$stripeInvoicePaid}\n";
|
||||
echo "Link on Stripe: https://dashboard.stripe.com/customers/{$stripeCustomerId}\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
$subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId);
|
||||
$subscription = $stripeClient->subscriptions->retrieve($stripeSubscriptionId);
|
||||
if ($subscription->status === 'active') {
|
||||
continue;
|
||||
}
|
||||
|
@@ -4,7 +4,9 @@ namespace App\Console\Commands;
|
||||
|
||||
use App\Events\ServerReachabilityChanged;
|
||||
use App\Models\Team;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use Stripe\StripeClient;
|
||||
|
||||
class CloudCleanupSubscriptions extends Command
|
||||
{
|
||||
@@ -21,7 +23,7 @@ class CloudCleanupSubscriptions extends Command
|
||||
return;
|
||||
}
|
||||
$this->info('Cleaning up subcriptions teams');
|
||||
$stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key'));
|
||||
$stripeClient = new StripeClient(config('subscription.stripe_api_key'));
|
||||
|
||||
$teams = Team::all()->filter(function ($team) {
|
||||
return $team->id !== 0;
|
||||
@@ -47,8 +49,8 @@ class CloudCleanupSubscriptions extends Command
|
||||
$this->disableServers($team);
|
||||
|
||||
continue;
|
||||
} else {
|
||||
$subscription = $stripe->subscriptions->retrieve(data_get($team, 'subscription.stripe_subscription_id'), []);
|
||||
}
|
||||
$subscription = $stripeClient->subscriptions->retrieve(data_get($team, 'subscription.stripe_subscription_id'), []);
|
||||
$status = data_get($subscription, 'status');
|
||||
if ($status === 'active' || $status === 'past_due') {
|
||||
$team->subscription->update([
|
||||
@@ -73,8 +75,7 @@ class CloudCleanupSubscriptions extends Command
|
||||
$this->disableServers($team);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
|
||||
return;
|
||||
|
@@ -33,7 +33,7 @@ class Dev extends Command
|
||||
// Generate OpenAPI documentation
|
||||
echo "Generating OpenAPI documentation.\n";
|
||||
// https://github.com/OAI/OpenAPI-Specification/releases
|
||||
$process = Process::run([
|
||||
$processResult = Process::run([
|
||||
'/var/www/html/vendor/bin/openapi',
|
||||
'app',
|
||||
'-o',
|
||||
@@ -41,11 +41,11 @@ class Dev extends Command
|
||||
'--version',
|
||||
'3.1.0',
|
||||
]);
|
||||
$error = $process->errorOutput();
|
||||
$error = $processResult->errorOutput();
|
||||
$error = preg_replace('/^.*an object literal,.*$/m', '', $error);
|
||||
$error = preg_replace('/^\h*\v+/m', '', $error);
|
||||
echo $error;
|
||||
echo $process->output();
|
||||
echo $processResult->output();
|
||||
// Convert YAML to JSON
|
||||
$yaml = file_get_contents('openapi.yaml');
|
||||
$json = json_encode(Yaml::parse($yaml), JSON_PRETTY_PRINT);
|
||||
@@ -69,7 +69,7 @@ class Dev extends Command
|
||||
}
|
||||
|
||||
// Seed database if it's empty
|
||||
$settings = InstanceSettings::find(0);
|
||||
$settings = InstanceSettings::query()->find(0);
|
||||
if (! $settings) {
|
||||
echo "Initializing instance, seeding database.\n";
|
||||
Artisan::call('migrate --seed');
|
||||
|
@@ -12,7 +12,6 @@ use App\Notifications\Application\DeploymentFailed;
|
||||
use App\Notifications\Application\DeploymentSuccess;
|
||||
use App\Notifications\Application\StatusChanged;
|
||||
use App\Notifications\Database\BackupFailed;
|
||||
use App\Notifications\Database\BackupSuccess;
|
||||
use App\Notifications\Test;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -43,7 +42,7 @@ class Emails extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
private ?MailMessage $mail = null;
|
||||
private ?MailMessage $mailMessage = null;
|
||||
|
||||
private ?string $email = null;
|
||||
|
||||
@@ -69,15 +68,13 @@ class Emails extends Command
|
||||
$emailsGathered = ['realusers-before-trial', 'realusers-server-lost-connection'];
|
||||
if (isDev()) {
|
||||
$this->email = 'test@example.com';
|
||||
} else {
|
||||
if (! in_array($type, $emailsGathered)) {
|
||||
} elseif (! in_array($type, $emailsGathered)) {
|
||||
$this->email = text('Email Address to send to:');
|
||||
}
|
||||
}
|
||||
set_transanctional_email_settings();
|
||||
|
||||
$this->mail = new MailMessage;
|
||||
$this->mail->subject('Test Email');
|
||||
$this->mailMessage = new MailMessage;
|
||||
$this->mailMessage->subject('Test Email');
|
||||
switch ($type) {
|
||||
case 'updates':
|
||||
$teams = Team::all();
|
||||
@@ -102,18 +99,18 @@ class Emails extends Command
|
||||
$confirmed = confirm('Are you sure?');
|
||||
if ($confirmed) {
|
||||
foreach ($emails as $email) {
|
||||
$this->mail = new MailMessage;
|
||||
$this->mail->subject('One-click Services, Docker Compose support');
|
||||
$this->mailMessage = new MailMessage;
|
||||
$this->mailMessage->subject('One-click Services, Docker Compose support');
|
||||
$unsubscribeUrl = route('unsubscribe.marketing.emails', [
|
||||
'token' => encrypt($email),
|
||||
]);
|
||||
$this->mail->view('emails.updates', ['unsubscribeUrl' => $unsubscribeUrl]);
|
||||
$this->mailMessage->view('emails.updates', ['unsubscribeUrl' => $unsubscribeUrl]);
|
||||
$this->sendEmail($email);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'emails-test':
|
||||
$this->mail = (new Test)->toMail();
|
||||
$this->mailMessage = (new Test)->toMail();
|
||||
$this->sendEmail();
|
||||
break;
|
||||
case 'application-deployment-success-daily':
|
||||
@@ -123,41 +120,41 @@ class Emails extends Command
|
||||
if ($deployments->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
$this->mail = (new DeploymentSuccess($application, 'test'))->toMail();
|
||||
$this->mailMessage = (new DeploymentSuccess($application, 'test'))->toMail();
|
||||
$this->sendEmail();
|
||||
}
|
||||
break;
|
||||
case 'application-deployment-success':
|
||||
$application = Application::all()->first();
|
||||
$this->mail = (new DeploymentSuccess($application, 'test'))->toMail();
|
||||
$this->mailMessage = (new DeploymentSuccess($application, 'test'))->toMail();
|
||||
$this->sendEmail();
|
||||
break;
|
||||
case 'application-deployment-failed':
|
||||
$application = Application::all()->first();
|
||||
$preview = ApplicationPreview::all()->first();
|
||||
if (! $preview) {
|
||||
$preview = ApplicationPreview::create([
|
||||
$preview = ApplicationPreview::query()->create([
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => 1,
|
||||
'pull_request_html_url' => 'http://example.com',
|
||||
'fqdn' => $application->fqdn,
|
||||
]);
|
||||
}
|
||||
$this->mail = (new DeploymentFailed($application, 'test'))->toMail();
|
||||
$this->mailMessage = (new DeploymentFailed($application, 'test'))->toMail();
|
||||
$this->sendEmail();
|
||||
$this->mail = (new DeploymentFailed($application, 'test', $preview))->toMail();
|
||||
$this->mailMessage = (new DeploymentFailed($application, 'test', $preview))->toMail();
|
||||
$this->sendEmail();
|
||||
break;
|
||||
case 'application-status-changed':
|
||||
$application = Application::all()->first();
|
||||
$this->mail = (new StatusChanged($application))->toMail();
|
||||
$this->mailMessage = (new StatusChanged($application))->toMail();
|
||||
$this->sendEmail();
|
||||
break;
|
||||
case 'backup-failed':
|
||||
$backup = ScheduledDatabaseBackup::all()->first();
|
||||
$db = StandalonePostgresql::all()->first();
|
||||
if (! $backup) {
|
||||
$backup = ScheduledDatabaseBackup::create([
|
||||
$backup = ScheduledDatabaseBackup::query()->create([
|
||||
'enabled' => true,
|
||||
'frequency' => 'daily',
|
||||
'save_s3' => false,
|
||||
@@ -167,14 +164,14 @@ class Emails extends Command
|
||||
]);
|
||||
}
|
||||
$output = 'Because of an error, the backup of the database '.$db->name.' failed.';
|
||||
$this->mail = (new BackupFailed($backup, $db, $output))->toMail();
|
||||
$this->mailMessage = (new BackupFailed($backup, $db, $output))->toMail();
|
||||
$this->sendEmail();
|
||||
break;
|
||||
case 'backup-success':
|
||||
$backup = ScheduledDatabaseBackup::all()->first();
|
||||
$db = StandalonePostgresql::all()->first();
|
||||
if (! $backup) {
|
||||
$backup = ScheduledDatabaseBackup::create([
|
||||
$backup = ScheduledDatabaseBackup::query()->create([
|
||||
'enabled' => true,
|
||||
'frequency' => 'daily',
|
||||
'save_s3' => false,
|
||||
@@ -201,10 +198,10 @@ class Emails extends Command
|
||||
// $this->sendEmail();
|
||||
// break;
|
||||
case 'realusers-before-trial':
|
||||
$this->mail = new MailMessage;
|
||||
$this->mail->view('emails.before-trial-conversion');
|
||||
$this->mail->subject('Trial period has been added for all subscription plans.');
|
||||
$teams = Team::doesntHave('subscription')->where('id', '!=', 0)->get();
|
||||
$this->mailMessage = new MailMessage;
|
||||
$this->mailMessage->view('emails.before-trial-conversion');
|
||||
$this->mailMessage->subject('Trial period has been added for all subscription plans.');
|
||||
$teams = Team::query()->doesntHave('subscription')->where('id', '!=', 0)->get();
|
||||
if (! $teams || $teams->isEmpty()) {
|
||||
echo 'No teams found.'.PHP_EOL;
|
||||
|
||||
@@ -232,7 +229,7 @@ class Emails extends Command
|
||||
break;
|
||||
case 'realusers-server-lost-connection':
|
||||
$serverId = text('Server Id');
|
||||
$server = Server::find($serverId);
|
||||
$server = Server::query()->find($serverId);
|
||||
if (! $server) {
|
||||
throw new Exception('Server not found');
|
||||
}
|
||||
@@ -247,13 +244,13 @@ class Emails extends Command
|
||||
foreach ($admins as $admin) {
|
||||
$this->info($admin);
|
||||
}
|
||||
$this->mail = new MailMessage;
|
||||
$this->mail->view('emails.server-lost-connection', [
|
||||
$this->mailMessage = new MailMessage;
|
||||
$this->mailMessage->view('emails.server-lost-connection', [
|
||||
'name' => $server->name,
|
||||
]);
|
||||
$this->mail->subject('Action required: Server '.$server->name.' lost connection.');
|
||||
foreach ($admins as $email) {
|
||||
$this->sendEmail($email);
|
||||
$this->mailMessage->subject('Action required: Server '.$server->name.' lost connection.');
|
||||
foreach ($admins as $admin) {
|
||||
$this->sendEmail($admin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -269,8 +266,8 @@ class Emails extends Command
|
||||
[],
|
||||
fn (Message $message) => $message
|
||||
->to($this->email)
|
||||
->subject($this->mail->subject)
|
||||
->html((string) $this->mail->render())
|
||||
->subject($this->mailMessage->subject)
|
||||
->html((string) $this->mailMessage->render())
|
||||
);
|
||||
$this->info("Email sent to $this->email successfully. 📧");
|
||||
}
|
||||
|
@@ -16,8 +16,7 @@ class Horizon extends Command
|
||||
$this->info('Horizon is enabled on this server.');
|
||||
$this->call('horizon');
|
||||
exit(0);
|
||||
} else {
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Throwable;
|
||||
|
||||
class Init extends Command
|
||||
{
|
||||
@@ -22,7 +23,7 @@ class Init extends Command
|
||||
|
||||
protected $description = 'Cleanup instance related stuffs';
|
||||
|
||||
public $servers = null;
|
||||
public $servers;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
@@ -35,8 +36,7 @@ class Init extends Command
|
||||
}
|
||||
|
||||
$this->servers = Server::all();
|
||||
if (isCloud()) {
|
||||
} else {
|
||||
if (! isCloud()) {
|
||||
$this->send_alive_signal();
|
||||
get_public_ips();
|
||||
}
|
||||
@@ -61,14 +61,14 @@ class Init extends Command
|
||||
|
||||
try {
|
||||
$this->pullHelperImage();
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
//
|
||||
}
|
||||
|
||||
if (isCloud()) {
|
||||
try {
|
||||
$this->pullTemplatesFromCDN();
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Could not pull templates from CDN: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
@@ -76,13 +76,13 @@ class Init extends Command
|
||||
if (! isCloud()) {
|
||||
try {
|
||||
$this->pullTemplatesFromCDN();
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Could not pull templates from CDN: {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$localhost = $this->servers->where('id', 0)->first();
|
||||
$localhost->setupDynamicProxyConfiguration();
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
|
||||
}
|
||||
$settings = instanceSettings();
|
||||
@@ -119,8 +119,8 @@ class Init extends Command
|
||||
private function update_user_emails()
|
||||
{
|
||||
try {
|
||||
User::whereRaw('email ~ \'[A-Z]\'')->get()->each(fn (User $user) => $user->update(['email' => strtolower($user->email)]));
|
||||
} catch (\Throwable $e) {
|
||||
User::query()->whereRaw('email ~ \'[A-Z]\'')->get()->each(fn (User $user) => $user->update(['email' => strtolower($user->email)]));
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in updating user emails: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
@@ -128,8 +128,8 @@ class Init extends Command
|
||||
private function update_traefik_labels()
|
||||
{
|
||||
try {
|
||||
Server::where('proxy->type', 'TRAEFIK_V2')->update(['proxy->type' => 'TRAEFIK']);
|
||||
} catch (\Throwable $e) {
|
||||
Server::query()->where('proxy->type', 'TRAEFIK_V2')->update(['proxy->type' => 'TRAEFIK']);
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in updating traefik labels: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
@@ -149,10 +149,12 @@ class Init extends Command
|
||||
return instant_remote_process([
|
||||
"rm -f $file",
|
||||
], $server, false);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning up unnecessary dynamic proxy configuration: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function cleanup_unused_network_from_coolify_proxy()
|
||||
@@ -168,19 +170,19 @@ class Init extends Command
|
||||
['networks' => $networks, 'allNetworks' => $allNetworks] = collectDockerNetworksByServer($server);
|
||||
$removeNetworks = $allNetworks->diff($networks);
|
||||
$commands = collect();
|
||||
foreach ($removeNetworks as $network) {
|
||||
$out = instant_remote_process(["docker network inspect -f json $network | jq '.[].Containers | if . == {} then null else . end'"], $server, false);
|
||||
if (empty($out)) {
|
||||
$commands->push("docker network disconnect $network coolify-proxy >/dev/null 2>&1 || true");
|
||||
$commands->push("docker network rm $network >/dev/null 2>&1 || true");
|
||||
foreach ($removeNetworks as $removeNetwork) {
|
||||
$out = instant_remote_process(["docker network inspect -f json {$removeNetwork} | jq '.[].Containers | if . == {} then null else . end'"], $server, false);
|
||||
if ($out === null || $out === '' || $out === '0') {
|
||||
$commands->push("docker network disconnect {$removeNetwork} coolify-proxy >/dev/null 2>&1 || true");
|
||||
$commands->push("docker network rm {$removeNetwork} >/dev/null 2>&1 || true");
|
||||
} else {
|
||||
$data = collect(json_decode($out, true));
|
||||
if ($data->count() === 1) {
|
||||
// If only coolify-proxy itself is connected to that network (it should not be possible, but who knows)
|
||||
$isCoolifyProxyItself = data_get($data->first(), 'Name') === 'coolify-proxy';
|
||||
if ($isCoolifyProxyItself) {
|
||||
$commands->push("docker network disconnect $network coolify-proxy >/dev/null 2>&1 || true");
|
||||
$commands->push("docker network rm $network >/dev/null 2>&1 || true");
|
||||
$commands->push("docker network disconnect {$removeNetwork} coolify-proxy >/dev/null 2>&1 || true");
|
||||
$commands->push("docker network rm {$removeNetwork} >/dev/null 2>&1 || true");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,7 +190,7 @@ class Init extends Command
|
||||
if ($commands->isNotEmpty()) {
|
||||
remote_process(command: $commands, type: ActivityTypes::INLINE->value, server: $server, ignore_errors: false);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in cleaning up unused networks from coolify proxy: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
@@ -202,20 +204,20 @@ class Init extends Command
|
||||
if ($database && $database->trashed()) {
|
||||
echo "Restoring coolify db backup\n";
|
||||
$database->restore();
|
||||
$scheduledBackup = ScheduledDatabaseBackup::find(0);
|
||||
$scheduledBackup = ScheduledDatabaseBackup::query()->find(0);
|
||||
if (! $scheduledBackup) {
|
||||
ScheduledDatabaseBackup::create([
|
||||
ScheduledDatabaseBackup::query()->create([
|
||||
'id' => 0,
|
||||
'enabled' => true,
|
||||
'save_s3' => false,
|
||||
'frequency' => '0 0 * * *',
|
||||
'database_id' => $database->id,
|
||||
'database_type' => \App\Models\StandalonePostgresql::class,
|
||||
'database_type' => StandalonePostgresql::class,
|
||||
'team_id' => 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in restoring coolify db backup: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
@@ -234,7 +236,7 @@ class Init extends Command
|
||||
}
|
||||
try {
|
||||
Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version");
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error in sending live signal: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
@@ -246,12 +248,12 @@ class Init extends Command
|
||||
if (isCloud()) {
|
||||
return;
|
||||
}
|
||||
$queued_inprogress_deployments = ApplicationDeploymentQueue::whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
|
||||
foreach ($queued_inprogress_deployments as $deployment) {
|
||||
$deployment->status = ApplicationDeploymentStatus::FAILED->value;
|
||||
$deployment->save();
|
||||
$queued_inprogress_deployments = ApplicationDeploymentQueue::query()->whereIn('status', [ApplicationDeploymentStatus::IN_PROGRESS->value, ApplicationDeploymentStatus::QUEUED->value])->get();
|
||||
foreach ($queued_inprogress_deployments as $queued_inprogress_deployment) {
|
||||
$queued_inprogress_deployment->status = ApplicationDeploymentStatus::FAILED->value;
|
||||
$queued_inprogress_deployment->save();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
echo "Error: {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
|
@@ -16,9 +16,8 @@ class Migration extends Command
|
||||
$this->info('Migration is enabled on this server.');
|
||||
$this->call('migrate', ['--force' => true, '--isolated' => true]);
|
||||
exit(0);
|
||||
} else {
|
||||
}
|
||||
$this->info('Migration is disabled on this server.');
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ class OpenApi extends Command
|
||||
// Generate OpenAPI documentation
|
||||
echo "Generating OpenAPI documentation.\n";
|
||||
// https://github.com/OAI/OpenAPI-Specification/releases
|
||||
$process = Process::run([
|
||||
$processResult = Process::run([
|
||||
'/var/www/html/vendor/bin/openapi',
|
||||
'app',
|
||||
'-o',
|
||||
@@ -24,10 +24,10 @@ class OpenApi extends Command
|
||||
'--version',
|
||||
'3.1.0',
|
||||
]);
|
||||
$error = $process->errorOutput();
|
||||
$error = $processResult->errorOutput();
|
||||
$error = preg_replace('/^.*an object literal,.*$/m', '', $error);
|
||||
$error = preg_replace('/^\h*\v+/m', '', $error);
|
||||
echo $error;
|
||||
echo $process->output();
|
||||
echo $processResult->output();
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class RootChangeEmail extends Command
|
||||
@@ -31,9 +32,9 @@ class RootChangeEmail extends Command
|
||||
$email = $this->ask('Give me a new email for root user');
|
||||
$this->info('Updating root email...');
|
||||
try {
|
||||
User::find(0)->update(['email' => $email]);
|
||||
User::query()->find(0)->update(['email' => $email]);
|
||||
$this->info('Root user\'s email updated successfully.');
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$this->error('Failed to update root user\'s email.');
|
||||
|
||||
return;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
@@ -32,16 +33,16 @@ class RootResetPassword extends Command
|
||||
$this->info('You are about to reset the root password.');
|
||||
$password = password('Give me a new password for root user: ');
|
||||
$passwordAgain = password('Again');
|
||||
if ($password != $passwordAgain) {
|
||||
if ($password !== $passwordAgain) {
|
||||
$this->error('Passwords do not match.');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->info('Updating root password...');
|
||||
try {
|
||||
User::find(0)->update(['password' => Hash::make($password)]);
|
||||
User::query()->find(0)->update(['password' => Hash::make($password)]);
|
||||
$this->info('Root password updated successfully.');
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$this->error('Failed to update root password.');
|
||||
|
||||
return;
|
||||
|
@@ -16,8 +16,7 @@ class Scheduler extends Command
|
||||
$this->info('Scheduler is enabled on this server.');
|
||||
$this->call('schedule:work');
|
||||
exit(0);
|
||||
} else {
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,9 +16,8 @@ class Seeder extends Command
|
||||
$this->info('Seeder is enabled on this server.');
|
||||
$this->call('db:seed', ['--class' => 'ProductionSeeder', '--force' => true]);
|
||||
exit(0);
|
||||
} else {
|
||||
}
|
||||
$this->info('Seeder is disabled on this server.');
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,8 +62,8 @@ class ServicesDelete extends Command
|
||||
options: $servers->pluck('name', 'id')->sortKeys(),
|
||||
);
|
||||
|
||||
foreach ($serversToDelete as $server) {
|
||||
$toDelete = $servers->where('id', $server)->first();
|
||||
foreach ($serversToDelete as $serverToDelete) {
|
||||
$toDelete = $servers->where('id', $serverToDelete)->first();
|
||||
if ($toDelete) {
|
||||
$this->info($toDelete);
|
||||
$confirmed = confirm('Are you sure you want to delete all selected resources?');
|
||||
@@ -88,8 +88,8 @@ class ServicesDelete extends Command
|
||||
$applications->pluck('name', 'id')->sortKeys(),
|
||||
);
|
||||
|
||||
foreach ($applicationsToDelete as $application) {
|
||||
$toDelete = $applications->where('id', $application)->first();
|
||||
foreach ($applicationsToDelete as $applicationToDelete) {
|
||||
$toDelete = $applications->where('id', $applicationToDelete)->first();
|
||||
if ($toDelete) {
|
||||
$this->info($toDelete);
|
||||
$confirmed = confirm('Are you sure you want to delete all selected resources? ');
|
||||
@@ -114,8 +114,8 @@ class ServicesDelete extends Command
|
||||
$databases->pluck('name', 'id')->sortKeys(),
|
||||
);
|
||||
|
||||
foreach ($databasesToDelete as $database) {
|
||||
$toDelete = $databases->where('id', $database)->first();
|
||||
foreach ($databasesToDelete as $databaseToDelete) {
|
||||
$toDelete = $databases->where('id', $databaseToDelete)->first();
|
||||
if ($toDelete) {
|
||||
$this->info($toDelete);
|
||||
$confirmed = confirm('Are you sure you want to delete all selected resources?');
|
||||
@@ -140,8 +140,8 @@ class ServicesDelete extends Command
|
||||
$services->pluck('name', 'id')->sortKeys(),
|
||||
);
|
||||
|
||||
foreach ($servicesToDelete as $service) {
|
||||
$toDelete = $services->where('id', $service)->first();
|
||||
foreach ($servicesToDelete as $serviceToDelete) {
|
||||
$toDelete = $services->where('id', $serviceToDelete)->first();
|
||||
if ($toDelete) {
|
||||
$this->info($toDelete);
|
||||
$confirmed = confirm('Are you sure you want to delete all selected resources?');
|
||||
|
@@ -45,7 +45,7 @@ class ServicesGenerate extends Command
|
||||
$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'])] : [];
|
||||
return $m !== [] ? [trim($m['key']) => trim($m['value'])] : [];
|
||||
});
|
||||
|
||||
if (str($data->get('ignore'))->toBoolean()) {
|
||||
|
@@ -6,6 +6,7 @@ use Illuminate\Console\Command;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Http\Client\Pool;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Throwable;
|
||||
|
||||
use function Laravel\Prompts\confirm;
|
||||
|
||||
@@ -114,7 +115,8 @@ class SyncBunny extends Command
|
||||
$this->info('Service template uploaded & purged...');
|
||||
|
||||
return;
|
||||
} elseif ($only_version) {
|
||||
}
|
||||
if ($only_version) {
|
||||
if ($nightly) {
|
||||
$this->info('About to sync NIGHLTY versions.json to BunnyCDN.');
|
||||
} else {
|
||||
@@ -123,7 +125,6 @@ class SyncBunny extends Command
|
||||
$file = file_get_contents($versions_location);
|
||||
$json = json_decode($file, true);
|
||||
$actual_version = data_get($json, 'coolify.v4.version');
|
||||
|
||||
$confirmed = confirm("Are you sure you want to sync to {$actual_version}?");
|
||||
if (! $confirmed) {
|
||||
return;
|
||||
@@ -152,7 +153,7 @@ class SyncBunny extends Command
|
||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$install_script"),
|
||||
]);
|
||||
$this->info('All files uploaded & purged...');
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->error('Error: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
@@ -6,13 +6,11 @@ use App\Jobs\CheckAndStartSentinelJob;
|
||||
use App\Jobs\CheckForUpdatesJob;
|
||||
use App\Jobs\CheckHelperImageJob;
|
||||
use App\Jobs\CleanupInstanceStuffsJob;
|
||||
use App\Jobs\CleanupStaleMultiplexedConnections;
|
||||
use App\Jobs\DatabaseBackupJob;
|
||||
use App\Jobs\DockerCleanupJob;
|
||||
use App\Jobs\PullTemplatesFromCDN;
|
||||
use App\Jobs\ScheduledTaskJob;
|
||||
use App\Jobs\ServerCheckJob;
|
||||
use App\Jobs\ServerCleanupMux;
|
||||
use App\Jobs\ServerStorageCheckJob;
|
||||
use App\Jobs\UpdateCoolifyJob;
|
||||
use App\Models\InstanceSettings;
|
||||
@@ -28,9 +26,9 @@ class Kernel extends ConsoleKernel
|
||||
{
|
||||
private $allServers;
|
||||
|
||||
private Schedule $scheduleInstance;
|
||||
private Schedule $schedule;
|
||||
|
||||
private InstanceSettings $settings;
|
||||
private InstanceSettings $instanceSettings;
|
||||
|
||||
private string $updateCheckFrequency;
|
||||
|
||||
@@ -38,13 +36,13 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
$this->scheduleInstance = $schedule;
|
||||
$this->allServers = Server::where('ip', '!=', '1.2.3.4');
|
||||
$this->schedule = $schedule;
|
||||
$this->allServers = Server::query()->where('ip', '!=', '1.2.3.4');
|
||||
|
||||
$this->settings = instanceSettings();
|
||||
$this->updateCheckFrequency = $this->settings->update_check_frequency ?: '0 * * * *';
|
||||
$this->instanceSettings = instanceSettings();
|
||||
$this->updateCheckFrequency = $this->instanceSettings->update_check_frequency ?: '0 * * * *';
|
||||
|
||||
$this->instanceTimezone = $this->settings->instance_timezone ?: config('app.timezone');
|
||||
$this->instanceTimezone = $this->instanceSettings->instance_timezone ?: config('app.timezone');
|
||||
|
||||
if (validate_timezone($this->instanceTimezone) === false) {
|
||||
$this->instanceTimezone = config('app.timezone');
|
||||
@@ -54,9 +52,9 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
if (isDev()) {
|
||||
// Instance Jobs
|
||||
$this->scheduleInstance->command('horizon:snapshot')->everyMinute();
|
||||
$this->scheduleInstance->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
||||
$this->scheduleInstance->job(new CheckHelperImageJob)->everyTenMinutes()->onOneServer();
|
||||
$this->schedule->command('horizon:snapshot')->everyMinute();
|
||||
$this->schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
|
||||
$this->schedule->job(new CheckHelperImageJob)->everyTenMinutes()->onOneServer();
|
||||
|
||||
// Server Jobs
|
||||
$this->checkResources();
|
||||
@@ -64,16 +62,16 @@ class Kernel extends ConsoleKernel
|
||||
$this->checkScheduledBackups();
|
||||
$this->checkScheduledTasks();
|
||||
|
||||
$this->scheduleInstance->command('uploads:clear')->everyTwoMinutes();
|
||||
$this->schedule->command('uploads:clear')->everyTwoMinutes();
|
||||
|
||||
} else {
|
||||
// Instance Jobs
|
||||
$this->scheduleInstance->command('horizon:snapshot')->everyFiveMinutes();
|
||||
$this->scheduleInstance->command('cleanup:unreachable-servers')->daily()->onOneServer();
|
||||
$this->schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||
$this->schedule->command('cleanup:unreachable-servers')->daily()->onOneServer();
|
||||
|
||||
$this->scheduleInstance->job(new PullTemplatesFromCDN)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
$this->schedule->job(new PullTemplatesFromCDN)->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
|
||||
$this->scheduleInstance->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||
$this->schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
|
||||
$this->scheduleUpdates();
|
||||
|
||||
// Server Jobs
|
||||
@@ -84,8 +82,8 @@ class Kernel extends ConsoleKernel
|
||||
$this->checkScheduledBackups();
|
||||
$this->checkScheduledTasks();
|
||||
|
||||
$this->scheduleInstance->command('cleanup:database --yes')->daily();
|
||||
$this->scheduleInstance->command('uploads:clear')->everyTwoMinutes();
|
||||
$this->schedule->command('cleanup:database --yes')->daily();
|
||||
$this->schedule->command('uploads:clear')->everyTwoMinutes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,12 +92,12 @@ class Kernel extends ConsoleKernel
|
||||
$servers = $this->allServers->whereRelation('settings', 'is_usable', true)->whereRelation('settings', 'is_reachable', true)->get();
|
||||
foreach ($servers as $server) {
|
||||
if ($server->isSentinelEnabled()) {
|
||||
$this->scheduleInstance->job(function () use ($server) {
|
||||
$this->schedule->job(function () use ($server) {
|
||||
CheckAndStartSentinelJob::dispatch($server);
|
||||
})->cron($this->updateCheckFrequency)->timezone($this->instanceTimezone)->onOneServer();
|
||||
}
|
||||
}
|
||||
$this->scheduleInstance->job(new CheckHelperImageJob)
|
||||
$this->schedule->job(new CheckHelperImageJob)
|
||||
->cron($this->updateCheckFrequency)
|
||||
->timezone($this->instanceTimezone)
|
||||
->onOneServer();
|
||||
@@ -107,14 +105,14 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
private function scheduleUpdates(): void
|
||||
{
|
||||
$this->scheduleInstance->job(new CheckForUpdatesJob)
|
||||
$this->schedule->job(new CheckForUpdatesJob)
|
||||
->cron($this->updateCheckFrequency)
|
||||
->timezone($this->instanceTimezone)
|
||||
->onOneServer();
|
||||
|
||||
if ($this->settings->is_auto_update_enabled) {
|
||||
$autoUpdateFrequency = $this->settings->auto_update_frequency;
|
||||
$this->scheduleInstance->job(new UpdateCoolifyJob)
|
||||
if ($this->instanceSettings->is_auto_update_enabled) {
|
||||
$autoUpdateFrequency = $this->instanceSettings->auto_update_frequency;
|
||||
$this->schedule->job(new UpdateCoolifyJob)
|
||||
->cron($autoUpdateFrequency)
|
||||
->timezone($this->instanceTimezone)
|
||||
->onOneServer();
|
||||
@@ -125,7 +123,7 @@ class Kernel extends ConsoleKernel
|
||||
{
|
||||
if (isCloud()) {
|
||||
$servers = $this->allServers->whereHas('team.subscription')->get();
|
||||
$own = Team::find(0)->servers;
|
||||
$own = Team::query()->find(0)->servers;
|
||||
$servers = $servers->merge($own);
|
||||
} else {
|
||||
$servers = $this->allServers->get();
|
||||
@@ -142,23 +140,23 @@ class Kernel extends ConsoleKernel
|
||||
if (Carbon::parse($lastSentinelUpdate)->isBefore(now()->subSeconds($server->waitBeforeDoingSshCheck()))) {
|
||||
// Check container status every minute if Sentinel does not activated
|
||||
if (isCloud()) {
|
||||
$this->scheduleInstance->job(new ServerCheckJob($server))->timezone($serverTimezone)->everyFiveMinutes()->onOneServer();
|
||||
$this->schedule->job(new ServerCheckJob($server))->timezone($serverTimezone)->everyFiveMinutes()->onOneServer();
|
||||
} else {
|
||||
$this->scheduleInstance->job(new ServerCheckJob($server))->timezone($serverTimezone)->everyMinute()->onOneServer();
|
||||
$this->schedule->job(new ServerCheckJob($server))->timezone($serverTimezone)->everyMinute()->onOneServer();
|
||||
}
|
||||
// $this->scheduleInstance->job(new \App\Jobs\ServerCheckNewJob($server))->everyFiveMinutes()->onOneServer();
|
||||
|
||||
$this->scheduleInstance->job(new ServerStorageCheckJob($server))->cron($server->settings->server_disk_usage_check_frequency)->timezone($serverTimezone)->onOneServer();
|
||||
$this->schedule->job(new ServerStorageCheckJob($server))->cron($server->settings->server_disk_usage_check_frequency)->timezone($serverTimezone)->onOneServer();
|
||||
}
|
||||
|
||||
$this->scheduleInstance->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();
|
||||
$this->schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();
|
||||
|
||||
// Cleanup multiplexed connections every hour
|
||||
// $this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer();
|
||||
|
||||
// Temporary solution until we have better memory management for Sentinel
|
||||
if ($server->isSentinelEnabled()) {
|
||||
$this->scheduleInstance->job(function () use ($server) {
|
||||
$this->schedule->job(function () use ($server) {
|
||||
$server->restartContainer('coolify-sentinel');
|
||||
})->daily()->onOneServer();
|
||||
}
|
||||
@@ -167,7 +165,7 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
private function checkScheduledBackups(): void
|
||||
{
|
||||
$scheduled_backups = ScheduledDatabaseBackup::where('enabled', true)->get();
|
||||
$scheduled_backups = ScheduledDatabaseBackup::query()->where('enabled', true)->get();
|
||||
if ($scheduled_backups->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -187,7 +185,7 @@ class Kernel extends ConsoleKernel
|
||||
$scheduled_backup->frequency = VALID_CRON_STRINGS[$scheduled_backup->frequency];
|
||||
}
|
||||
$serverTimezone = data_get($server->settings, 'server_timezone', $this->instanceTimezone);
|
||||
$this->scheduleInstance->job(new DatabaseBackupJob(
|
||||
$this->schedule->job(new DatabaseBackupJob(
|
||||
backup: $scheduled_backup
|
||||
))->cron($scheduled_backup->frequency)->timezone($serverTimezone)->onOneServer();
|
||||
}
|
||||
@@ -195,7 +193,7 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
private function checkScheduledTasks(): void
|
||||
{
|
||||
$scheduled_tasks = ScheduledTask::where('enabled', true)->get();
|
||||
$scheduled_tasks = ScheduledTask::query()->where('enabled', true)->get();
|
||||
if ($scheduled_tasks->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -208,16 +206,12 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($application) {
|
||||
if (str($application->status)->contains('running') === false) {
|
||||
if ($application && str($application->status)->contains('running') === false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($service) {
|
||||
if (str($service->status)->contains('running') === false) {
|
||||
if ($service && str($service->status)->contains('running') === false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$server = $scheduled_task->server();
|
||||
if (! $server) {
|
||||
@@ -228,7 +222,7 @@ class Kernel extends ConsoleKernel
|
||||
$scheduled_task->frequency = VALID_CRON_STRINGS[$scheduled_task->frequency];
|
||||
}
|
||||
$serverTimezone = data_get($server->settings, 'server_timezone', $this->instanceTimezone);
|
||||
$this->scheduleInstance->job(new ScheduledTaskJob(
|
||||
$this->schedule->job(new ScheduledTaskJob(
|
||||
task: $scheduled_task
|
||||
))->cron($scheduled_task->frequency)->timezone($serverTimezone)->onOneServer();
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ use Spatie\LaravelData\Data;
|
||||
class ServerMetadata extends Data
|
||||
{
|
||||
public function __construct(
|
||||
public ?ProxyTypes $type,
|
||||
public ?ProxyStatus $status
|
||||
public ?ProxyTypes $proxyTypes,
|
||||
public ?ProxyStatus $proxyStatus
|
||||
) {}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
@@ -20,7 +21,7 @@ class ApplicationStatusChanged implements ShouldBroadcast
|
||||
$teamId = auth()->user()->currentTeam()->id ?? null;
|
||||
}
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
throw new Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
@@ -20,7 +21,7 @@ class BackupCreated implements ShouldBroadcast
|
||||
$teamId = auth()->user()->currentTeam()->id ?? null;
|
||||
}
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
throw new Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
@@ -20,7 +21,7 @@ class CloudflareTunnelConfigured implements ShouldBroadcast
|
||||
$teamId = auth()->user()->currentTeam()->id ?? null;
|
||||
}
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
throw new Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
@@ -21,7 +22,7 @@ class DatabaseProxyStopped implements ShouldBroadcast
|
||||
$teamId = Auth::user()?->currentTeam()?->id ?? null;
|
||||
}
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
throw new Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ class DatabaseStatusChanged implements ShouldBroadcast
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $userId = null;
|
||||
public $userId;
|
||||
|
||||
public function __construct($userId = null)
|
||||
{
|
||||
@@ -21,7 +21,7 @@ class DatabaseStatusChanged implements ShouldBroadcast
|
||||
$userId = Auth::id() ?? null;
|
||||
}
|
||||
if (is_null($userId)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->userId = $userId;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
@@ -17,7 +18,7 @@ class FileStorageChanged implements ShouldBroadcast
|
||||
public function __construct($teamId = null)
|
||||
{
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
throw new Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
@@ -20,7 +21,7 @@ class ProxyStatusChanged implements ShouldBroadcast
|
||||
$teamId = auth()->user()->currentTeam()->id ?? null;
|
||||
}
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
throw new Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
@@ -17,18 +17,15 @@ class RestoreJobFinished
|
||||
$tmpPath = data_get($data, 'tmpPath');
|
||||
$container = data_get($data, 'container');
|
||||
$serverId = data_get($data, 'serverId');
|
||||
if (filled($scriptPath) && filled($tmpPath) && filled($container) && filled($serverId)) {
|
||||
if (str($tmpPath)->startsWith('/tmp/')
|
||||
if (filled($scriptPath) && filled($tmpPath) && filled($container) && filled($serverId) && (str($tmpPath)->startsWith('/tmp/')
|
||||
&& str($scriptPath)->startsWith('/tmp/')
|
||||
&& ! str($tmpPath)->contains('..')
|
||||
&& ! str($scriptPath)->contains('..')
|
||||
&& strlen($tmpPath) > 5 // longer than just "/tmp/"
|
||||
&& strlen($scriptPath) > 5
|
||||
) {
|
||||
&& strlen($scriptPath) > 5)) {
|
||||
$commands[] = "docker exec {$container} sh -c 'rm {$scriptPath}'";
|
||||
$commands[] = "docker exec {$container} sh -c 'rm {$tmpPath}'";
|
||||
instant_remote_process($commands, Server::find($serverId), throwError: true);
|
||||
}
|
||||
instant_remote_process($commands, Server::query()->find($serverId), throwError: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
@@ -20,7 +21,7 @@ class ScheduledTaskDone implements ShouldBroadcast
|
||||
$teamId = auth()->user()->currentTeam()->id ?? null;
|
||||
}
|
||||
if (is_null($teamId)) {
|
||||
throw new \Exception('Team id is null');
|
||||
throw new Exception('Team id is null');
|
||||
}
|
||||
$this->teamId = $teamId;
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ class ServiceStatusChanged implements ShouldBroadcast
|
||||
$userId = Auth::id() ?? null;
|
||||
}
|
||||
if (is_null($userId)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ class Handler extends ExceptionHandler
|
||||
/**
|
||||
* A list of exception types with their corresponding custom log levels.
|
||||
*
|
||||
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
|
||||
* @var array<class-string<Throwable>, \Psr\Log\LogLevel::*>
|
||||
*/
|
||||
protected $levels = [
|
||||
//
|
||||
@@ -25,7 +25,7 @@ class Handler extends ExceptionHandler
|
||||
/**
|
||||
* A list of the exception types that are not reported.
|
||||
*
|
||||
* @var array<int, class-string<\Throwable>>
|
||||
* @var array<int, class-string<Throwable>>
|
||||
*/
|
||||
protected $dontReport = [
|
||||
ProcessException::class,
|
||||
@@ -42,15 +42,15 @@ class Handler extends ExceptionHandler
|
||||
'password_confirmation',
|
||||
];
|
||||
|
||||
private InstanceSettings $settings;
|
||||
private InstanceSettings $instanceSettings;
|
||||
|
||||
protected function unauthenticated($request, AuthenticationException $exception)
|
||||
protected function unauthenticated($request, AuthenticationException $authenticationException)
|
||||
{
|
||||
if ($request->is('api/*') || $request->expectsJson() || $this->shouldReturnJson($request, $exception)) {
|
||||
return response()->json(['message' => $exception->getMessage()], 401);
|
||||
if ($request->is('api/*') || $request->expectsJson() || $this->shouldReturnJson($request, $authenticationException)) {
|
||||
return response()->json(['message' => $authenticationException->getMessage()], 401);
|
||||
}
|
||||
|
||||
return redirect()->guest($exception->redirectTo($request) ?? route('login'));
|
||||
return redirect()->guest($authenticationException->redirectTo($request) ?? route('login'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,21 +58,21 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
$this->reportable(function (Throwable $throwable) {
|
||||
if (isDev()) {
|
||||
return;
|
||||
}
|
||||
if ($e instanceof RuntimeException) {
|
||||
if ($throwable instanceof RuntimeException) {
|
||||
return;
|
||||
}
|
||||
$this->settings = instanceSettings();
|
||||
if ($this->settings->do_not_track) {
|
||||
$this->instanceSettings = instanceSettings();
|
||||
if ($this->instanceSettings->do_not_track) {
|
||||
return;
|
||||
}
|
||||
app('sentry')->configureScope(
|
||||
function (Scope $scope) {
|
||||
$email = auth()?->user() ? auth()->user()->email : 'guest';
|
||||
$instanceAdmin = User::find(0)->email ?? 'admin@localhost';
|
||||
$instanceAdmin = User::query()->find(0)->email ?? 'admin@localhost';
|
||||
$scope->setUser(
|
||||
[
|
||||
'email' => $email,
|
||||
@@ -81,10 +81,10 @@ class Handler extends ExceptionHandler
|
||||
);
|
||||
}
|
||||
);
|
||||
if (str($e->getMessage())->contains('No space left on device')) {
|
||||
if (str($throwable->getMessage())->contains('No space left on device')) {
|
||||
return;
|
||||
}
|
||||
Integration::captureUnhandledException($e);
|
||||
Integration::captureUnhandledException($throwable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -6,12 +6,13 @@ use App\Models\PrivateKey;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use RuntimeException;
|
||||
|
||||
class SshMultiplexingHelper
|
||||
{
|
||||
public static function serverSshConfiguration(Server $server)
|
||||
{
|
||||
$privateKey = PrivateKey::findOrFail($server->private_key_id);
|
||||
$privateKey = PrivateKey::query()->findOrFail($server->private_key_id);
|
||||
$sshKeyLocation = $privateKey->getKeyLocation();
|
||||
$muxFilename = '/var/www/html/storage/app/ssh/mux/mux_'.$server->uuid;
|
||||
|
||||
@@ -35,9 +36,9 @@ class SshMultiplexingHelper
|
||||
$checkCommand .= '-o ProxyCommand="cloudflared access ssh --hostname %h" ';
|
||||
}
|
||||
$checkCommand .= "{$server->user}@{$server->ip}";
|
||||
$process = Process::run($checkCommand);
|
||||
$processResult = Process::run($checkCommand);
|
||||
|
||||
if ($process->exitCode() !== 0) {
|
||||
if ($processResult->exitCode() !== 0) {
|
||||
return self::establishNewMultiplexedConnection($server);
|
||||
}
|
||||
|
||||
@@ -60,12 +61,9 @@ class SshMultiplexingHelper
|
||||
}
|
||||
$establishCommand .= self::getCommonSshOptions($server, $sshKeyLocation, $connectionTimeout, $serverInterval);
|
||||
$establishCommand .= "{$server->user}@{$server->ip}";
|
||||
$establishProcess = Process::run($establishCommand);
|
||||
if ($establishProcess->exitCode() !== 0) {
|
||||
return false;
|
||||
}
|
||||
$processResult = Process::run($establishCommand);
|
||||
|
||||
return true;
|
||||
return $processResult->exitCode() === 0;
|
||||
}
|
||||
|
||||
public static function removeMuxFile(Server $server)
|
||||
@@ -103,15 +101,14 @@ class SshMultiplexingHelper
|
||||
}
|
||||
|
||||
$scp_command .= self::getCommonSshOptions($server, $sshKeyLocation, config('constants.ssh.connection_timeout'), config('constants.ssh.server_interval'), isScp: true);
|
||||
$scp_command .= "{$source} {$server->user}@{$server->ip}:{$dest}";
|
||||
|
||||
return $scp_command;
|
||||
return $scp_command."{$source} {$server->user}@{$server->ip}:{$dest}";
|
||||
}
|
||||
|
||||
public static function generateSshCommand(Server $server, string $command)
|
||||
{
|
||||
if ($server->settings->force_disabled) {
|
||||
throw new \RuntimeException('Server is disabled.');
|
||||
throw new RuntimeException('Server is disabled.');
|
||||
}
|
||||
|
||||
$sshConfig = self::serverSshConfiguration($server);
|
||||
@@ -140,11 +137,9 @@ class SshMultiplexingHelper
|
||||
$delimiter = base64_encode($delimiter);
|
||||
$command = str_replace($delimiter, '', $command);
|
||||
|
||||
$ssh_command .= "{$server->user}@{$server->ip} 'bash -se' << \\$delimiter".PHP_EOL
|
||||
return $ssh_command.("{$server->user}@{$server->ip} 'bash -se' << \\$delimiter".PHP_EOL
|
||||
.$command.PHP_EOL
|
||||
.$delimiter;
|
||||
|
||||
return $ssh_command;
|
||||
.$delimiter);
|
||||
}
|
||||
|
||||
private static function isMultiplexingEnabled(): bool
|
||||
@@ -156,9 +151,9 @@ class SshMultiplexingHelper
|
||||
{
|
||||
$keyLocation = $privateKey->getKeyLocation();
|
||||
$checkKeyCommand = "ls $keyLocation 2>/dev/null";
|
||||
$keyCheckProcess = Process::run($checkKeyCommand);
|
||||
$processResult = Process::run($checkKeyCommand);
|
||||
|
||||
if ($keyCheckProcess->exitCode() !== 0) {
|
||||
if ($processResult->exitCode() !== 0) {
|
||||
$privateKey->storeInFileSystem();
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ use App\Models\PrivateKey;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use OpenApi\Attributes as OA;
|
||||
@@ -89,7 +90,7 @@ class ApplicationsController extends Controller
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
$projects = Project::query()->where('team_id', $teamId)->get();
|
||||
$applications = collect();
|
||||
$applications->push($projects->pluck('applications')->flatten());
|
||||
$applications = $applications->flatten();
|
||||
@@ -717,7 +718,7 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -731,12 +732,10 @@ class ApplicationsController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -825,15 +824,12 @@ class ApplicationsController extends Controller
|
||||
if ($request->build_pack === 'dockercompose') {
|
||||
$request->offsetSet('ports_exposes', '80');
|
||||
}
|
||||
|
||||
$return = $this->validateDataApplications($request, $server);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$application = new Application;
|
||||
removeUnnecessaryFieldsFromRequest($request);
|
||||
|
||||
$application->fill($request->all());
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
@@ -848,7 +844,6 @@ class ApplicationsController extends Controller
|
||||
if ($dockerComposeDomainsJson->count() > 0) {
|
||||
$application->docker_compose_domains = $dockerComposeDomainsJson;
|
||||
}
|
||||
|
||||
$application->fqdn = $fqdn;
|
||||
$application->destination_id = $destination->id;
|
||||
$application->destination_type = $destination->getMorphClass();
|
||||
@@ -868,27 +863,24 @@ class ApplicationsController extends Controller
|
||||
$application->save();
|
||||
}
|
||||
$application->isConfigurationChanged(true);
|
||||
|
||||
if ($instantDeploy) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
|
||||
queue_application_deployment(
|
||||
application: $application,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
no_questions_asked: true,
|
||||
is_api: true,
|
||||
);
|
||||
} else {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
} elseif ($application->build_pack === 'dockercompose') {
|
||||
LoadComposeFile::dispatch($application);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse([
|
||||
'uuid' => data_get($application, 'uuid'),
|
||||
'domains' => data_get($application, 'domains'),
|
||||
]))->setStatusCode(201);
|
||||
} elseif ($type === 'private-gh-app') {
|
||||
}
|
||||
if ($type === 'private-gh-app') {
|
||||
$validationRules = [
|
||||
'git_repository' => 'string|required',
|
||||
'git_branch' => 'string|required',
|
||||
@@ -900,7 +892,6 @@ class ApplicationsController extends Controller
|
||||
'docker_compose_raw' => 'string|nullable',
|
||||
];
|
||||
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
||||
|
||||
$validator = customApiValidator($request->all(), $validationRules);
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
@@ -908,16 +899,14 @@ class ApplicationsController extends Controller
|
||||
'errors' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (! $request->has('name')) {
|
||||
$request->offsetSet('name', generate_application_name($request->git_repository, $request->git_branch));
|
||||
}
|
||||
if ($request->build_pack === 'dockercompose') {
|
||||
$request->offsetSet('ports_exposes', '80');
|
||||
}
|
||||
|
||||
$return = $this->validateDataApplications($request, $server);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$githubApp = GithubApp::whereTeamId($teamId)->where('uuid', $githubAppUuid)->first();
|
||||
@@ -930,9 +919,7 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
$application = new Application;
|
||||
removeUnnecessaryFieldsFromRequest($request);
|
||||
|
||||
$application->fill($request->all());
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
@@ -969,28 +956,24 @@ class ApplicationsController extends Controller
|
||||
$application->save();
|
||||
}
|
||||
$application->isConfigurationChanged(true);
|
||||
|
||||
if ($instantDeploy) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
|
||||
queue_application_deployment(
|
||||
application: $application,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
no_questions_asked: true,
|
||||
is_api: true,
|
||||
);
|
||||
} else {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
} elseif ($application->build_pack === 'dockercompose') {
|
||||
LoadComposeFile::dispatch($application);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse([
|
||||
'uuid' => data_get($application, 'uuid'),
|
||||
'domains' => data_get($application, 'domains'),
|
||||
]))->setStatusCode(201);
|
||||
} elseif ($type === 'private-deploy-key') {
|
||||
|
||||
}
|
||||
if ($type === 'private-deploy-key') {
|
||||
$validationRules = [
|
||||
'git_repository' => 'string|required',
|
||||
'git_branch' => 'string|required',
|
||||
@@ -1001,10 +984,8 @@ class ApplicationsController extends Controller
|
||||
'docker_compose_location' => 'string',
|
||||
'docker_compose_raw' => 'string|nullable',
|
||||
];
|
||||
|
||||
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
||||
$validator = customApiValidator($request->all(), $validationRules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
@@ -1017,21 +998,17 @@ class ApplicationsController extends Controller
|
||||
if ($request->build_pack === 'dockercompose') {
|
||||
$request->offsetSet('ports_exposes', '80');
|
||||
}
|
||||
|
||||
$return = $this->validateDataApplications($request, $server);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$privateKey = PrivateKey::whereTeamId($teamId)->where('uuid', $request->private_key_uuid)->first();
|
||||
if (! $privateKey) {
|
||||
return response()->json(['message' => 'Private Key not found.'], 404);
|
||||
}
|
||||
|
||||
$application = new Application;
|
||||
removeUnnecessaryFieldsFromRequest($request);
|
||||
|
||||
$application->fill($request->all());
|
||||
|
||||
$dockerComposeDomainsJson = collect();
|
||||
if ($request->has('docker_compose_domains')) {
|
||||
$yaml = Yaml::parse($application->docker_compose_raw);
|
||||
@@ -1066,33 +1043,29 @@ class ApplicationsController extends Controller
|
||||
$application->save();
|
||||
}
|
||||
$application->isConfigurationChanged(true);
|
||||
|
||||
if ($instantDeploy) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
|
||||
queue_application_deployment(
|
||||
application: $application,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
no_questions_asked: true,
|
||||
is_api: true,
|
||||
);
|
||||
} else {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
} elseif ($application->build_pack === 'dockercompose') {
|
||||
LoadComposeFile::dispatch($application);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse([
|
||||
'uuid' => data_get($application, 'uuid'),
|
||||
'domains' => data_get($application, 'domains'),
|
||||
]))->setStatusCode(201);
|
||||
} elseif ($type === 'dockerfile') {
|
||||
}
|
||||
if ($type === 'dockerfile') {
|
||||
$validationRules = [
|
||||
'dockerfile' => 'string|required',
|
||||
];
|
||||
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
||||
$validator = customApiValidator($request->all(), $validationRules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
@@ -1102,9 +1075,8 @@ class ApplicationsController extends Controller
|
||||
if (! $request->has('name')) {
|
||||
$request->offsetSet('name', 'dockerfile-'.new Cuid2);
|
||||
}
|
||||
|
||||
$return = $this->validateDataApplications($request, $server);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
if (! isBase64Encoded($request->dockerfile)) {
|
||||
@@ -1126,12 +1098,10 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
$dockerFile = base64_decode($request->dockerfile);
|
||||
removeUnnecessaryFieldsFromRequest($request);
|
||||
|
||||
$port = get_port_from_dockerfile($request->dockerfile);
|
||||
if (! $port) {
|
||||
$port = 80;
|
||||
}
|
||||
|
||||
$application = new Application;
|
||||
$application->fill($request->all());
|
||||
$application->fqdn = $fqdn;
|
||||
@@ -1141,8 +1111,6 @@ class ApplicationsController extends Controller
|
||||
$application->destination_id = $destination->id;
|
||||
$application->destination_type = $destination->getMorphClass();
|
||||
$application->environment_id = $environment->id;
|
||||
|
||||
|
||||
$application->git_repository = 'coollabsio/coolify';
|
||||
$application->git_branch = 'main';
|
||||
$application->save();
|
||||
@@ -1156,7 +1124,6 @@ class ApplicationsController extends Controller
|
||||
$application->save();
|
||||
}
|
||||
$application->isConfigurationChanged(true);
|
||||
|
||||
if ($instantDeploy) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
|
||||
@@ -1172,7 +1139,8 @@ class ApplicationsController extends Controller
|
||||
'uuid' => data_get($application, 'uuid'),
|
||||
'domains' => data_get($application, 'domains'),
|
||||
]))->setStatusCode(201);
|
||||
} elseif ($type === 'dockerimage') {
|
||||
}
|
||||
if ($type === 'dockerimage') {
|
||||
$validationRules = [
|
||||
'docker_registry_image_name' => 'string|required',
|
||||
'docker_registry_image_tag' => 'string',
|
||||
@@ -1180,7 +1148,6 @@ class ApplicationsController extends Controller
|
||||
];
|
||||
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
||||
$validator = customApiValidator($request->all(), $validationRules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
@@ -1191,7 +1158,7 @@ class ApplicationsController extends Controller
|
||||
$request->offsetSet('name', 'docker-image-'.new Cuid2);
|
||||
}
|
||||
$return = $this->validateDataApplications($request, $server);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
if (! $request->docker_registry_image_tag) {
|
||||
@@ -1199,14 +1166,12 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
$application = new Application;
|
||||
removeUnnecessaryFieldsFromRequest($request);
|
||||
|
||||
$application->fill($request->all());
|
||||
$application->fqdn = $fqdn;
|
||||
$application->build_pack = 'dockerimage';
|
||||
$application->destination_id = $destination->id;
|
||||
$application->destination_type = $destination->getMorphClass();
|
||||
$application->environment_id = $environment->id;
|
||||
|
||||
$application->git_repository = 'coollabsio/coolify';
|
||||
$application->git_branch = 'main';
|
||||
$application->save();
|
||||
@@ -1220,7 +1185,6 @@ class ApplicationsController extends Controller
|
||||
$application->save();
|
||||
}
|
||||
$application->isConfigurationChanged(true);
|
||||
|
||||
if ($instantDeploy) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
|
||||
@@ -1236,16 +1200,14 @@ class ApplicationsController extends Controller
|
||||
'uuid' => data_get($application, 'uuid'),
|
||||
'domains' => data_get($application, 'domains'),
|
||||
]))->setStatusCode(201);
|
||||
} elseif ($type === 'dockercompose') {
|
||||
$allowedFields = ['project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'instant_deploy', 'docker_compose_raw'];
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
if ($type === 'dockercompose') {
|
||||
$allowedFields = ['project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'instant_deploy', 'docker_compose_raw'];
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1261,7 +1223,6 @@ class ApplicationsController extends Controller
|
||||
];
|
||||
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
||||
$validator = customApiValidator($request->all(), $validationRules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
@@ -1269,7 +1230,7 @@ class ApplicationsController extends Controller
|
||||
], 422);
|
||||
}
|
||||
$return = $this->validateDataApplications($request, $server);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
if (! isBase64Encoded($request->docker_compose_raw)) {
|
||||
@@ -1291,23 +1252,19 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
$dockerCompose = base64_decode($request->docker_compose_raw);
|
||||
$dockerComposeRaw = Yaml::dump(Yaml::parse($dockerCompose), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
||||
|
||||
// $isValid = validateComposeFile($dockerComposeRaw, $server_id);
|
||||
// if ($isValid !== 'OK') {
|
||||
// return $this->dispatch('error', "Invalid docker-compose file.\n$isValid");
|
||||
// }
|
||||
|
||||
$service = new Service;
|
||||
removeUnnecessaryFieldsFromRequest($request);
|
||||
$service->fill($request->all());
|
||||
|
||||
$service->docker_compose_raw = $dockerComposeRaw;
|
||||
$service->environment_id = $environment->id;
|
||||
$service->server_id = $server->id;
|
||||
$service->destination_id = $destination->id;
|
||||
$service->destination_type = $destination->getMorphClass();
|
||||
$service->save();
|
||||
|
||||
$service->name = "service-$service->uuid";
|
||||
$service->parse(isNew: true);
|
||||
if ($instantDeploy) {
|
||||
@@ -1447,7 +1404,7 @@ class ApplicationsController extends Controller
|
||||
public function delete_by_uuid(Request $request)
|
||||
{
|
||||
$teamId = getTeamIdFromToken();
|
||||
$cleanup = filter_var($request->query->get('cleanup', true), FILTER_VALIDATE_BOOLEAN);
|
||||
filter_var($request->query->get('cleanup', true), FILTER_VALIDATE_BOOLEAN);
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
@@ -1602,7 +1559,7 @@ class ApplicationsController extends Controller
|
||||
], 400);
|
||||
}
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
|
||||
@@ -1664,16 +1621,14 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
}
|
||||
$return = $this->validateDataApplications($request, $server);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1696,7 +1651,7 @@ class ApplicationsController extends Controller
|
||||
|
||||
return $domain;
|
||||
});
|
||||
if (count($errors) > 0) {
|
||||
if ($errors !== []) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => $errors,
|
||||
@@ -1755,11 +1710,11 @@ class ApplicationsController extends Controller
|
||||
$application->save();
|
||||
|
||||
if ($instantDeploy) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
$cuid2 = new Cuid2;
|
||||
|
||||
queue_application_deployment(
|
||||
application: $application,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
deployment_uuid: $cuid2,
|
||||
is_api: true,
|
||||
);
|
||||
}
|
||||
@@ -1935,7 +1890,7 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
|
||||
@@ -1956,12 +1911,10 @@ class ApplicationsController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1995,12 +1948,12 @@ class ApplicationsController extends Controller
|
||||
$env->save();
|
||||
|
||||
return response()->json($this->removeSensitiveData($env))->setStatusCode(201);
|
||||
} else {
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Environment variable not found.',
|
||||
], 404);
|
||||
}
|
||||
} else {
|
||||
$env = $application->environment_variables->where('key', $key)->first();
|
||||
if ($env) {
|
||||
$env->value = $request->value;
|
||||
@@ -2022,16 +1975,11 @@ class ApplicationsController extends Controller
|
||||
$env->save();
|
||||
|
||||
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);
|
||||
'message' => 'Environment variable not found.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
#[OA\Patch(
|
||||
@@ -2124,7 +2072,7 @@ class ApplicationsController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$application = Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
|
||||
@@ -2330,12 +2278,10 @@ class ApplicationsController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -2352,7 +2298,7 @@ class ApplicationsController extends Controller
|
||||
return response()->json([
|
||||
'message' => 'Environment variable already exists. Use PATCH request to update it.',
|
||||
], 409);
|
||||
} else {
|
||||
}
|
||||
$env = $application->environment_variables()->create([
|
||||
'key' => $request->key,
|
||||
'value' => $request->value,
|
||||
@@ -2369,13 +2315,12 @@ class ApplicationsController extends Controller
|
||||
'uuid' => $env->uuid,
|
||||
])->setStatusCode(201);
|
||||
}
|
||||
} else {
|
||||
$env = $application->environment_variables->where('key', $key)->first();
|
||||
if ($env) {
|
||||
return response()->json([
|
||||
'message' => 'Environment variable already exists. Use PATCH request to update it.',
|
||||
], 409);
|
||||
} else {
|
||||
}
|
||||
$env = $application->environment_variables()->create([
|
||||
'key' => $request->key,
|
||||
'value' => $request->value,
|
||||
@@ -2392,12 +2337,6 @@ class ApplicationsController extends Controller
|
||||
'uuid' => $env->uuid,
|
||||
])->setStatusCode(201);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong.',
|
||||
], 500);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
summary: 'Delete Env',
|
||||
@@ -2473,7 +2412,7 @@ class ApplicationsController extends Controller
|
||||
'message' => 'Application not found.',
|
||||
], 404);
|
||||
}
|
||||
$found_env = EnvironmentVariable::where('uuid', $request->env_uuid)
|
||||
$found_env = EnvironmentVariable::query()->where('uuid', $request->env_uuid)
|
||||
->where('resourceable_type', Application::class)
|
||||
->where('resourceable_id', $application->id)
|
||||
->first();
|
||||
@@ -2576,11 +2515,11 @@ class ApplicationsController extends Controller
|
||||
return response()->json(['message' => 'Application not found.'], 404);
|
||||
}
|
||||
|
||||
$deployment_uuid = new Cuid2;
|
||||
$cuid2 = new Cuid2;
|
||||
|
||||
queue_application_deployment(
|
||||
application: $application,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
deployment_uuid: $cuid2,
|
||||
force_rebuild: $force,
|
||||
is_api: true,
|
||||
no_questions_asked: $instant_deploy
|
||||
@@ -2589,7 +2528,7 @@ class ApplicationsController extends Controller
|
||||
return response()->json(
|
||||
[
|
||||
'message' => 'Deployment request queued.',
|
||||
'deployment_uuid' => $deployment_uuid->toString(),
|
||||
'deployment_uuid' => $cuid2->toString(),
|
||||
],
|
||||
200
|
||||
);
|
||||
@@ -2737,11 +2676,11 @@ class ApplicationsController extends Controller
|
||||
return response()->json(['message' => 'Application not found.'], 404);
|
||||
}
|
||||
|
||||
$deployment_uuid = new Cuid2;
|
||||
$cuid2 = new Cuid2;
|
||||
|
||||
queue_application_deployment(
|
||||
application: $application,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
deployment_uuid: $cuid2,
|
||||
restart_only: true,
|
||||
is_api: true,
|
||||
);
|
||||
@@ -2749,7 +2688,7 @@ class ApplicationsController extends Controller
|
||||
return response()->json(
|
||||
[
|
||||
'message' => 'Restart request queued.',
|
||||
'deployment_uuid' => $deployment_uuid->toString(),
|
||||
'deployment_uuid' => $cuid2->toString(),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -2836,7 +2775,7 @@ class ApplicationsController extends Controller
|
||||
return response()->json(['message' => 'Application not found.'], 404);
|
||||
}
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -2844,12 +2783,10 @@ class ApplicationsController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -2932,7 +2869,7 @@ class ApplicationsController extends Controller
|
||||
|
||||
return str($domain)->trim()->lower();
|
||||
});
|
||||
if (count($errors) > 0) {
|
||||
if ($errors !== []) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => $errors,
|
||||
@@ -2947,5 +2884,7 @@ class ApplicationsController extends Controller
|
||||
], 422);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Jobs\DeleteResourceJob;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
@@ -73,7 +74,7 @@ class DatabasesController extends Controller
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
$projects = Project::query()->where('team_id', $teamId)->get();
|
||||
$databases = collect();
|
||||
foreach ($projects as $project) {
|
||||
$databases = $databases->merge($project->databases());
|
||||
@@ -246,7 +247,7 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -276,11 +277,9 @@ class DatabasesController extends Controller
|
||||
if (! $database) {
|
||||
return response()->json(['message' => 'Database not found.'], 404);
|
||||
}
|
||||
if ($request->is_public && $request->public_port) {
|
||||
if (isPublicPortAlreadyUsed($database->destination->server, $request->public_port, $database->id)) {
|
||||
if ($request->is_public && $request->public_port && isPublicPortAlreadyUsed($database->destination->server, $request->public_port, $database->id)) {
|
||||
return response()->json(['message' => 'Public port already used by another database.'], 400);
|
||||
}
|
||||
}
|
||||
switch ($database->type()) {
|
||||
case 'standalone-postgresql':
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'postgres_user', 'postgres_password', 'postgres_db', 'postgres_initdb_args', 'postgres_host_auth_method', 'postgres_conf'];
|
||||
@@ -472,12 +471,10 @@ class DatabasesController extends Controller
|
||||
break;
|
||||
}
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1019,7 +1016,7 @@ class DatabasesController extends Controller
|
||||
return $this->create_database($request, NewDatabaseTypes::MONGODB);
|
||||
}
|
||||
|
||||
public function create_database(Request $request, NewDatabaseTypes $type)
|
||||
public function create_database(Request $request, NewDatabaseTypes $newDatabaseTypes)
|
||||
{
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'postgres_user', 'postgres_password', 'postgres_db', 'postgres_initdb_args', 'postgres_host_auth_method', 'postgres_conf', 'clickhouse_admin_user', 'clickhouse_admin_password', 'dragonfly_password', 'redis_password', 'redis_conf', 'keydb_password', 'keydb_conf', 'mariadb_conf', 'mariadb_root_password', 'mariadb_user', 'mariadb_password', 'mariadb_database', 'mongo_conf', 'mongo_initdb_root_username', 'mongo_initdb_root_password', 'mongo_initdb_database', 'mysql_root_password', 'mysql_password', 'mysql_user', 'mysql_database', 'mysql_conf'];
|
||||
|
||||
@@ -1029,17 +1026,15 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if (! empty($extraFields)) {
|
||||
if ($extraFields !== []) {
|
||||
$errors = collect([]);
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1080,11 +1075,9 @@ class DatabasesController extends Controller
|
||||
return response()->json(['message' => 'Server has multiple destinations and you do not set destination_uuid.'], 400);
|
||||
}
|
||||
$destination = $destinations->first();
|
||||
if ($request->has('public_port') && $request->is_public) {
|
||||
if (isPublicPortAlreadyUsed($server, $request->public_port)) {
|
||||
if ($request->has('public_port') && $request->is_public && isPublicPortAlreadyUsed($server, $request->public_port)) {
|
||||
return response()->json(['message' => 'Public port already used by another database.'], 400);
|
||||
}
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'name' => 'string|max:255',
|
||||
'description' => 'string|nullable',
|
||||
@@ -1111,8 +1104,7 @@ class DatabasesController extends Controller
|
||||
'errors' => $validator->errors(),
|
||||
], 422);
|
||||
}
|
||||
if ($request->public_port) {
|
||||
if ($request->public_port < 1024 || $request->public_port > 65535) {
|
||||
if ($request->public_port && ($request->public_port < 1024 || $request->public_port > 65535)) {
|
||||
return response()->json([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
@@ -1120,8 +1112,7 @@ class DatabasesController extends Controller
|
||||
],
|
||||
], 422);
|
||||
}
|
||||
}
|
||||
if ($type === NewDatabaseTypes::POSTGRESQL) {
|
||||
if ($newDatabaseTypes === NewDatabaseTypes::POSTGRESQL) {
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'postgres_user', 'postgres_password', 'postgres_db', 'postgres_initdb_args', 'postgres_host_auth_method', 'postgres_conf'];
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'postgres_user' => 'string',
|
||||
@@ -1132,12 +1123,10 @@ class DatabasesController extends Controller
|
||||
'postgres_conf' => 'string',
|
||||
]);
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1180,19 +1169,18 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||
} elseif ($type === NewDatabaseTypes::MARIADB) {
|
||||
}
|
||||
if ($newDatabaseTypes === NewDatabaseTypes::MARIADB) {
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', '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(), [
|
||||
'clickhouse_admin_user' => 'string',
|
||||
'clickhouse_admin_password' => 'string',
|
||||
]);
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1225,7 +1213,6 @@ class DatabasesController extends Controller
|
||||
if ($instantDeploy) {
|
||||
StartDatabase::dispatch($database);
|
||||
}
|
||||
|
||||
$database->refresh();
|
||||
$payload = [
|
||||
'uuid' => $database->uuid,
|
||||
@@ -1236,7 +1223,8 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||
} elseif ($type === NewDatabaseTypes::MYSQL) {
|
||||
}
|
||||
if ($newDatabaseTypes === NewDatabaseTypes::MYSQL) {
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mysql_root_password', 'mysql_password', 'mysql_user', 'mysql_database', 'mysql_conf'];
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'mysql_root_password' => 'string',
|
||||
@@ -1246,12 +1234,10 @@ class DatabasesController extends Controller
|
||||
'mysql_conf' => 'string',
|
||||
]);
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1284,7 +1270,6 @@ class DatabasesController extends Controller
|
||||
if ($instantDeploy) {
|
||||
StartDatabase::dispatch($database);
|
||||
}
|
||||
|
||||
$database->refresh();
|
||||
$payload = [
|
||||
'uuid' => $database->uuid,
|
||||
@@ -1295,19 +1280,18 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||
} elseif ($type === NewDatabaseTypes::REDIS) {
|
||||
}
|
||||
if ($newDatabaseTypes === NewDatabaseTypes::REDIS) {
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'redis_password', 'redis_conf'];
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'redis_password' => 'string',
|
||||
'redis_conf' => 'string',
|
||||
]);
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1340,7 +1324,6 @@ class DatabasesController extends Controller
|
||||
if ($instantDeploy) {
|
||||
StartDatabase::dispatch($database);
|
||||
}
|
||||
|
||||
$database->refresh();
|
||||
$payload = [
|
||||
'uuid' => $database->uuid,
|
||||
@@ -1351,19 +1334,17 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||
} elseif ($type === NewDatabaseTypes::DRAGONFLY) {
|
||||
}
|
||||
if ($newDatabaseTypes === NewDatabaseTypes::DRAGONFLY) {
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'dragonfly_password'];
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'dragonfly_password' => 'string',
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1371,7 +1352,6 @@ class DatabasesController extends Controller
|
||||
'errors' => $errors,
|
||||
], 422);
|
||||
}
|
||||
|
||||
removeUnnecessaryFieldsFromRequest($request);
|
||||
$database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all());
|
||||
if ($instantDeploy) {
|
||||
@@ -1381,19 +1361,18 @@ class DatabasesController extends Controller
|
||||
return response()->json(serializeApiResponse([
|
||||
'uuid' => $database->uuid,
|
||||
]))->setStatusCode(201);
|
||||
} elseif ($type === NewDatabaseTypes::KEYDB) {
|
||||
}
|
||||
if ($newDatabaseTypes === NewDatabaseTypes::KEYDB) {
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'keydb_password', 'keydb_conf'];
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'keydb_password' => 'string',
|
||||
'keydb_conf' => 'string',
|
||||
]);
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1426,7 +1405,6 @@ class DatabasesController extends Controller
|
||||
if ($instantDeploy) {
|
||||
StartDatabase::dispatch($database);
|
||||
}
|
||||
|
||||
$database->refresh();
|
||||
$payload = [
|
||||
'uuid' => $database->uuid,
|
||||
@@ -1437,19 +1415,18 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||
} elseif ($type === NewDatabaseTypes::CLICKHOUSE) {
|
||||
}
|
||||
if ($newDatabaseTypes === NewDatabaseTypes::CLICKHOUSE) {
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'clickhouse_admin_user', 'clickhouse_admin_password'];
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'clickhouse_admin_user' => 'string',
|
||||
'clickhouse_admin_password' => 'string',
|
||||
]);
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1462,7 +1439,6 @@ class DatabasesController extends Controller
|
||||
if ($instantDeploy) {
|
||||
StartDatabase::dispatch($database);
|
||||
}
|
||||
|
||||
$database->refresh();
|
||||
$payload = [
|
||||
'uuid' => $database->uuid,
|
||||
@@ -1473,7 +1449,7 @@ class DatabasesController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||
} elseif ($type === NewDatabaseTypes::MONGODB) {
|
||||
}
|
||||
$allowedFields = ['name', 'description', 'image', 'public_port', 'is_public', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'mongo_conf', 'mongo_initdb_root_username', 'mongo_initdb_root_password', 'mongo_initdb_database'];
|
||||
$validator = customApiValidator($request->all(), [
|
||||
'mongo_conf' => 'string',
|
||||
@@ -1482,12 +1458,10 @@ class DatabasesController extends Controller
|
||||
'mongo_initdb_database' => 'string',
|
||||
]);
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -1520,7 +1494,6 @@ class DatabasesController extends Controller
|
||||
if ($instantDeploy) {
|
||||
StartDatabase::dispatch($database);
|
||||
}
|
||||
|
||||
$database->refresh();
|
||||
$payload = [
|
||||
'uuid' => $database->uuid,
|
||||
@@ -1533,9 +1506,6 @@ class DatabasesController extends Controller
|
||||
return response()->json(serializeApiResponse($payload))->setStatusCode(201);
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Invalid database type requested.'], 400);
|
||||
}
|
||||
|
||||
#[OA\Delete(
|
||||
summary: 'Delete',
|
||||
description: 'Delete database by UUID.',
|
||||
@@ -1594,7 +1564,7 @@ class DatabasesController extends Controller
|
||||
public function delete_by_uuid(Request $request)
|
||||
{
|
||||
$teamId = getTeamIdFromToken();
|
||||
$cleanup = filter_var($request->query->get('cleanup', true), FILTER_VALIDATE_BOOLEAN);
|
||||
filter_var($request->query->get('cleanup', true), FILTER_VALIDATE_BOOLEAN);
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
|
@@ -5,8 +5,10 @@ namespace App\Http\Controllers\Api;
|
||||
use App\Actions\Database\StartDatabase;
|
||||
use App\Actions\Service\StartService;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use App\Models\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
use OpenApi\Attributes as OA;
|
||||
@@ -65,7 +67,7 @@ class DeployController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$servers = Server::whereTeamId($teamId)->get();
|
||||
$deployments_per_server = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $servers->pluck('id'))->get()->sortBy('id');
|
||||
$deployments_per_server = ApplicationDeploymentQueue::query()->whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $servers->pluck('id'))->get()->sortBy('id');
|
||||
$deployments_per_server = $deployments_per_server->map(function ($deployment) {
|
||||
return $this->removeSensitiveData($deployment);
|
||||
});
|
||||
@@ -121,7 +123,7 @@ class DeployController extends Controller
|
||||
if (! $uuid) {
|
||||
return response()->json(['message' => 'UUID is required.'], 400);
|
||||
}
|
||||
$deployment = ApplicationDeploymentQueue::where('deployment_uuid', $uuid)->first();
|
||||
$deployment = ApplicationDeploymentQueue::query()->where('deployment_uuid', $uuid)->first();
|
||||
if (! $deployment) {
|
||||
return response()->json(['message' => 'Deployment not found.'], 404);
|
||||
}
|
||||
@@ -196,7 +198,8 @@ class DeployController extends Controller
|
||||
}
|
||||
if ($tags) {
|
||||
return $this->by_tags($tags, $teamId, $force);
|
||||
} elseif ($uuids) {
|
||||
}
|
||||
if ($uuids) {
|
||||
return $this->by_uuids($uuids, $teamId, $force);
|
||||
}
|
||||
|
||||
@@ -245,7 +248,7 @@ class DeployController extends Controller
|
||||
$deployments = collect();
|
||||
$payload = collect();
|
||||
foreach ($tags as $tag) {
|
||||
$found_tag = Tag::where(['name' => $tag, 'team_id' => $team_id])->first();
|
||||
$found_tag = Tag::query()->where(['name' => $tag, 'team_id' => $team_id])->first();
|
||||
if (! $found_tag) {
|
||||
// $message->push("Tag {$tag} not found.");
|
||||
continue;
|
||||
@@ -257,15 +260,15 @@ class DeployController extends Controller
|
||||
|
||||
continue;
|
||||
}
|
||||
foreach ($applications as $resource) {
|
||||
['message' => $return_message, 'deployment_uuid' => $deployment_uuid] = $this->deploy_resource($resource, $force);
|
||||
foreach ($applications as $application) {
|
||||
['message' => $return_message, 'deployment_uuid' => $deployment_uuid] = $this->deploy_resource($application, $force);
|
||||
if ($deployment_uuid) {
|
||||
$deployments->push(['resource_uuid' => $resource->uuid, 'deployment_uuid' => $deployment_uuid->toString()]);
|
||||
$deployments->push(['resource_uuid' => $application->uuid, 'deployment_uuid' => $deployment_uuid->toString()]);
|
||||
}
|
||||
$message = $message->merge($return_message);
|
||||
}
|
||||
foreach ($services as $resource) {
|
||||
['message' => $return_message] = $this->deploy_resource($resource, $force);
|
||||
foreach ($services as $service) {
|
||||
['message' => $return_message] = $this->deploy_resource($service, $force);
|
||||
$message = $message->merge($return_message);
|
||||
}
|
||||
}
|
||||
@@ -289,7 +292,7 @@ class DeployController extends Controller
|
||||
return ['message' => "Resource ($resource) not found.", 'deployment_uuid' => $deployment_uuid];
|
||||
}
|
||||
switch ($resource?->getMorphClass()) {
|
||||
case \App\Models\Application::class:
|
||||
case Application::class:
|
||||
$deployment_uuid = new Cuid2;
|
||||
queue_application_deployment(
|
||||
application: $resource,
|
||||
@@ -298,7 +301,7 @@ class DeployController extends Controller
|
||||
);
|
||||
$message = "Application {$resource->name} deployment queued.";
|
||||
break;
|
||||
case \App\Models\Service::class:
|
||||
case Service::class:
|
||||
StartService::run($resource);
|
||||
$message = "Service {$resource->name} started. It could take a while, be patient.";
|
||||
break;
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Project;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
@@ -96,6 +97,7 @@ class ProjectController extends Controller
|
||||
}
|
||||
|
||||
$project->load(['environments']);
|
||||
|
||||
return response()->json(
|
||||
serializeApiResponse($project),
|
||||
);
|
||||
@@ -223,7 +225,7 @@ class ProjectController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -232,12 +234,10 @@ class ProjectController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -246,7 +246,7 @@ class ProjectController extends Controller
|
||||
], 422);
|
||||
}
|
||||
|
||||
$project = Project::create([
|
||||
$project = Project::query()->create([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
'team_id' => $teamId,
|
||||
@@ -321,7 +321,7 @@ class ProjectController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -330,12 +330,10 @@ class ProjectController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
|
@@ -43,7 +43,7 @@ class ResourcesController extends Controller
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
$projects = Project::query()->where('team_id', $teamId)->get();
|
||||
$resources = collect();
|
||||
$resources->push($projects->pluck('applications')->flatten());
|
||||
$resources->push($projects->pluck('services')->flatten());
|
||||
|
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PrivateKey;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
@@ -58,7 +59,7 @@ class SecurityController extends Controller
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$keys = PrivateKey::where('team_id', $teamId)->get();
|
||||
$keys = PrivateKey::query()->where('team_id', $teamId)->get();
|
||||
|
||||
return response()->json($this->removeSensitiveData($keys));
|
||||
}
|
||||
@@ -102,7 +103,7 @@ class SecurityController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
|
||||
$key = PrivateKey::where('team_id', $teamId)->where('uuid', $request->uuid)->first();
|
||||
$key = PrivateKey::query()->where('team_id', $teamId)->where('uuid', $request->uuid)->first();
|
||||
|
||||
if (is_null($key)) {
|
||||
return response()->json([
|
||||
@@ -172,7 +173,7 @@ class SecurityController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -195,7 +196,7 @@ class SecurityController extends Controller
|
||||
if (! $request->description) {
|
||||
$request->offsetSet('description', 'Created by Coolify via API');
|
||||
}
|
||||
$key = PrivateKey::create([
|
||||
$privateKey = PrivateKey::query()->create([
|
||||
'team_id' => $teamId,
|
||||
'name' => $request->name,
|
||||
'description' => $request->description,
|
||||
@@ -203,7 +204,7 @@ class SecurityController extends Controller
|
||||
]);
|
||||
|
||||
return response()->json(serializeApiResponse([
|
||||
'uuid' => $key->uuid,
|
||||
'uuid' => $privateKey->uuid,
|
||||
]))->setStatusCode(201);
|
||||
}
|
||||
|
||||
@@ -267,7 +268,7 @@ class SecurityController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -278,12 +279,10 @@ class SecurityController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -291,7 +290,7 @@ class SecurityController extends Controller
|
||||
'errors' => $errors,
|
||||
], 422);
|
||||
}
|
||||
$foundKey = PrivateKey::where('team_id', $teamId)->where('uuid', $request->uuid)->first();
|
||||
$foundKey = PrivateKey::query()->where('team_id', $teamId)->where('uuid', $request->uuid)->first();
|
||||
if (is_null($foundKey)) {
|
||||
return response()->json([
|
||||
'message' => 'Private Key not found.',
|
||||
@@ -355,7 +354,7 @@ class SecurityController extends Controller
|
||||
return response()->json(['message' => 'UUID is required.'], 422);
|
||||
}
|
||||
|
||||
$key = PrivateKey::where('team_id', $teamId)->where('uuid', $request->uuid)->first();
|
||||
$key = PrivateKey::query()->where('team_id', $teamId)->where('uuid', $request->uuid)->first();
|
||||
if (is_null($key)) {
|
||||
return response()->json(['message' => 'Private Key not found.'], 404);
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ use App\Models\Application;
|
||||
use App\Models\PrivateKey;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server as ModelsServer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Stringable;
|
||||
@@ -294,7 +295,7 @@ class ServersController extends Controller
|
||||
|
||||
return response()->json(serializeApiResponse($domains));
|
||||
}
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
$projects = Project::query()->where('team_id', $teamId)->get();
|
||||
$domains = collect();
|
||||
$applications = $projects->pluck('applications')->flatten();
|
||||
$settings = instanceSettings();
|
||||
@@ -305,8 +306,8 @@ class ServersController extends Controller
|
||||
$f = str($fqdn)->replace('http://', '')->replace('https://', '')->explode('/');
|
||||
|
||||
return str(str($f[0])->explode(':')[0]);
|
||||
})->filter(function (Stringable $fqdn) {
|
||||
return $fqdn->isNotEmpty();
|
||||
})->filter(function (Stringable $stringable) {
|
||||
return $stringable->isNotEmpty();
|
||||
});
|
||||
|
||||
if ($ip === 'host.docker.internal') {
|
||||
@@ -341,13 +342,13 @@ class ServersController extends Controller
|
||||
foreach ($services as $service) {
|
||||
$service_applications = $service->applications;
|
||||
if ($service_applications->count() > 0) {
|
||||
foreach ($service_applications as $application) {
|
||||
$fqdn = str($application->fqdn)->explode(',')->map(function ($fqdn) {
|
||||
foreach ($service_applications as $service_application) {
|
||||
$fqdn = str($service_application->fqdn)->explode(',')->map(function ($fqdn) {
|
||||
$f = str($fqdn)->replace('http://', '')->replace('https://', '')->explode('/');
|
||||
|
||||
return str(str($f[0])->explode(':')[0]);
|
||||
})->filter(function (Stringable $fqdn) {
|
||||
return $fqdn->isNotEmpty();
|
||||
})->filter(function (Stringable $stringable) {
|
||||
return $stringable->isNotEmpty();
|
||||
});
|
||||
if ($ip === 'host.docker.internal') {
|
||||
if ($settings->public_ipv4) {
|
||||
@@ -459,7 +460,7 @@ class ServersController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -475,12 +476,10 @@ class ServersController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -616,7 +615,7 @@ class ServersController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -632,12 +631,10 @@ class ServersController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
|
@@ -11,6 +11,7 @@ use App\Models\EnvironmentVariable;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
@@ -75,7 +76,7 @@ class ServicesController extends Controller
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$projects = Project::where('team_id', $teamId)->get();
|
||||
$projects = Project::query()->where('team_id', $teamId)->get();
|
||||
$services = collect();
|
||||
foreach ($projects as $project) {
|
||||
$services->push($project->services()->get());
|
||||
@@ -245,7 +246,7 @@ class ServicesController extends Controller
|
||||
}
|
||||
|
||||
$return = validateIncomingRequest($request);
|
||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||
if ($return instanceof JsonResponse) {
|
||||
return $return;
|
||||
}
|
||||
$validator = customApiValidator($request->all(), [
|
||||
@@ -261,12 +262,10 @@ class ServicesController extends Controller
|
||||
]);
|
||||
|
||||
$extraFields = array_diff(array_keys($request->all()), $allowedFields);
|
||||
if ($validator->fails() || ! empty($extraFields)) {
|
||||
if ($validator->fails() || $extraFields !== []) {
|
||||
$errors = $validator->errors();
|
||||
if (! empty($extraFields)) {
|
||||
foreach ($extraFields as $field) {
|
||||
$errors->add($field, 'This field is not allowed.');
|
||||
}
|
||||
foreach ($extraFields as $extraField) {
|
||||
$errors->add($extraField, 'This field is not allowed.');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
@@ -315,7 +314,7 @@ class ServicesController extends Controller
|
||||
$oneClickDotEnvs = data_get($services, "$oneClickServiceName.envs", null);
|
||||
if ($oneClickDotEnvs) {
|
||||
$oneClickDotEnvs = str(base64_decode($oneClickDotEnvs))->split('/\r\n|\r|\n/')->filter(function ($value) {
|
||||
return ! empty($value);
|
||||
return $value !== '' && $value !== '0';
|
||||
});
|
||||
}
|
||||
if ($oneClickService) {
|
||||
@@ -331,7 +330,7 @@ class ServicesController extends Controller
|
||||
if ($oneClickServiceName === 'cloudflared') {
|
||||
data_set($service_payload, 'connect_to_docker_network', true);
|
||||
}
|
||||
$service = Service::create($service_payload);
|
||||
$service = Service::query()->create($service_payload);
|
||||
$service->name = "$oneClickServiceName-".$service->uuid;
|
||||
$service->save();
|
||||
if ($oneClickDotEnvs?->count() > 0) {
|
||||
@@ -343,7 +342,7 @@ class ServicesController extends Controller
|
||||
$command = $value->after('SERVICE_')->beforeLast('_');
|
||||
$generatedValue = generateEnvValue($command->value(), $service);
|
||||
}
|
||||
EnvironmentVariable::create([
|
||||
EnvironmentVariable::query()->create([
|
||||
'key' => $key,
|
||||
'value' => $generatedValue,
|
||||
'resourceable_id' => $service->id,
|
||||
@@ -373,11 +372,9 @@ class ServicesController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
} else {
|
||||
return response()->json(['message' => 'Invalid service type.', 'valid_service_types' => $serviceKeys], 400);
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Invalid service type.'], 400);
|
||||
return response()->json(['message' => 'Invalid service type.', 'valid_service_types' => $serviceKeys], 400);
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
@@ -428,7 +425,7 @@ class ServicesController extends Controller
|
||||
if (! $request->uuid) {
|
||||
return response()->json(['message' => 'UUID is required.'], 404);
|
||||
}
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -493,7 +490,7 @@ class ServicesController extends Controller
|
||||
if (! $request->uuid) {
|
||||
return response()->json(['message' => 'UUID is required.'], 404);
|
||||
}
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -566,7 +563,7 @@ class ServicesController extends Controller
|
||||
if (is_null($teamId)) {
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -670,7 +667,7 @@ class ServicesController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -791,7 +788,7 @@ class ServicesController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -907,7 +904,7 @@ class ServicesController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -1009,12 +1006,12 @@ class ServicesController extends Controller
|
||||
return invalidTokenResponse();
|
||||
}
|
||||
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
|
||||
$env = EnvironmentVariable::where('uuid', $request->env_uuid)
|
||||
$env = EnvironmentVariable::query()->where('uuid', $request->env_uuid)
|
||||
->where('resourceable_type', Service::class)
|
||||
->where('resourceable_id', $service->id)
|
||||
->first();
|
||||
@@ -1089,7 +1086,7 @@ class ServicesController extends Controller
|
||||
if (! $uuid) {
|
||||
return response()->json(['message' => 'UUID is required.'], 400);
|
||||
}
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -1167,7 +1164,7 @@ class ServicesController extends Controller
|
||||
if (! $uuid) {
|
||||
return response()->json(['message' => 'UUID is required.'], 400);
|
||||
}
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
@@ -1245,7 +1242,7 @@ class ServicesController extends Controller
|
||||
if (! $uuid) {
|
||||
return response()->json(['message' => 'UUID is required.'], 400);
|
||||
}
|
||||
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
$service = Service::query()->whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
|
||||
if (! $service) {
|
||||
return response()->json(['message' => 'Service not found.'], 404);
|
||||
}
|
||||
|
@@ -39,9 +39,9 @@ class Controller extends BaseController
|
||||
return view('auth.verify-email');
|
||||
}
|
||||
|
||||
public function email_verify(EmailVerificationRequest $request)
|
||||
public function email_verify(EmailVerificationRequest $emailVerificationRequest)
|
||||
{
|
||||
$request->fulfill();
|
||||
$emailVerificationRequest->fulfill();
|
||||
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
@@ -139,9 +139,10 @@ class Controller extends BaseController
|
||||
refreshSession($invitation->team);
|
||||
|
||||
return redirect()->route('team.index');
|
||||
} else {
|
||||
abort(400, 'Invitation expired.');
|
||||
}
|
||||
abort(400, 'Invitation expired.');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function revoke_invitation()
|
||||
|
@@ -46,10 +46,7 @@ class MagicController extends Controller
|
||||
|
||||
public function newProject()
|
||||
{
|
||||
$project = Project::firstOrCreate(
|
||||
['name' => request()->query('name') ?? generate_random_name()],
|
||||
['team_id' => currentTeam()->id]
|
||||
);
|
||||
$project = Project::query()->firstOrCreate(['name' => request()->query('name') ?? generate_random_name()], ['team_id' => currentTeam()->id]);
|
||||
|
||||
return response()->json([
|
||||
'project_uuid' => $project->uuid,
|
||||
@@ -58,10 +55,7 @@ class MagicController extends Controller
|
||||
|
||||
public function newEnvironment()
|
||||
{
|
||||
$environment = Environment::firstOrCreate(
|
||||
['name' => request()->query('name') ?? generate_random_name()],
|
||||
['project_id' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->firstOrFail()->id]
|
||||
);
|
||||
$environment = Environment::query()->firstOrCreate(['name' => request()->query('name') ?? generate_random_name()], ['project_id' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->firstOrFail()->id]);
|
||||
|
||||
return response()->json([
|
||||
'environment_name' => $environment->name,
|
||||
@@ -70,12 +64,10 @@ class MagicController extends Controller
|
||||
|
||||
public function newTeam()
|
||||
{
|
||||
$team = Team::create(
|
||||
[
|
||||
$team = Team::query()->create([
|
||||
'name' => request()->query('name') ?? generate_random_name(),
|
||||
'personal_team' => false,
|
||||
],
|
||||
);
|
||||
]);
|
||||
auth()->user()->teams()->attach($team, ['role' => 'admin']);
|
||||
refreshSession();
|
||||
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
@@ -26,7 +27,7 @@ class OauthController extends Controller
|
||||
abort(403, 'Registration is disabled');
|
||||
}
|
||||
|
||||
$user = User::create([
|
||||
$user = User::query()->create([
|
||||
'name' => $oauthUser->name,
|
||||
'email' => $oauthUser->email,
|
||||
]);
|
||||
@@ -34,7 +35,7 @@ class OauthController extends Controller
|
||||
Auth::login($user);
|
||||
|
||||
return redirect('/');
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$errorCode = $e instanceof HttpException ? 'auth.failed' : 'auth.failed.callback';
|
||||
|
||||
return redirect()->route('login')->withErrors([__($errorCode)]);
|
||||
|
@@ -17,13 +17,13 @@ class UploadController extends BaseController
|
||||
if (is_null($resource)) {
|
||||
return response()->json(['error' => 'You do not have permission for this database'], 500);
|
||||
}
|
||||
$receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
|
||||
$fileReceiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
|
||||
|
||||
if ($receiver->isUploaded() === false) {
|
||||
if ($fileReceiver->isUploaded() === false) {
|
||||
throw new UploadMissingFileException;
|
||||
}
|
||||
|
||||
$save = $receiver->receive();
|
||||
$save = $fileReceiver->receive();
|
||||
|
||||
if ($save->isFinished()) {
|
||||
return $this->saveFile($save->getFile(), $resource);
|
||||
@@ -57,22 +57,22 @@ class UploadController extends BaseController
|
||||
// 'mime_type' => $mime
|
||||
// ]);
|
||||
// }
|
||||
protected function saveFile(UploadedFile $file, $resource)
|
||||
protected function saveFile(UploadedFile $uploadedFile, $resource)
|
||||
{
|
||||
$mime = str_replace('/', '-', $file->getMimeType());
|
||||
$mime = str_replace('/', '-', $uploadedFile->getMimeType());
|
||||
$filePath = "upload/{$resource->uuid}";
|
||||
$finalPath = storage_path('app/'.$filePath);
|
||||
$file->move($finalPath, 'restore');
|
||||
$uploadedFile->move($finalPath, 'restore');
|
||||
|
||||
return response()->json([
|
||||
'mime_type' => $mime,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function createFilename(UploadedFile $file)
|
||||
protected function createFilename(UploadedFile $uploadedFile)
|
||||
{
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
$filename = str_replace('.'.$extension, '', $file->getClientOriginalName()); // Filename without extension
|
||||
$extension = $uploadedFile->getClientOriginalExtension();
|
||||
$filename = str_replace('.'.$extension, '', $uploadedFile->getClientOriginalName()); // Filename without extension
|
||||
|
||||
$filename .= '_'.md5(time()).'.'.$extension;
|
||||
|
||||
|
@@ -30,7 +30,7 @@ class Bitbucket extends Controller
|
||||
$json = json_encode($data);
|
||||
Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Bitbicket::manual_bitbucket", $json);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$return_payloads = collect([]);
|
||||
$payload = $request->collect();
|
||||
@@ -63,7 +63,7 @@ class Bitbucket extends Controller
|
||||
$pull_request_html_url = data_get($payload, 'pullrequest.links.html.href');
|
||||
$commit = data_get($payload, 'pullrequest.source.commit.hash');
|
||||
}
|
||||
$applications = Application::where('git_repository', 'like', "%$full_name%");
|
||||
$applications = Application::query()->where('git_repository', 'like', "%$full_name%");
|
||||
$applications = $applications->where('git_branch', $branch)->get();
|
||||
if ($applications->isEmpty()) {
|
||||
return response([
|
||||
@@ -122,10 +122,10 @@ class Bitbucket extends Controller
|
||||
if ($x_bitbucket_event === 'pullrequest:created') {
|
||||
if ($application->isPRDeployable()) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if (! $found) {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
$pr_app = ApplicationPreview::create([
|
||||
$pr_app = ApplicationPreview::query()->create([
|
||||
'git_type' => 'bitbucket',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -134,7 +134,7 @@ class Bitbucket extends Controller
|
||||
]);
|
||||
$pr_app->generate_preview_fqdn_compose();
|
||||
} else {
|
||||
ApplicationPreview::create([
|
||||
ApplicationPreview::query()->create([
|
||||
'git_type' => 'bitbucket',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -165,7 +165,7 @@ class Bitbucket extends Controller
|
||||
}
|
||||
}
|
||||
if ($x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') {
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if ($found) {
|
||||
$found->delete();
|
||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||
|
@@ -25,7 +25,7 @@ class Gitea extends Controller
|
||||
return Str::contains($file, $x_gitea_delivery);
|
||||
})->first();
|
||||
if ($gitea_delivery_found) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$data = [
|
||||
'attributes' => $request->attributes->all(),
|
||||
@@ -40,7 +40,7 @@ class Gitea extends Controller
|
||||
$json = json_encode($data);
|
||||
Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitea::manual_{$x_gitea_delivery}", $json);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$x_gitea_event = Str::lower($request->header('X-Gitea-Event'));
|
||||
$x_hub_signature_256 = Str::after($request->header('X-Hub-Signature-256'), 'sha256=');
|
||||
@@ -76,7 +76,7 @@ class Gitea extends Controller
|
||||
if (! $branch) {
|
||||
return response('Nothing to do. No branch found in the request.');
|
||||
}
|
||||
$applications = Application::where('git_repository', 'like', "%$full_name%");
|
||||
$applications = Application::query()->where('git_repository', 'like', "%$full_name%");
|
||||
if ($x_gitea_event === 'push') {
|
||||
$applications = $applications->where('git_branch', $branch)->get();
|
||||
if ($applications->isEmpty()) {
|
||||
@@ -155,10 +155,10 @@ class Gitea extends Controller
|
||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
||||
if ($application->isPRDeployable()) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if (! $found) {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
$pr_app = ApplicationPreview::create([
|
||||
$pr_app = ApplicationPreview::query()->create([
|
||||
'git_type' => 'gitea',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -167,7 +167,7 @@ class Gitea extends Controller
|
||||
]);
|
||||
$pr_app->generate_preview_fqdn_compose();
|
||||
} else {
|
||||
ApplicationPreview::create([
|
||||
ApplicationPreview::query()->create([
|
||||
'git_type' => 'gitea',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -198,7 +198,7 @@ class Gitea extends Controller
|
||||
}
|
||||
}
|
||||
if ($action === 'closed') {
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if ($found) {
|
||||
$found->delete();
|
||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||
|
@@ -31,7 +31,7 @@ class Github extends Controller
|
||||
return Str::contains($file, $x_github_delivery);
|
||||
})->first();
|
||||
if ($github_delivery_found) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$data = [
|
||||
'attributes' => $request->attributes->all(),
|
||||
@@ -46,7 +46,7 @@ class Github extends Controller
|
||||
$json = json_encode($data);
|
||||
Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::manual_{$x_github_delivery}", $json);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$x_github_event = Str::lower($request->header('X-GitHub-Event'));
|
||||
$x_hub_signature_256 = Str::after($request->header('X-Hub-Signature-256'), 'sha256=');
|
||||
@@ -82,7 +82,7 @@ class Github extends Controller
|
||||
if (! $branch) {
|
||||
return response('Nothing to do. No branch found in the request.');
|
||||
}
|
||||
$applications = Application::where('git_repository', 'like', "%$full_name%");
|
||||
$applications = Application::query()->where('git_repository', 'like', "%$full_name%");
|
||||
if ($x_github_event === 'push') {
|
||||
$applications = $applications->where('git_branch', $branch)->get();
|
||||
if ($applications->isEmpty()) {
|
||||
@@ -161,10 +161,10 @@ class Github extends Controller
|
||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
||||
if ($application->isPRDeployable()) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if (! $found) {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
$pr_app = ApplicationPreview::create([
|
||||
$pr_app = ApplicationPreview::query()->create([
|
||||
'git_type' => 'github',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -173,7 +173,7 @@ class Github extends Controller
|
||||
]);
|
||||
$pr_app->generate_preview_fqdn_compose();
|
||||
} else {
|
||||
ApplicationPreview::create([
|
||||
ApplicationPreview::query()->create([
|
||||
'git_type' => 'github',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -204,7 +204,7 @@ class Github extends Controller
|
||||
}
|
||||
}
|
||||
if ($action === 'closed') {
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if ($found) {
|
||||
$found->delete();
|
||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||
@@ -245,7 +245,7 @@ class Github extends Controller
|
||||
return Str::contains($file, $x_github_delivery);
|
||||
})->first();
|
||||
if ($github_delivery_found) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$data = [
|
||||
'attributes' => $request->attributes->all(),
|
||||
@@ -260,7 +260,7 @@ class Github extends Controller
|
||||
$json = json_encode($data);
|
||||
Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::normal_{$x_github_delivery}", $json);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$x_github_event = Str::lower($request->header('X-GitHub-Event'));
|
||||
$x_github_hook_installation_target_id = $request->header('X-GitHub-Hook-Installation-Target-Id');
|
||||
@@ -270,17 +270,15 @@ class Github extends Controller
|
||||
// Just pong
|
||||
return response('pong');
|
||||
}
|
||||
$github_app = GithubApp::where('app_id', $x_github_hook_installation_target_id)->first();
|
||||
$github_app = GithubApp::query()->where('app_id', $x_github_hook_installation_target_id)->first();
|
||||
if (is_null($github_app)) {
|
||||
return response('Nothing to do. No GitHub App found.');
|
||||
}
|
||||
$webhook_secret = data_get($github_app, 'webhook_secret');
|
||||
$hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret);
|
||||
if (config('app.env') !== 'local') {
|
||||
if (! hash_equals($x_hub_signature_256, $hmac)) {
|
||||
if (config('app.env') !== 'local' && ! hash_equals($x_hub_signature_256, $hmac)) {
|
||||
return response('Invalid signature.');
|
||||
}
|
||||
}
|
||||
if ($x_github_event === 'installation' || $x_github_event === 'installation_repositories') {
|
||||
// Installation handled by setup redirect url. Repositories queried on-demand.
|
||||
$action = data_get($payload, 'action');
|
||||
@@ -312,7 +310,7 @@ class Github extends Controller
|
||||
if (! $id || ! $branch) {
|
||||
return response('Nothing to do. No id or branch found.');
|
||||
}
|
||||
$applications = Application::where('repository_project_id', $id)->whereRelation('source', 'is_public', false);
|
||||
$applications = Application::query()->where('repository_project_id', $id)->whereRelation('source', 'is_public', false);
|
||||
if ($x_github_event === 'push') {
|
||||
$applications = $applications->where('git_branch', $branch)->get();
|
||||
if ($applications->isEmpty()) {
|
||||
@@ -381,9 +379,9 @@ class Github extends Controller
|
||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
||||
if ($application->isPRDeployable()) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if (! $found) {
|
||||
ApplicationPreview::create([
|
||||
ApplicationPreview::query()->create([
|
||||
'git_type' => 'github',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -413,7 +411,7 @@ class Github extends Controller
|
||||
}
|
||||
}
|
||||
if ($action === 'closed' || $action === 'close') {
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if ($found) {
|
||||
$containers = getCurrentApplicationContainerStatus($application->destination->server, $application->id, $pull_request_id);
|
||||
if ($containers->isNotEmpty()) {
|
||||
@@ -453,7 +451,7 @@ class Github extends Controller
|
||||
try {
|
||||
$code = $request->get('code');
|
||||
$state = $request->get('state');
|
||||
$github_app = GithubApp::where('uuid', $state)->firstOrFail();
|
||||
$github_app = GithubApp::query()->where('uuid', $state)->firstOrFail();
|
||||
$api_url = data_get($github_app, 'api_url');
|
||||
$data = Http::withBody(null)->accept('application/vnd.github+json')->post("$api_url/app-manifests/$code/conversions")->throw()->json();
|
||||
$id = data_get($data, 'id');
|
||||
@@ -462,7 +460,7 @@ class Github extends Controller
|
||||
$client_secret = data_get($data, 'client_secret');
|
||||
$private_key = data_get($data, 'pem');
|
||||
$webhook_secret = data_get($data, 'webhook_secret');
|
||||
$private_key = PrivateKey::create([
|
||||
$private_key = PrivateKey::query()->create([
|
||||
'name' => "github-app-{$slug}",
|
||||
'private_key' => $private_key,
|
||||
'team_id' => $github_app->team_id,
|
||||
@@ -501,11 +499,11 @@ class Github extends Controller
|
||||
$json = json_encode($data);
|
||||
Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::install_{$installation_id}", $json);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
$source = $request->get('source');
|
||||
$setup_action = $request->get('setup_action');
|
||||
$github_app = GithubApp::where('uuid', $source)->firstOrFail();
|
||||
$github_app = GithubApp::query()->where('uuid', $source)->firstOrFail();
|
||||
if ($setup_action === 'install') {
|
||||
$github_app->installation_id = $installation_id;
|
||||
$github_app->save();
|
||||
|
@@ -31,7 +31,7 @@ class Gitlab extends Controller
|
||||
$json = json_encode($data);
|
||||
Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitlab::manual_gitlab", $json);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$return_payloads = collect([]);
|
||||
@@ -93,7 +93,7 @@ class Gitlab extends Controller
|
||||
return response($return_payloads);
|
||||
}
|
||||
}
|
||||
$applications = Application::where('git_repository', 'like', "%$full_name%");
|
||||
$applications = Application::query()->where('git_repository', 'like', "%$full_name%");
|
||||
if ($x_gitlab_event === 'push') {
|
||||
$applications = $applications->where('git_branch', $branch)->get();
|
||||
if ($applications->isEmpty()) {
|
||||
@@ -181,10 +181,10 @@ class Gitlab extends Controller
|
||||
if ($action === 'open' || $action === 'opened' || $action === 'synchronize' || $action === 'reopened' || $action === 'reopen' || $action === 'update') {
|
||||
if ($application->isPRDeployable()) {
|
||||
$deployment_uuid = new Cuid2;
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if (! $found) {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
$pr_app = ApplicationPreview::create([
|
||||
$pr_app = ApplicationPreview::query()->create([
|
||||
'git_type' => 'gitlab',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -193,7 +193,7 @@ class Gitlab extends Controller
|
||||
]);
|
||||
$pr_app->generate_preview_fqdn_compose();
|
||||
} else {
|
||||
ApplicationPreview::create([
|
||||
ApplicationPreview::query()->create([
|
||||
'git_type' => 'gitlab',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $pull_request_id,
|
||||
@@ -223,7 +223,7 @@ class Gitlab extends Controller
|
||||
]);
|
||||
}
|
||||
} elseif ($action === 'closed' || $action === 'close' || $action === 'merge') {
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
$found = ApplicationPreview::query()->where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if ($found) {
|
||||
$found->delete();
|
||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||
|
@@ -40,7 +40,7 @@ class Stripe extends Controller
|
||||
|
||||
return response('Webhook received. Cool cool cool cool cool.', 200);
|
||||
}
|
||||
$this->webhook = Webhook::create([
|
||||
$this->webhook = Webhook::query()->create([
|
||||
'type' => 'stripe',
|
||||
'payload' => $request->getContent(),
|
||||
]);
|
||||
|
@@ -2,7 +2,35 @@
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\ApiAbility;
|
||||
use App\Http\Middleware\ApiSensitiveData;
|
||||
use App\Http\Middleware\Authenticate;
|
||||
use App\Http\Middleware\CheckForcePasswordReset;
|
||||
use App\Http\Middleware\DecideWhatToDoWithUser;
|
||||
use App\Http\Middleware\EncryptCookies;
|
||||
use App\Http\Middleware\PreventRequestsDuringMaintenance;
|
||||
use App\Http\Middleware\RedirectIfAuthenticated;
|
||||
use App\Http\Middleware\TrimStrings;
|
||||
use App\Http\Middleware\TrustProxies;
|
||||
use App\Http\Middleware\ValidateSignature;
|
||||
use App\Http\Middleware\VerifyCsrfToken;
|
||||
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
|
||||
use Illuminate\Auth\Middleware\Authorize;
|
||||
use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
|
||||
use Illuminate\Auth\Middleware\RequirePassword;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\Http\Middleware\HandleCors;
|
||||
use Illuminate\Http\Middleware\SetCacheHeaders;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
|
||||
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
@@ -15,12 +43,12 @@ class Kernel extends HttpKernel
|
||||
*/
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
TrustProxies::class,
|
||||
HandleCors::class,
|
||||
PreventRequestsDuringMaintenance::class,
|
||||
ValidatePostSize::class,
|
||||
TrimStrings::class,
|
||||
ConvertEmptyStringsToNull::class,
|
||||
|
||||
];
|
||||
|
||||
@@ -31,21 +59,21 @@ class Kernel extends HttpKernel
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\CheckForcePasswordReset::class,
|
||||
\App\Http\Middleware\DecideWhatToDoWithUser::class,
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartSession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
CheckForcePasswordReset::class,
|
||||
DecideWhatToDoWithUser::class,
|
||||
|
||||
],
|
||||
|
||||
'api' => [
|
||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
ThrottleRequests::class.':api',
|
||||
SubstituteBindings::class,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -57,19 +85,19 @@ class Kernel extends HttpKernel
|
||||
* @var array<string, class-string|string>
|
||||
*/
|
||||
protected $middlewareAliases = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,
|
||||
'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,
|
||||
'api.ability' => \App\Http\Middleware\ApiAbility::class,
|
||||
'api.sensitive' => \App\Http\Middleware\ApiSensitiveData::class,
|
||||
'auth' => Authenticate::class,
|
||||
'auth.basic' => AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => AuthenticateSession::class,
|
||||
'cache.headers' => SetCacheHeaders::class,
|
||||
'can' => Authorize::class,
|
||||
'guest' => RedirectIfAuthenticated::class,
|
||||
'password.confirm' => RequirePassword::class,
|
||||
'signed' => ValidateSignature::class,
|
||||
'throttle' => ThrottleRequests::class,
|
||||
'verified' => EnsureEmailIsVerified::class,
|
||||
'abilities' => CheckAbilities::class,
|
||||
'ability' => CheckForAnyAbility::class,
|
||||
'api.ability' => ApiAbility::class,
|
||||
'api.sensitive' => ApiSensitiveData::class,
|
||||
];
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;
|
||||
|
||||
class ApiAbility extends CheckForAnyAbility
|
||||
@@ -14,11 +16,11 @@ class ApiAbility extends CheckForAnyAbility
|
||||
}
|
||||
|
||||
return parent::handle($request, $next, ...$abilities);
|
||||
} catch (\Illuminate\Auth\AuthenticationException $e) {
|
||||
} catch (AuthenticationException $e) {
|
||||
return response()->json([
|
||||
'message' => 'Unauthenticated.',
|
||||
], 401);
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
return response()->json([
|
||||
'message' => 'Missing required permissions: '.implode(', ', $abilities),
|
||||
], 403);
|
||||
|
@@ -18,14 +18,12 @@ class ApiAllowed
|
||||
return response()->json(['success' => true, 'message' => 'API is disabled.'], 403);
|
||||
}
|
||||
|
||||
if (! isDev()) {
|
||||
if ($settings->allowed_ips) {
|
||||
if (! isDev() && $settings->allowed_ips) {
|
||||
$allowedIps = explode(',', $settings->allowed_ips);
|
||||
if (! in_array($request->ip(), $allowedIps)) {
|
||||
return response()->json(['success' => true, 'message' => 'You are not allowed to access the API.'], 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ class CheckForcePasswordReset
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request):Response $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
@@ -33,15 +33,13 @@ class DecideWhatToDoWithUser
|
||||
|
||||
return redirect()->route('verify.email');
|
||||
}
|
||||
if (! isSubscriptionActive() && ! isSubscriptionOnGracePeriod()) {
|
||||
if (! in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
|
||||
if (! isSubscriptionActive() && ! isSubscriptionOnGracePeriod() && ! in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
|
||||
if (Str::startsWith($request->path(), 'invitations')) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return redirect()->route('subscription.index');
|
||||
}
|
||||
}
|
||||
if (showBoarding() && ! in_array($request->path(), allowedPathsForBoardingAccounts())) {
|
||||
if (Str::startsWith($request->path(), 'invitations')) {
|
||||
return $next($request);
|
||||
|
@@ -13,11 +13,11 @@ class RedirectIfAuthenticated
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request):Response $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
$guards = empty($guards) ? [null] : $guards;
|
||||
$guards = $guards === [] ? [null] : $guards;
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
if (Auth::guard($guard)->check()) {
|
||||
|
@@ -88,7 +88,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private bool $is_this_additional_server = false;
|
||||
|
||||
private ?ApplicationPreview $preview = null;
|
||||
private ?ApplicationPreview $applicationPreview = null;
|
||||
|
||||
private ?string $git_type = null;
|
||||
|
||||
@@ -174,8 +174,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
$this->nixpacks_plan_json = collect([]);
|
||||
|
||||
$this->application_deployment_queue = ApplicationDeploymentQueue::find($application_deployment_queue_id);
|
||||
$this->application = Application::find($this->application_deployment_queue->application_id);
|
||||
$this->application_deployment_queue = ApplicationDeploymentQueue::query()->find($application_deployment_queue_id);
|
||||
$this->application = Application::query()->find($this->application_deployment_queue->application_id);
|
||||
$this->build_pack = data_get($this->application, 'build_pack');
|
||||
$this->build_args = collect([]);
|
||||
|
||||
@@ -199,7 +199,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if ($source) {
|
||||
$this->source = $source->getMorphClass()::where('id', $this->application->source->id)->first();
|
||||
}
|
||||
$this->server = Server::find($this->application_deployment_queue->server_id);
|
||||
$this->server = Server::query()->find($this->application_deployment_queue->server_id);
|
||||
$this->timeout = $this->server->settings->dynamic_timeout;
|
||||
$this->destination = $this->server->destinations()->where('id', $this->application_deployment_queue->destination_id)->first();
|
||||
$this->server = $this->mainServer = $this->destination->server;
|
||||
@@ -225,17 +225,15 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
// Set preview fqdn
|
||||
if ($this->pull_request_id !== 0) {
|
||||
$this->preview = $this->application->generate_preview_fqdn($this->pull_request_id);
|
||||
$this->applicationPreview = $this->application->generate_preview_fqdn($this->pull_request_id);
|
||||
if ($this->application->is_github_based()) {
|
||||
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::IN_PROGRESS);
|
||||
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->applicationPreview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::IN_PROGRESS);
|
||||
}
|
||||
if ($this->application->build_pack === 'dockerfile') {
|
||||
if (data_get($this->application, 'dockerfile_location')) {
|
||||
if ($this->application->build_pack === 'dockerfile' && data_get($this->application, 'dockerfile_location')) {
|
||||
$this->dockerfile_location = $this->application->dockerfile_location;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function tags(): array
|
||||
{
|
||||
@@ -263,15 +261,15 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if (count($allContainers) > 0) {
|
||||
$allContainers = $allContainers[0];
|
||||
$allContainers = collect($allContainers)->sort()->values();
|
||||
foreach ($allContainers as $container) {
|
||||
$containerName = data_get($container, 'Name');
|
||||
foreach ($allContainers as $allContainer) {
|
||||
$containerName = data_get($allContainer, 'Name');
|
||||
if ($containerName === 'coolify-proxy') {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/-(\d{12})/', $containerName)) {
|
||||
continue;
|
||||
}
|
||||
$containerIp = data_get($container, 'IPv4Address');
|
||||
$containerIp = data_get($allContainer, 'IPv4Address');
|
||||
if ($containerName && $containerIp) {
|
||||
$containerIp = str($containerIp)->before('/');
|
||||
$ips->put($containerName, $containerIp->value());
|
||||
@@ -312,7 +310,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->decide_what_to_do();
|
||||
} catch (Exception $e) {
|
||||
if ($this->pull_request_id !== 0 && $this->application->is_github_based()) {
|
||||
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::ERROR);
|
||||
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->applicationPreview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::ERROR);
|
||||
}
|
||||
$this->fail($e);
|
||||
throw $e;
|
||||
@@ -340,7 +338,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->just_restart();
|
||||
|
||||
return;
|
||||
} elseif ($this->pull_request_id !== 0) {
|
||||
}
|
||||
if ($this->pull_request_id !== 0) {
|
||||
$this->deploy_pull_request();
|
||||
} elseif ($this->application->dockerfile) {
|
||||
$this->deploy_simple_dockerfile();
|
||||
@@ -364,10 +363,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
GetContainersStatus::dispatch($this->server);
|
||||
}
|
||||
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
||||
if ($this->pull_request_id !== 0) {
|
||||
if ($this->application->is_github_based()) {
|
||||
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::FINISHED);
|
||||
}
|
||||
if ($this->pull_request_id !== 0 && $this->application->is_github_based()) {
|
||||
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->applicationPreview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::FINISHED);
|
||||
}
|
||||
$this->run_post_deployment_command();
|
||||
$this->application->isConfigurationChanged(true);
|
||||
@@ -470,7 +467,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$yaml = $composeFile = $this->application->docker_compose_raw;
|
||||
$this->save_environment_variables();
|
||||
} else {
|
||||
$composeFile = $this->application->parse(pull_request_id: $this->pull_request_id, preview_id: data_get($this->preview, 'id'));
|
||||
$composeFile = $this->application->parse(pull_request_id: $this->pull_request_id, preview_id: data_get($this->applicationPreview, 'id'));
|
||||
$this->save_environment_variables();
|
||||
if (! is_null($this->env_filename)) {
|
||||
$services = collect(data_get($composeFile, 'services', []));
|
||||
@@ -553,8 +550,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
['command' => $command, 'hidden' => true],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if ($this->docker_compose_custom_start_command) {
|
||||
} elseif ($this->docker_compose_custom_start_command) {
|
||||
$this->write_deployment_configurations();
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
|
||||
@@ -582,7 +578,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->write_deployment_configurations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->application_deployment_queue->addLogEntry('New container started.');
|
||||
}
|
||||
@@ -688,7 +683,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->server = $this->build_server;
|
||||
}
|
||||
}
|
||||
if (isset($this->docker_compose_base64)) {
|
||||
if ($this->docker_compose_base64 !== null) {
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->original_server;
|
||||
}
|
||||
@@ -773,9 +768,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->application_deployment_queue->addLogEntry('Failed to push image to docker registry. Please check debug logs for more information.');
|
||||
if ($forceFail) {
|
||||
throw new RuntimeException($e->getMessage(), 69420);
|
||||
}
|
||||
throw new RuntimeException($e->getMessage(), 69420, $e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,9 +839,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->rolling_update();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
$this->application_deployment_queue->addLogEntry('Configuration changed. Rebuilding image.');
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry('Configuration changed. Rebuilding image.');
|
||||
} else {
|
||||
$this->application_deployment_queue->addLogEntry("Image not found ({$this->production_image_name}). Building new image.");
|
||||
}
|
||||
@@ -908,11 +900,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
}
|
||||
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_FQDN')->isEmpty()) {
|
||||
$envs->push("COOLIFY_FQDN={$this->preview->fqdn}");
|
||||
$envs->push("COOLIFY_DOMAIN_URL={$this->preview->fqdn}");
|
||||
$envs->push("COOLIFY_FQDN={$this->applicationPreview->fqdn}");
|
||||
$envs->push("COOLIFY_DOMAIN_URL={$this->applicationPreview->fqdn}");
|
||||
}
|
||||
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_URL')->isEmpty()) {
|
||||
$url = str($this->preview->fqdn)->replace('http://', '')->replace('https://', '');
|
||||
$url = str($this->applicationPreview->fqdn)->replace('http://', '')->replace('https://', '');
|
||||
$envs->push("COOLIFY_URL={$url}");
|
||||
$envs->push("COOLIFY_DOMAIN_FQDN={$url}");
|
||||
}
|
||||
@@ -927,25 +919,21 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
add_coolify_default_environment_variables($this->application, $envs, $this->application->environment_variables_preview);
|
||||
|
||||
foreach ($sorted_environment_variables_preview as $env) {
|
||||
$real_value = $env->real_value;
|
||||
if ($env->version === '4.0.0-beta.239') {
|
||||
$real_value = $env->real_value;
|
||||
} else {
|
||||
if ($env->is_literal || $env->is_multiline) {
|
||||
foreach ($sorted_environment_variables_preview as $sorted_environment_variable_preview) {
|
||||
$real_value = $sorted_environment_variable_preview->real_value;
|
||||
if ($sorted_environment_variable_preview->version === '4.0.0-beta.239') {
|
||||
$real_value = $sorted_environment_variable_preview->real_value;
|
||||
} elseif ($sorted_environment_variable_preview->is_literal || $sorted_environment_variable_preview->is_multiline) {
|
||||
$real_value = '\''.$real_value.'\'';
|
||||
} else {
|
||||
$real_value = escapeEnvVariables($env->real_value);
|
||||
$real_value = escapeEnvVariables($sorted_environment_variable_preview->real_value);
|
||||
}
|
||||
}
|
||||
$envs->push($env->key.'='.$real_value);
|
||||
$envs->push($sorted_environment_variable_preview->key.'='.$real_value);
|
||||
}
|
||||
// Add PORT if not exists, use the first port as default
|
||||
if ($this->build_pack !== 'dockercompose') {
|
||||
if ($this->application->environment_variables_preview->where('key', 'PORT')->isEmpty()) {
|
||||
if ($this->build_pack !== 'dockercompose' && $this->application->environment_variables_preview->where('key', 'PORT')->isEmpty()) {
|
||||
$envs->push("PORT={$ports[0]}");
|
||||
}
|
||||
}
|
||||
// Add HOST if not exists
|
||||
if ($this->application->environment_variables_preview->where('key', 'HOST')->isEmpty()) {
|
||||
$envs->push('HOST=0.0.0.0');
|
||||
@@ -986,25 +974,21 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
add_coolify_default_environment_variables($this->application, $envs, $this->application->environment_variables);
|
||||
|
||||
foreach ($sorted_environment_variables as $env) {
|
||||
$real_value = $env->real_value;
|
||||
if ($env->version === '4.0.0-beta.239') {
|
||||
$real_value = $env->real_value;
|
||||
} else {
|
||||
if ($env->is_literal || $env->is_multiline) {
|
||||
foreach ($sorted_environment_variables as $sorted_environment_variable) {
|
||||
$real_value = $sorted_environment_variable->real_value;
|
||||
if ($sorted_environment_variable->version === '4.0.0-beta.239') {
|
||||
$real_value = $sorted_environment_variable->real_value;
|
||||
} elseif ($sorted_environment_variable->is_literal || $sorted_environment_variable->is_multiline) {
|
||||
$real_value = '\''.$real_value.'\'';
|
||||
} else {
|
||||
$real_value = escapeEnvVariables($env->real_value);
|
||||
$real_value = escapeEnvVariables($sorted_environment_variable->real_value);
|
||||
}
|
||||
}
|
||||
$envs->push($env->key.'='.$real_value);
|
||||
$envs->push($sorted_environment_variable->key.'='.$real_value);
|
||||
}
|
||||
// Add PORT if not exists, use the first port as default
|
||||
if ($this->build_pack !== 'dockercompose') {
|
||||
if ($this->application->environment_variables->where('key', 'PORT')->isEmpty()) {
|
||||
if ($this->build_pack !== 'dockercompose' && $this->application->environment_variables->where('key', 'PORT')->isEmpty()) {
|
||||
$envs->push("PORT={$ports[0]}");
|
||||
}
|
||||
}
|
||||
// Add HOST if not exists
|
||||
if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) {
|
||||
$envs->push('HOST=0.0.0.0');
|
||||
@@ -1067,11 +1051,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private function elixir_finetunes()
|
||||
{
|
||||
if ($this->pull_request_id === 0) {
|
||||
$envType = 'environment_variables';
|
||||
} else {
|
||||
$envType = 'environment_variables_preview';
|
||||
}
|
||||
$envType = $this->pull_request_id === 0 ? 'environment_variables' : 'environment_variables_preview';
|
||||
$mix_env = $this->application->{$envType}->where('key', 'MIX_ENV')->first();
|
||||
if ($mix_env) {
|
||||
if ($mix_env->is_build_time === false) {
|
||||
@@ -1106,11 +1086,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private function laravel_finetunes()
|
||||
{
|
||||
if ($this->pull_request_id === 0) {
|
||||
$envType = 'environment_variables';
|
||||
} else {
|
||||
$envType = 'environment_variables_preview';
|
||||
}
|
||||
$envType = $this->pull_request_id === 0 ? 'environment_variables' : 'environment_variables_preview';
|
||||
$nixpacks_php_fallback_path = $this->application->{$envType}->where('key', 'NIXPACKS_PHP_FALLBACK_PATH')->first();
|
||||
$nixpacks_php_root_dir = $this->application->{$envType}->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
|
||||
|
||||
@@ -1194,7 +1170,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->application_deployment_queue->addLogEntry('Custom healthcheck found, skipping default healthcheck.');
|
||||
}
|
||||
// ray('New container name: ', $this->container_name);
|
||||
if ($this->container_name) {
|
||||
if ($this->container_name !== '' && $this->container_name !== '0') {
|
||||
$counter = 1;
|
||||
$this->application_deployment_queue->addLogEntry('Waiting for healthcheck to pass on the new container.');
|
||||
if ($this->full_healthcheck_url) {
|
||||
@@ -1344,13 +1320,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
throw new RuntimeException('Docker config file (~/.docker/config.json) not found on the build server. Please run "docker login" to login to the docker registry on the server.');
|
||||
}
|
||||
$runCommand = "docker run -d --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||
} else {
|
||||
if ($this->dockerConfigFileExists === 'OK') {
|
||||
} elseif ($this->dockerConfigFileExists === 'OK') {
|
||||
$runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||
} else {
|
||||
$runCommand = "docker run -d --network {$this->destination->network} --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||
}
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry("Preparing container with helper image: $helperImage.");
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
@@ -1389,7 +1363,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
return;
|
||||
}
|
||||
foreach ($destination_ids as $destination_id) {
|
||||
$destination = StandaloneDocker::find($destination_id);
|
||||
$destination = StandaloneDocker::query()->find($destination_id);
|
||||
$server = $destination->server;
|
||||
if ($server->team_id !== $this->mainServer->team_id) {
|
||||
$this->application_deployment_queue->addLogEntry("Skipping deployment to {$server->name}. Not in the same team?!");
|
||||
@@ -1417,17 +1391,13 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
private function set_coolify_variables()
|
||||
{
|
||||
$this->coolify_variables = "SOURCE_COMMIT={$this->commit} ";
|
||||
if ($this->pull_request_id === 0) {
|
||||
$fqdn = $this->application->fqdn;
|
||||
} else {
|
||||
$fqdn = $this->preview->fqdn;
|
||||
}
|
||||
$fqdn = $this->pull_request_id === 0 ? $this->application->fqdn : $this->applicationPreview->fqdn;
|
||||
if (isset($fqdn)) {
|
||||
$this->coolify_variables .= "COOLIFY_FQDN={$fqdn} ";
|
||||
$url = str($fqdn)->replace('http://', '')->replace('https://', '');
|
||||
$this->coolify_variables .= "COOLIFY_URL={$url} ";
|
||||
}
|
||||
if (isset($this->application->git_branch)) {
|
||||
if (property_exists($this->application, 'git_branch') && $this->application->git_branch !== null) {
|
||||
$this->coolify_variables .= "COOLIFY_BRANCH={$this->application->git_branch} ";
|
||||
}
|
||||
}
|
||||
@@ -1598,9 +1568,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if ($this->application->install_command) {
|
||||
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
|
||||
}
|
||||
$nixpacks_command .= " {$this->workdir}";
|
||||
|
||||
return $nixpacks_command;
|
||||
return $nixpacks_command." {$this->workdir}";
|
||||
}
|
||||
|
||||
private function generate_nixpacks_env_variables()
|
||||
@@ -1666,7 +1635,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
});
|
||||
if ($found_caddy_labels->count() === 0) {
|
||||
if ($this->pull_request_id !== 0) {
|
||||
$domains = str(data_get($this->preview, 'fqdn'))->explode(',');
|
||||
$domains = str(data_get($this->applicationPreview, 'fqdn'))->explode(',');
|
||||
} else {
|
||||
$domains = str(data_get($this->application, 'fqdn'))->explode(',');
|
||||
}
|
||||
@@ -1682,13 +1651,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
$this->application->custom_labels = base64_encode($labels->implode("\n"));
|
||||
$this->application->save();
|
||||
} else {
|
||||
if (! $this->application->settings->is_container_label_readonly_enabled) {
|
||||
$labels = collect(generateLabelsApplication($this->application, $this->preview));
|
||||
}
|
||||
} elseif (! $this->application->settings->is_container_label_readonly_enabled) {
|
||||
$labels = collect(generateLabelsApplication($this->application, $this->applicationPreview));
|
||||
}
|
||||
if ($this->pull_request_id !== 0) {
|
||||
$labels = collect(generateLabelsApplication($this->application, $this->preview));
|
||||
$labels = collect(generateLabelsApplication($this->application, $this->applicationPreview));
|
||||
}
|
||||
if ($this->application->settings->is_container_label_escape_enabled) {
|
||||
$labels = $labels->map(function ($value, $key) {
|
||||
@@ -1874,8 +1841,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$docker_compose['services'][$this->application->uuid] = array_merge_recursive($docker_compose['services'][$this->application->uuid], $custom_compose);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (count($custom_compose) > 0) {
|
||||
} elseif (count($custom_compose) > 0) {
|
||||
$ipv4 = data_get($custom_compose, 'ip.0');
|
||||
$ipv6 = data_get($custom_compose, 'ip6.0');
|
||||
data_forget($custom_compose, 'ip');
|
||||
@@ -1892,7 +1858,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$docker_compose['services'][$this->container_name] = array_merge_recursive($docker_compose['services'][$this->container_name], $custom_compose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->docker_compose = Yaml::dump($docker_compose, 10);
|
||||
$this->docker_compose_base64 = base64_encode($this->docker_compose);
|
||||
@@ -2105,9 +2070,8 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
} else {
|
||||
} elseif ($this->application->dockerfile) {
|
||||
// Pure Dockerfile based deployment
|
||||
if ($this->application->dockerfile) {
|
||||
if ($this->force_rebuild) {
|
||||
$build_command = "docker build --no-cache --pull {$this->buildTarget} {$this->addHosts} --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
|
||||
} else {
|
||||
@@ -2128,8 +2092,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
} else {
|
||||
if ($this->application->build_pack === 'nixpacks') {
|
||||
} elseif ($this->application->build_pack === 'nixpacks') {
|
||||
$this->nixpacks_plan = base64_encode($this->nixpacks_plan);
|
||||
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee /artifacts/thegameplan.json > /dev/null"), 'hidden' => true]);
|
||||
if ($this->force_rebuild) {
|
||||
@@ -2184,8 +2147,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry('Building docker image completed.');
|
||||
}
|
||||
|
||||
@@ -2214,7 +2175,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
["docker kill $containerName", 'hidden' => true, 'ignore_errors' => true]
|
||||
);
|
||||
}
|
||||
} catch (\Exception $error) {
|
||||
} catch (Exception $error) {
|
||||
$this->application_deployment_queue->addLogEntry("Error stopping container $containerName: ".$error->getMessage(), 'stderr');
|
||||
}
|
||||
|
||||
@@ -2267,8 +2228,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} pull"), 'hidden' => true],
|
||||
[executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} up --build -d"), 'hidden' => true],
|
||||
);
|
||||
} else {
|
||||
if ($this->use_build_server) {
|
||||
} elseif ($this->use_build_server) {
|
||||
$this->execute_remote_command(
|
||||
["{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->configuration_dir} -f {$this->configuration_dir}{$this->docker_compose_location} up --build -d", 'hidden' => true],
|
||||
);
|
||||
@@ -2277,7 +2237,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
[executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up --build -d"), 'hidden' => true],
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry('New container started.');
|
||||
}
|
||||
|
||||
@@ -2398,7 +2357,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
]);
|
||||
}
|
||||
if ($this->application_deployment_queue->status === ApplicationDeploymentStatus::FAILED->value) {
|
||||
$this->application->environment->project->team?->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview));
|
||||
$this->application->environment->project->team?->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->applicationPreview));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -2406,20 +2365,20 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
if (! $this->only_this_server) {
|
||||
$this->deploy_to_additional_destinations();
|
||||
}
|
||||
$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
|
||||
$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->applicationPreview));
|
||||
}
|
||||
}
|
||||
|
||||
public function failed(Throwable $exception): void
|
||||
public function failed(Throwable $throwable): void
|
||||
{
|
||||
$this->next(ApplicationDeploymentStatus::FAILED->value);
|
||||
$this->application_deployment_queue->addLogEntry('Oops something is not okay, are you okay? 😢', 'stderr');
|
||||
if (str($exception->getMessage())->isNotEmpty()) {
|
||||
$this->application_deployment_queue->addLogEntry($exception->getMessage(), 'stderr');
|
||||
if (str($throwable->getMessage())->isNotEmpty()) {
|
||||
$this->application_deployment_queue->addLogEntry($throwable->getMessage(), 'stderr');
|
||||
}
|
||||
|
||||
if ($this->application->build_pack !== 'dockercompose') {
|
||||
$code = $exception->getCode();
|
||||
$code = $throwable->getCode();
|
||||
if ($code !== 69420) {
|
||||
// 69420 means failed to push the image to the registry, so we don't need to remove the new version as it is the currently running one
|
||||
if ($this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty()) {
|
||||
|
@@ -11,6 +11,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Throwable;
|
||||
|
||||
class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
@@ -22,8 +23,8 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
public function __construct(
|
||||
public Application $application,
|
||||
public ApplicationPreview $preview,
|
||||
public ProcessStatus $status,
|
||||
public ApplicationPreview $applicationPreview,
|
||||
public ProcessStatus $processStatus,
|
||||
public ?string $deployment_uuid = null
|
||||
) {
|
||||
$this->onQueue('high');
|
||||
@@ -33,39 +34,42 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
try {
|
||||
if ($this->application->is_public_repository()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if ($this->status === ProcessStatus::CLOSED) {
|
||||
if ($this->processStatus === ProcessStatus::CLOSED) {
|
||||
$this->delete_comment();
|
||||
|
||||
return;
|
||||
} elseif ($this->status === ProcessStatus::IN_PROGRESS) {
|
||||
$this->body = "The preview deployment is in progress. 🟡\n\n";
|
||||
} elseif ($this->status === ProcessStatus::FINISHED) {
|
||||
$this->body = "The preview deployment is ready. 🟢\n\n";
|
||||
if ($this->preview->fqdn) {
|
||||
$this->body .= "[Open Preview]({$this->preview->fqdn}) | ";
|
||||
return null;
|
||||
}
|
||||
} elseif ($this->status === ProcessStatus::ERROR) {
|
||||
if ($this->processStatus === ProcessStatus::IN_PROGRESS) {
|
||||
$this->body = "The preview deployment is in progress. 🟡\n\n";
|
||||
} elseif ($this->processStatus === ProcessStatus::FINISHED) {
|
||||
$this->body = "The preview deployment is ready. 🟢\n\n";
|
||||
if ($this->applicationPreview->fqdn) {
|
||||
$this->body .= "[Open Preview]({$this->applicationPreview->fqdn}) | ";
|
||||
}
|
||||
} elseif ($this->processStatus === ProcessStatus::ERROR) {
|
||||
$this->body = "The preview deployment failed. 🔴\n\n";
|
||||
}
|
||||
$this->build_logs_url = base_url()."/project/{$this->application->environment->project->uuid}/{$this->application->environment->name}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
|
||||
|
||||
$this->body .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n";
|
||||
$this->body .= 'Last updated at: '.now()->toDateTimeString().' CET';
|
||||
if ($this->preview->pull_request_issue_comment_id) {
|
||||
if ($this->applicationPreview->pull_request_issue_comment_id) {
|
||||
$this->update_comment();
|
||||
} else {
|
||||
$this->create_comment();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
return $e;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function update_comment()
|
||||
{
|
||||
['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->preview->pull_request_issue_comment_id}", method: 'patch', data: [
|
||||
['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->applicationPreview->pull_request_issue_comment_id}", method: 'patch', data: [
|
||||
'body' => $this->body,
|
||||
], throwError: false);
|
||||
if (data_get($data, 'message') === 'Not Found') {
|
||||
@@ -75,15 +79,15 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private function create_comment()
|
||||
{
|
||||
['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/{$this->preview->pull_request_id}/comments", method: 'post', data: [
|
||||
['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/{$this->applicationPreview->pull_request_id}/comments", method: 'post', data: [
|
||||
'body' => $this->body,
|
||||
]);
|
||||
$this->preview->pull_request_issue_comment_id = $data['id'];
|
||||
$this->preview->save();
|
||||
$this->applicationPreview->pull_request_issue_comment_id = $data['id'];
|
||||
$this->applicationPreview->save();
|
||||
}
|
||||
|
||||
private function delete_comment()
|
||||
{
|
||||
githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->preview->pull_request_issue_comment_id}", method: 'delete');
|
||||
githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->applicationPreview->pull_request_issue_comment_id}", method: 'delete');
|
||||
}
|
||||
}
|
||||
|
@@ -34,14 +34,14 @@ class CheckAndStartSentinelJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
// If sentinel is running, check if it needs an update
|
||||
$runningVersion = instant_remote_process(['docker exec coolify-sentinel sh -c "curl http://127.0.0.1:8888/api/version"'], $this->server, false);
|
||||
if (empty($runningVersion)) {
|
||||
if ($runningVersion === null || $runningVersion === '' || $runningVersion === '0') {
|
||||
$runningVersion = '0.0.0';
|
||||
}
|
||||
if ($latestVersion === '0.0.0' && $runningVersion === '0.0.0') {
|
||||
StartSentinel::run(server: $this->server, restart: true, latestVersion: 'latest');
|
||||
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
if (version_compare($runningVersion, $latestVersion, '<')) {
|
||||
StartSentinel::run(server: $this->server, restart: true, latestVersion: $latestVersion);
|
||||
|
||||
@@ -49,4 +49,3 @@ class CheckAndStartSentinelJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Throwable;
|
||||
|
||||
class CheckForUpdatesJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
@@ -37,7 +38,7 @@ class CheckForUpdatesJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$settings->update(['new_version_available' => false]);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
// Consider implementing a notification to administrators
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Throwable;
|
||||
|
||||
class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
@@ -16,8 +17,6 @@ class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
public $timeout = 1000;
|
||||
|
||||
public function __construct() {}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
@@ -31,7 +30,7 @@ class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$settings->update(['helper_version' => $latest_version]);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
send_internal_notification('CheckHelperImageJob failed with: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Throwable;
|
||||
|
||||
class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, ShouldQueue
|
||||
{
|
||||
@@ -27,7 +28,7 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
|
||||
instant_remote_process(['docker container rm -f '.$containerId], $this->server, false);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
send_internal_notification('CleanupHelperContainersJob failed with error: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
@@ -12,13 +12,12 @@ use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Throwable;
|
||||
|
||||
class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct() {}
|
||||
|
||||
public function middleware(): array
|
||||
{
|
||||
return [(new WithoutOverlapping('cleanup-instance-stuffs'))->dontRelease()];
|
||||
@@ -28,7 +27,7 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho
|
||||
{
|
||||
try {
|
||||
$this->cleanupInvitationLink();
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
Log::error('CleanupInstanceStuffsJob failed with error: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ class CleanupStaleMultiplexedConnections implements ShouldQueue
|
||||
|
||||
foreach ($muxFiles as $muxFile) {
|
||||
$serverUuid = $this->extractServerUuidFromMuxFile($muxFile);
|
||||
$server = Server::where('uuid', $serverUuid)->first();
|
||||
$server = Server::query()->where('uuid', $serverUuid)->first();
|
||||
|
||||
if (! $server) {
|
||||
$this->removeMultiplexFile($muxFile);
|
||||
@@ -57,7 +57,7 @@ class CleanupStaleMultiplexedConnections implements ShouldQueue
|
||||
private function cleanupNonExistentServerConnections()
|
||||
{
|
||||
$muxFiles = Storage::disk('ssh-mux')->files();
|
||||
$existingServerUuids = Server::pluck('uuid')->toArray();
|
||||
$existingServerUuids = Server::query()->pluck('uuid')->toArray();
|
||||
|
||||
foreach ($muxFiles as $muxFile) {
|
||||
$serverUuid = $this->extractServerUuidFromMuxFile($muxFile);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user