commit
						5ebbd769e8
					
				
							
								
								
									
										25
									
								
								.github/workflows/fix-php-code-style-issues.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								.github/workflows/fix-php-code-style-issues.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | name: Fix PHP code style issues | ||||||
|  | 
 | ||||||
|  | on: [push] | ||||||
|  | 
 | ||||||
|  | permissions: | ||||||
|  |   contents: write | ||||||
|  | 
 | ||||||
|  | jobs: | ||||||
|  |   php-code-styling: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     timeout-minutes: 5 | ||||||
|  | 
 | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout code | ||||||
|  |         uses: actions/checkout@v4 | ||||||
|  |         with: | ||||||
|  |           ref: ${{ github.head_ref }} | ||||||
|  | 
 | ||||||
|  |       - name: Fix PHP code style issues | ||||||
|  |         uses: aglipanci/laravel-pint-action@2.4 | ||||||
|  | 
 | ||||||
|  |       - name: Commit changes | ||||||
|  |         uses: stefanzweifel/git-auto-commit-action@v5 | ||||||
|  |         with: | ||||||
|  |           commit_message: Fix styling | ||||||
| @ -3,17 +3,17 @@ | |||||||
| namespace App\Actions\Application; | namespace App\Actions\Application; | ||||||
| 
 | 
 | ||||||
| use App\Models\Application; | use App\Models\Application; | ||||||
| use App\Models\StandaloneDocker; |  | ||||||
| use App\Notifications\Application\StatusChanged; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class StopApplication | class StopApplication | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Application $application) |     public function handle(Application $application) | ||||||
|     { |     { | ||||||
|         if ($application->destination->server->isSwarm()) { |         if ($application->destination->server->isSwarm()) { | ||||||
|             instant_remote_process(["docker stack rm {$application->uuid}"], $application->destination->server); |             instant_remote_process(["docker stack rm {$application->uuid}"], $application->destination->server); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -23,7 +23,7 @@ class StopApplication | |||||||
|             $servers->push($server); |             $servers->push($server); | ||||||
|         }); |         }); | ||||||
|         foreach ($servers as $server) { |         foreach ($servers as $server) { | ||||||
|             if (!$server->isFunctional()) { |             if (! $server->isFunctional()) { | ||||||
|                 return 'Server is not functional'; |                 return 'Server is not functional'; | ||||||
|             } |             } | ||||||
|             $containers = getCurrentApplicationContainerStatus($server, $application->id, 0); |             $containers = getCurrentApplicationContainerStatus($server, $application->id, 0); | ||||||
|  | |||||||
| @ -9,12 +9,13 @@ use Lorisleiva\Actions\Concerns\AsAction; | |||||||
| class StopApplicationOneServer | class StopApplicationOneServer | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Application $application, Server $server) |     public function handle(Application $application, Server $server) | ||||||
|     { |     { | ||||||
|         if ($application->destination->server->isSwarm()) { |         if ($application->destination->server->isSwarm()) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if (!$server->isFunctional()) { |         if (! $server->isFunctional()) { | ||||||
|             return 'Server is not functional'; |             return 'Server is not functional'; | ||||||
|         } |         } | ||||||
|         try { |         try { | ||||||
| @ -32,6 +33,7 @@ class StopApplicationOneServer | |||||||
|             } |             } | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return $e->getMessage(); |             return $e->getMessage(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ use Spatie\Activitylog\Models\Activity; | |||||||
| class PrepareCoolifyTask | class PrepareCoolifyTask | ||||||
| { | { | ||||||
|     protected Activity $activity; |     protected Activity $activity; | ||||||
|  | 
 | ||||||
|     protected CoolifyTaskArgs $remoteProcessArgs; |     protected CoolifyTaskArgs $remoteProcessArgs; | ||||||
| 
 | 
 | ||||||
|     public function __construct(CoolifyTaskArgs $remoteProcessArgs) |     public function __construct(CoolifyTaskArgs $remoteProcessArgs) | ||||||
| @ -28,12 +29,12 @@ class PrepareCoolifyTask | |||||||
|                 ->withProperties($properties) |                 ->withProperties($properties) | ||||||
|                 ->performedOn($remoteProcessArgs->model) |                 ->performedOn($remoteProcessArgs->model) | ||||||
|                 ->event($remoteProcessArgs->type) |                 ->event($remoteProcessArgs->type) | ||||||
|                 ->log("[]"); |                 ->log('[]'); | ||||||
|         } else { |         } else { | ||||||
|             $this->activity = activity() |             $this->activity = activity() | ||||||
|                 ->withProperties($remoteProcessArgs->toArray()) |                 ->withProperties($remoteProcessArgs->toArray()) | ||||||
|                 ->event($remoteProcessArgs->type) |                 ->event($remoteProcessArgs->type) | ||||||
|                 ->log("[]"); |                 ->log('[]'); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -42,6 +43,7 @@ class PrepareCoolifyTask | |||||||
|         $job = new CoolifyTask($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); |         $job = new CoolifyTask($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($job); | ||||||
|         $this->activity->refresh(); |         $this->activity->refresh(); | ||||||
|  | 
 | ||||||
|         return $this->activity; |         return $this->activity; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -69,7 +69,7 @@ class RunRemoteProcess | |||||||
|         return collect($decoded) |         return collect($decoded) | ||||||
|             ->sortBy(fn ($i) => $i['order']) |             ->sortBy(fn ($i) => $i['order']) | ||||||
|             ->map(fn ($i) => $i['output']) |             ->map(fn ($i) => $i['output']) | ||||||
|             ->implode(""); |             ->implode(''); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function __invoke(): ProcessResult |     public function __invoke(): ProcessResult | ||||||
| @ -91,7 +91,7 @@ class RunRemoteProcess | |||||||
|             if ($processResult->exitCode() == 0) { |             if ($processResult->exitCode() == 0) { | ||||||
|                 $status = ProcessStatus::FINISHED; |                 $status = ProcessStatus::FINISHED; | ||||||
|             } |             } | ||||||
|             if ($processResult->exitCode() != 0 && !$this->ignore_errors) { |             if ($processResult->exitCode() != 0 && ! $this->ignore_errors) { | ||||||
|                 $status = ProcessStatus::ERROR; |                 $status = ProcessStatus::ERROR; | ||||||
|             } |             } | ||||||
|             // if (($processResult->exitCode() == 0 && $this->is_finished) || $this->activity->properties->get('status') === ProcessStatus::FINISHED->value) {
 |             // if (($processResult->exitCode() == 0 && $this->is_finished) || $this->activity->properties->get('status') === ProcessStatus::FINISHED->value) {
 | ||||||
| @ -109,14 +109,14 @@ class RunRemoteProcess | |||||||
|             'status' => $status->value, |             'status' => $status->value, | ||||||
|         ]); |         ]); | ||||||
|         $this->activity->save(); |         $this->activity->save(); | ||||||
|         if ($processResult->exitCode() != 0 && !$this->ignore_errors) { |         if ($processResult->exitCode() != 0 && ! $this->ignore_errors) { | ||||||
|             throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode()); |             throw new \RuntimeException($processResult->errorOutput(), $processResult->exitCode()); | ||||||
|         } |         } | ||||||
|         if ($this->call_event_on_finish) { |         if ($this->call_event_on_finish) { | ||||||
|             try { |             try { | ||||||
|                 if ($this->call_event_data) { |                 if ($this->call_event_data) { | ||||||
|                     event(resolve("App\\Events\\$this->call_event_on_finish", [ |                     event(resolve("App\\Events\\$this->call_event_on_finish", [ | ||||||
|                         "data" => $this->call_event_data, |                         'data' => $this->call_event_data, | ||||||
|                     ])); |                     ])); | ||||||
|                 } else { |                 } else { | ||||||
|                     event(resolve("App\\Events\\$this->call_event_on_finish", [ |                     event(resolve("App\\Events\\$this->call_event_on_finish", [ | ||||||
| @ -127,6 +127,7 @@ class RunRemoteProcess | |||||||
|                 ray($e); |                 ray($e); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $processResult; |         return $processResult; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -182,6 +183,7 @@ class RunRemoteProcess | |||||||
|         if ($description === null || count($description) === 0) { |         if ($description === null || count($description) === 0) { | ||||||
|             return 1; |             return 1; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return end($description)['order'] + 1; |         return end($description)['order'] + 1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,24 +4,25 @@ namespace App\Actions\Database; | |||||||
| 
 | 
 | ||||||
| use App\Models\StandaloneClickhouse; | use App\Models\StandaloneClickhouse; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartClickhouse | class StartClickhouse | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandaloneClickhouse $database; |     public StandaloneClickhouse $database; | ||||||
|  | 
 | ||||||
|     public array $commands = []; |     public array $commands = []; | ||||||
|  | 
 | ||||||
|     public string $configuration_dir; |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandaloneClickhouse $database) |     public function handle(StandaloneClickhouse $database) | ||||||
|     { |     { | ||||||
|         $this->database = $database; |         $this->database = $database; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
| @ -57,7 +58,7 @@ class StartClickhouse | |||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -65,27 +66,27 @@ class StartClickhouse | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -111,6 +112,7 @@ class StartClickhouse | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|  | 
 | ||||||
|         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -119,12 +121,13 @@ class StartClickhouse | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -141,6 +144,7 @@ class StartClickhouse | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -69,19 +69,19 @@ class StartDatabaseProxy | |||||||
|         } |         } | ||||||
|         if ($type === 'App\Models\StandaloneRedis') { |         if ($type === 'App\Models\StandaloneRedis') { | ||||||
|             $internalPort = 6379; |             $internalPort = 6379; | ||||||
|         } else if ($type === 'App\Models\StandalonePostgresql') { |         } elseif ($type === 'App\Models\StandalonePostgresql') { | ||||||
|             $internalPort = 5432; |             $internalPort = 5432; | ||||||
|         } else if ($type === 'App\Models\StandaloneMongodb') { |         } elseif ($type === 'App\Models\StandaloneMongodb') { | ||||||
|             $internalPort = 27017; |             $internalPort = 27017; | ||||||
|         } else if ($type === 'App\Models\StandaloneMysql') { |         } elseif ($type === 'App\Models\StandaloneMysql') { | ||||||
|             $internalPort = 3306; |             $internalPort = 3306; | ||||||
|         } else if ($type === 'App\Models\StandaloneMariadb') { |         } elseif ($type === 'App\Models\StandaloneMariadb') { | ||||||
|             $internalPort = 3306; |             $internalPort = 3306; | ||||||
|         } else if ($type === 'App\Models\StandaloneKeydb') { |         } elseif ($type === 'App\Models\StandaloneKeydb') { | ||||||
|             $internalPort = 6379; |             $internalPort = 6379; | ||||||
|         } else if ($type === 'App\Models\StandaloneDragonfly') { |         } elseif ($type === 'App\Models\StandaloneDragonfly') { | ||||||
|             $internalPort = 6379; |             $internalPort = 6379; | ||||||
|         } else if ($type === 'App\Models\StandaloneClickhouse') { |         } elseif ($type === 'App\Models\StandaloneClickhouse') { | ||||||
|             $internalPort = 9000; |             $internalPort = 9000; | ||||||
|         } |         } | ||||||
|         $configuration_dir = database_proxy_dir($database->uuid); |         $configuration_dir = database_proxy_dir($database->uuid); | ||||||
| @ -101,7 +101,7 @@ class StartDatabaseProxy | |||||||
|        } |        } | ||||||
|     } |     } | ||||||
|     EOF; |     EOF; | ||||||
|         $dockerfile = <<< EOF |         $dockerfile = <<< 'EOF' | ||||||
|     FROM nginx:stable-alpine |     FROM nginx:stable-alpine | ||||||
| 
 | 
 | ||||||
|     COPY nginx.conf /etc/nginx/nginx.conf |     COPY nginx.conf /etc/nginx/nginx.conf | ||||||
| @ -113,7 +113,7 @@ class StartDatabaseProxy | |||||||
|                         'context' => $configuration_dir, |                         'context' => $configuration_dir, | ||||||
|                         'dockerfile' => 'Dockerfile', |                         'dockerfile' => 'Dockerfile', | ||||||
|                     ], |                     ], | ||||||
|                     'image' => "nginx:stable-alpine", |                     'image' => 'nginx:stable-alpine', | ||||||
|                     'container_name' => $proxyContainerName, |                     'container_name' => $proxyContainerName, | ||||||
|                     'restart' => RESTART_MODE, |                     'restart' => RESTART_MODE, | ||||||
|                     'ports' => [ |                     'ports' => [ | ||||||
| @ -130,17 +130,17 @@ class StartDatabaseProxy | |||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 3, |                         'retries' => 3, | ||||||
|                         'start_period' => '1s' |                         'start_period' => '1s', | ||||||
|                     ], |                     ], | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $network => [ |                 $network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $network, |                     'name' => $network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         $dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2)); |         $dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2)); | ||||||
|         $nginxconf_base64 = base64_encode($nginxconf); |         $nginxconf_base64 = base64_encode($nginxconf); | ||||||
|  | |||||||
| @ -3,19 +3,19 @@ | |||||||
| namespace App\Actions\Database; | namespace App\Actions\Database; | ||||||
| 
 | 
 | ||||||
| use App\Models\StandaloneDragonfly; | use App\Models\StandaloneDragonfly; | ||||||
| use Illuminate\Support\Facades\Storage; |  | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartDragonfly | class StartDragonfly | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandaloneDragonfly $database; |     public StandaloneDragonfly $database; | ||||||
|     public array $commands = []; |  | ||||||
|     public string $configuration_dir; |  | ||||||
| 
 | 
 | ||||||
|  |     public array $commands = []; | ||||||
|  | 
 | ||||||
|  |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandaloneDragonfly $database) |     public function handle(StandaloneDragonfly $database) | ||||||
|     { |     { | ||||||
| @ -24,7 +24,7 @@ class StartDragonfly | |||||||
|         $startCommand = "dragonfly --requirepass {$this->database->dragonfly_password}"; |         $startCommand = "dragonfly --requirepass {$this->database->dragonfly_password}"; | ||||||
| 
 | 
 | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
| @ -48,7 +48,7 @@ class StartDragonfly | |||||||
|                         $this->database->destination->network, |                         $this->database->destination->network, | ||||||
|                     ], |                     ], | ||||||
|                     'ulimits' => [ |                     'ulimits' => [ | ||||||
|                         'memlock'=> '-1' |                         'memlock' => '-1', | ||||||
|                     ], |                     ], | ||||||
|                     'labels' => [ |                     'labels' => [ | ||||||
|                         'coolify.managed' => 'true', |                         'coolify.managed' => 'true', | ||||||
| @ -58,7 +58,7 @@ class StartDragonfly | |||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -66,27 +66,27 @@ class StartDragonfly | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -112,6 +112,7 @@ class StartDragonfly | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|  | 
 | ||||||
|         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -120,12 +121,13 @@ class StartDragonfly | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -142,6 +144,7 @@ class StartDragonfly | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,17 +5,18 @@ namespace App\Actions\Database; | |||||||
| use App\Models\StandaloneKeydb; | use App\Models\StandaloneKeydb; | ||||||
| use Illuminate\Support\Facades\Storage; | use Illuminate\Support\Facades\Storage; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartKeydb | class StartKeydb | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandaloneKeydb $database; |     public StandaloneKeydb $database; | ||||||
|     public array $commands = []; |  | ||||||
|     public string $configuration_dir; |  | ||||||
| 
 | 
 | ||||||
|  |     public array $commands = []; | ||||||
|  | 
 | ||||||
|  |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandaloneKeydb $database) |     public function handle(StandaloneKeydb $database) | ||||||
|     { |     { | ||||||
| @ -24,7 +25,7 @@ class StartKeydb | |||||||
|         $startCommand = "keydb-server --requirepass {$this->database->keydb_password} --appendonly yes"; |         $startCommand = "keydb-server --requirepass {$this->database->keydb_password} --appendonly yes"; | ||||||
| 
 | 
 | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
| @ -56,7 +57,7 @@ class StartKeydb | |||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -64,27 +65,27 @@ class StartKeydb | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -101,10 +102,10 @@ class StartKeydb | |||||||
|         if (count($volume_names) > 0) { |         if (count($volume_names) > 0) { | ||||||
|             $docker_compose['volumes'] = $volume_names; |             $docker_compose['volumes'] = $volume_names; | ||||||
|         } |         } | ||||||
|         if (!is_null($this->database->keydb_conf) || !empty($this->database->keydb_conf)) { |         if (! is_null($this->database->keydb_conf) || ! empty($this->database->keydb_conf)) { | ||||||
|             $docker_compose['services'][$container_name]['volumes'][] = [ |             $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|                 'type' => 'bind', |                 'type' => 'bind', | ||||||
|                 'source' => $this->configuration_dir . '/keydb.conf', |                 'source' => $this->configuration_dir.'/keydb.conf', | ||||||
|                 'target' => '/etc/keydb/keydb.conf', |                 'target' => '/etc/keydb/keydb.conf', | ||||||
|                 'read_only' => true, |                 'read_only' => true, | ||||||
|             ]; |             ]; | ||||||
| @ -119,6 +120,7 @@ class StartKeydb | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|  | 
 | ||||||
|         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -127,12 +129,13 @@ class StartKeydb | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -149,6 +152,7 @@ class StartKeydb | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -165,6 +169,7 @@ class StartKeydb | |||||||
| 
 | 
 | ||||||
|         return $environment_variables->all(); |         return $environment_variables->all(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_custom_keydb() |     private function add_custom_keydb() | ||||||
|     { |     { | ||||||
|         if (is_null($this->database->keydb_conf) || empty($this->database->keydb_conf)) { |         if (is_null($this->database->keydb_conf) || empty($this->database->keydb_conf)) { | ||||||
|  | |||||||
| @ -4,15 +4,17 @@ namespace App\Actions\Database; | |||||||
| 
 | 
 | ||||||
| use App\Models\StandaloneMariadb; | use App\Models\StandaloneMariadb; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartMariadb | class StartMariadb | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandaloneMariadb $database; |     public StandaloneMariadb $database; | ||||||
|  | 
 | ||||||
|     public array $commands = []; |     public array $commands = []; | ||||||
|  | 
 | ||||||
|     public string $configuration_dir; |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandaloneMariadb $database) |     public function handle(StandaloneMariadb $database) | ||||||
| @ -20,7 +22,7 @@ class StartMariadb | |||||||
|         $this->database = $database; |         $this->database = $database; | ||||||
| 
 | 
 | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
| @ -46,11 +48,11 @@ class StartMariadb | |||||||
|                         'coolify.managed' => 'true', |                         'coolify.managed' => 'true', | ||||||
|                     ], |                     ], | ||||||
|                     'healthcheck' => [ |                     'healthcheck' => [ | ||||||
|                         'test' => ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"], |                         'test' => ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized'], | ||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -58,27 +60,27 @@ class StartMariadb | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -95,10 +97,10 @@ class StartMariadb | |||||||
|         if (count($volume_names) > 0) { |         if (count($volume_names) > 0) { | ||||||
|             $docker_compose['volumes'] = $volume_names; |             $docker_compose['volumes'] = $volume_names; | ||||||
|         } |         } | ||||||
|         if (!is_null($this->database->mariadb_conf) || !empty($this->database->mariadb_conf)) { |         if (! is_null($this->database->mariadb_conf) || ! empty($this->database->mariadb_conf)) { | ||||||
|             $docker_compose['services'][$container_name]['volumes'][] = [ |             $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|                 'type' => 'bind', |                 'type' => 'bind', | ||||||
|                 'source' => $this->configuration_dir . '/custom-config.cnf', |                 'source' => $this->configuration_dir.'/custom-config.cnf', | ||||||
|                 'target' => '/etc/mysql/conf.d/custom-config.cnf', |                 'target' => '/etc/mysql/conf.d/custom-config.cnf', | ||||||
|                 'read_only' => true, |                 'read_only' => true, | ||||||
|             ]; |             ]; | ||||||
| @ -112,6 +114,7 @@ class StartMariadb | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|  | 
 | ||||||
|         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -120,12 +123,13 @@ class StartMariadb | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -142,6 +146,7 @@ class StartMariadb | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -166,8 +171,10 @@ class StartMariadb | |||||||
|         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MARIADB_PASSWORD'))->isEmpty()) { |         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MARIADB_PASSWORD'))->isEmpty()) { | ||||||
|             $environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}"); |             $environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}"); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $environment_variables->all(); |         return $environment_variables->all(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_custom_mysql() |     private function add_custom_mysql() | ||||||
|     { |     { | ||||||
|         if (is_null($this->database->mariadb_conf) || empty($this->database->mariadb_conf)) { |         if (is_null($this->database->mariadb_conf) || empty($this->database->mariadb_conf)) { | ||||||
|  | |||||||
| @ -4,25 +4,27 @@ namespace App\Actions\Database; | |||||||
| 
 | 
 | ||||||
| use App\Models\StandaloneMongodb; | use App\Models\StandaloneMongodb; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartMongodb | class StartMongodb | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandaloneMongodb $database; |     public StandaloneMongodb $database; | ||||||
|  | 
 | ||||||
|     public array $commands = []; |     public array $commands = []; | ||||||
|  | 
 | ||||||
|     public string $configuration_dir; |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandaloneMongodb $database) |     public function handle(StandaloneMongodb $database) | ||||||
|     { |     { | ||||||
|         $this->database = $database; |         $this->database = $database; | ||||||
| 
 | 
 | ||||||
|         $startCommand = "mongod"; |         $startCommand = 'mongod'; | ||||||
| 
 | 
 | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
| @ -51,14 +53,14 @@ class StartMongodb | |||||||
|                     ], |                     ], | ||||||
|                     'healthcheck' => [ |                     'healthcheck' => [ | ||||||
|                         'test' => [ |                         'test' => [ | ||||||
|                             "CMD", |                             'CMD', | ||||||
|                             "echo", |                             'echo', | ||||||
|                             "ok" |                             'ok', | ||||||
|                         ], |                         ], | ||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -66,27 +68,27 @@ class StartMongodb | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -103,19 +105,19 @@ class StartMongodb | |||||||
|         if (count($volume_names) > 0) { |         if (count($volume_names) > 0) { | ||||||
|             $docker_compose['volumes'] = $volume_names; |             $docker_compose['volumes'] = $volume_names; | ||||||
|         } |         } | ||||||
|         if (!is_null($this->database->mongo_conf) || !empty($this->database->mongo_conf)) { |         if (! is_null($this->database->mongo_conf) || ! empty($this->database->mongo_conf)) { | ||||||
|             $docker_compose['services'][$container_name]['volumes'][] = [ |             $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|                 'type' => 'bind', |                 'type' => 'bind', | ||||||
|                 'source' => $this->configuration_dir . '/mongod.conf', |                 'source' => $this->configuration_dir.'/mongod.conf', | ||||||
|                 'target' => '/etc/mongo/mongod.conf', |                 'target' => '/etc/mongo/mongod.conf', | ||||||
|                 'read_only' => true, |                 'read_only' => true, | ||||||
|             ]; |             ]; | ||||||
|             $docker_compose['services'][$container_name]['command'] =  $startCommand . ' --config /etc/mongo/mongod.conf'; |             $docker_compose['services'][$container_name]['command'] = $startCommand.' --config /etc/mongo/mongod.conf'; | ||||||
|         } |         } | ||||||
|         $this->add_default_database(); |         $this->add_default_database(); | ||||||
|         $docker_compose['services'][$container_name]['volumes'][] = [ |         $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|             'type' => 'bind', |             'type' => 'bind', | ||||||
|             'source' => $this->configuration_dir . '/docker-entrypoint-initdb.d', |             'source' => $this->configuration_dir.'/docker-entrypoint-initdb.d', | ||||||
|             'target' => '/docker-entrypoint-initdb.d', |             'target' => '/docker-entrypoint-initdb.d', | ||||||
|             'read_only' => true, |             'read_only' => true, | ||||||
|         ]; |         ]; | ||||||
| @ -129,6 +131,7 @@ class StartMongodb | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|  | 
 | ||||||
|         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -137,12 +140,13 @@ class StartMongodb | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -159,6 +163,7 @@ class StartMongodb | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -180,8 +185,10 @@ class StartMongodb | |||||||
|         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) { |         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) { | ||||||
|             $environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}"); |             $environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}"); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $environment_variables->all(); |         return $environment_variables->all(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_custom_mongo_conf() |     private function add_custom_mongo_conf() | ||||||
|     { |     { | ||||||
|         if (is_null($this->database->mongo_conf) || empty($this->database->mongo_conf)) { |         if (is_null($this->database->mongo_conf) || empty($this->database->mongo_conf)) { | ||||||
| @ -192,6 +199,7 @@ class StartMongodb | |||||||
|         $content_base64 = base64_encode($content); |         $content_base64 = base64_encode($content); | ||||||
|         $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $this->configuration_dir/{$filename} > /dev/null"; |         $this->commands[] = "echo '{$content_base64}' | base64 -d | tee $this->configuration_dir/{$filename} > /dev/null"; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_default_database() |     private function add_default_database() | ||||||
|     { |     { | ||||||
|         $content = "db = db.getSiblingDB(\"{$this->database->mongo_initdb_database}\");db.createCollection('init_collection');db.createUser({user: \"{$this->database->mongo_initdb_root_username}\", pwd: \"{$this->database->mongo_initdb_root_password}\",roles: [{role:\"readWrite\",db:\"{$this->database->mongo_initdb_database}\"}]});"; |         $content = "db = db.getSiblingDB(\"{$this->database->mongo_initdb_database}\");db.createCollection('init_collection');db.createUser({user: \"{$this->database->mongo_initdb_root_username}\", pwd: \"{$this->database->mongo_initdb_root_password}\",roles: [{role:\"readWrite\",db:\"{$this->database->mongo_initdb_database}\"}]});"; | ||||||
|  | |||||||
| @ -4,15 +4,17 @@ namespace App\Actions\Database; | |||||||
| 
 | 
 | ||||||
| use App\Models\StandaloneMysql; | use App\Models\StandaloneMysql; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartMysql | class StartMysql | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandaloneMysql $database; |     public StandaloneMysql $database; | ||||||
|  | 
 | ||||||
|     public array $commands = []; |     public array $commands = []; | ||||||
|  | 
 | ||||||
|     public string $configuration_dir; |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandaloneMysql $database) |     public function handle(StandaloneMysql $database) | ||||||
| @ -20,7 +22,7 @@ class StartMysql | |||||||
|         $this->database = $database; |         $this->database = $database; | ||||||
| 
 | 
 | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
| @ -46,11 +48,11 @@ class StartMysql | |||||||
|                         'coolify.managed' => 'true', |                         'coolify.managed' => 'true', | ||||||
|                     ], |                     ], | ||||||
|                     'healthcheck' => [ |                     'healthcheck' => [ | ||||||
|                         'test' => ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p{$this->database->mysql_root_password}"], |                         'test' => ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', "-p{$this->database->mysql_root_password}"], | ||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -58,27 +60,27 @@ class StartMysql | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -95,10 +97,10 @@ class StartMysql | |||||||
|         if (count($volume_names) > 0) { |         if (count($volume_names) > 0) { | ||||||
|             $docker_compose['volumes'] = $volume_names; |             $docker_compose['volumes'] = $volume_names; | ||||||
|         } |         } | ||||||
|         if (!is_null($this->database->mysql_conf) || !empty($this->database->mysql_conf)) { |         if (! is_null($this->database->mysql_conf) || ! empty($this->database->mysql_conf)) { | ||||||
|             $docker_compose['services'][$container_name]['volumes'][] = [ |             $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|                 'type' => 'bind', |                 'type' => 'bind', | ||||||
|                 'source' => $this->configuration_dir . '/custom-config.cnf', |                 'source' => $this->configuration_dir.'/custom-config.cnf', | ||||||
|                 'target' => '/etc/mysql/conf.d/custom-config.cnf', |                 'target' => '/etc/mysql/conf.d/custom-config.cnf', | ||||||
|                 'read_only' => true, |                 'read_only' => true, | ||||||
|             ]; |             ]; | ||||||
| @ -112,7 +114,8 @@ class StartMysql | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|         return remote_process($this->commands, $database->destination->server,callEventOnFinish: 'DatabaseStatusChanged'); | 
 | ||||||
|  |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private function generate_local_persistent_volumes() |     private function generate_local_persistent_volumes() | ||||||
| @ -120,12 +123,13 @@ class StartMysql | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -142,6 +146,7 @@ class StartMysql | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -166,8 +171,10 @@ class StartMysql | |||||||
|         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MYSQL_PASSWORD'))->isEmpty()) { |         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('MYSQL_PASSWORD'))->isEmpty()) { | ||||||
|             $environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}"); |             $environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}"); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $environment_variables->all(); |         return $environment_variables->all(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_custom_mysql() |     private function add_custom_mysql() | ||||||
|     { |     { | ||||||
|         if (is_null($this->database->mysql_conf) || empty($this->database->mysql_conf)) { |         if (is_null($this->database->mysql_conf) || empty($this->database->mysql_conf)) { | ||||||
|  | |||||||
| @ -4,28 +4,31 @@ namespace App\Actions\Database; | |||||||
| 
 | 
 | ||||||
| use App\Models\StandalonePostgresql; | use App\Models\StandalonePostgresql; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartPostgresql | class StartPostgresql | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandalonePostgresql $database; |     public StandalonePostgresql $database; | ||||||
|  | 
 | ||||||
|     public array $commands = []; |     public array $commands = []; | ||||||
|  | 
 | ||||||
|     public array $init_scripts = []; |     public array $init_scripts = []; | ||||||
|  | 
 | ||||||
|     public string $configuration_dir; |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandalonePostgresql $database) |     public function handle(StandalonePostgresql $database) | ||||||
|     { |     { | ||||||
|         $this->database = $database; |         $this->database = $database; | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
|             "mkdir -p $this->configuration_dir", |             "mkdir -p $this->configuration_dir", | ||||||
|             "mkdir -p $this->configuration_dir/docker-entrypoint-initdb.d/" |             "mkdir -p $this->configuration_dir/docker-entrypoint-initdb.d/", | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         $persistent_storages = $this->generate_local_persistent_volumes(); |         $persistent_storages = $this->generate_local_persistent_volumes(); | ||||||
| @ -50,13 +53,13 @@ class StartPostgresql | |||||||
|                     ], |                     ], | ||||||
|                     'healthcheck' => [ |                     'healthcheck' => [ | ||||||
|                         'test' => [ |                         'test' => [ | ||||||
|                             "CMD-SHELL", |                             'CMD-SHELL', | ||||||
|                             "psql -U {$this->database->postgres_user} -d {$this->database->postgres_db} -c 'SELECT 1' || exit 1" |                             "psql -U {$this->database->postgres_user} -d {$this->database->postgres_db} -c 'SELECT 1' || exit 1", | ||||||
|                         ], |                         ], | ||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -64,27 +67,27 @@ class StartPostgresql | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -106,15 +109,15 @@ class StartPostgresql | |||||||
|                 $docker_compose['services'][$container_name]['volumes'][] = [ |                 $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|                     'type' => 'bind', |                     'type' => 'bind', | ||||||
|                     'source' => $init_script, |                     'source' => $init_script, | ||||||
|                     'target' => '/docker-entrypoint-initdb.d/' . basename($init_script), |                     'target' => '/docker-entrypoint-initdb.d/'.basename($init_script), | ||||||
|                     'read_only' => true, |                     'read_only' => true, | ||||||
|                 ]; |                 ]; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (!is_null($this->database->postgres_conf) && !empty($this->database->postgres_conf)) { |         if (! is_null($this->database->postgres_conf) && ! empty($this->database->postgres_conf)) { | ||||||
|             $docker_compose['services'][$container_name]['volumes'][] = [ |             $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|                 'type' => 'bind', |                 'type' => 'bind', | ||||||
|                 'source' => $this->configuration_dir . '/custom-postgres.conf', |                 'source' => $this->configuration_dir.'/custom-postgres.conf', | ||||||
|                 'target' => '/etc/postgresql/postgresql.conf', |                 'target' => '/etc/postgresql/postgresql.conf', | ||||||
|                 'read_only' => true, |                 'read_only' => true, | ||||||
|             ]; |             ]; | ||||||
| @ -133,6 +136,7 @@ class StartPostgresql | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|  | 
 | ||||||
|         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -141,12 +145,13 @@ class StartPostgresql | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -163,6 +168,7 @@ class StartPostgresql | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -187,6 +193,7 @@ class StartPostgresql | |||||||
|         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_DB'))->isEmpty()) { |         if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_DB'))->isEmpty()) { | ||||||
|             $environment_variables->push("POSTGRES_DB={$this->database->postgres_db}"); |             $environment_variables->push("POSTGRES_DB={$this->database->postgres_db}"); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $environment_variables->all(); |         return $environment_variables->all(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -203,6 +210,7 @@ class StartPostgresql | |||||||
|             $this->init_scripts[] = "$this->configuration_dir/docker-entrypoint-initdb.d/{$filename}"; |             $this->init_scripts[] = "$this->configuration_dir/docker-entrypoint-initdb.d/{$filename}"; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_custom_conf() |     private function add_custom_conf() | ||||||
|     { |     { | ||||||
|         if (is_null($this->database->postgres_conf) || empty($this->database->postgres_conf)) { |         if (is_null($this->database->postgres_conf) || empty($this->database->postgres_conf)) { | ||||||
| @ -210,7 +218,7 @@ class StartPostgresql | |||||||
|         } |         } | ||||||
|         $filename = 'custom-postgres.conf'; |         $filename = 'custom-postgres.conf'; | ||||||
|         $content = $this->database->postgres_conf; |         $content = $this->database->postgres_conf; | ||||||
|         if (!str($content)->contains('listen_addresses')) { |         if (! str($content)->contains('listen_addresses')) { | ||||||
|             $content .= "\nlisten_addresses = '*'"; |             $content .= "\nlisten_addresses = '*'"; | ||||||
|             $this->database->postgres_conf = $content; |             $this->database->postgres_conf = $content; | ||||||
|             $this->database->save(); |             $this->database->save(); | ||||||
|  | |||||||
| @ -5,17 +5,18 @@ namespace App\Actions\Database; | |||||||
| use App\Models\StandaloneRedis; | use App\Models\StandaloneRedis; | ||||||
| use Illuminate\Support\Facades\Storage; | use Illuminate\Support\Facades\Storage; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Symfony\Component\Yaml\Yaml; |  | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
|  | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartRedis | class StartRedis | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
| 
 | 
 | ||||||
|     public StandaloneRedis $database; |     public StandaloneRedis $database; | ||||||
|     public array $commands = []; |  | ||||||
|     public string $configuration_dir; |  | ||||||
| 
 | 
 | ||||||
|  |     public array $commands = []; | ||||||
|  | 
 | ||||||
|  |     public string $configuration_dir; | ||||||
| 
 | 
 | ||||||
|     public function handle(StandaloneRedis $database) |     public function handle(StandaloneRedis $database) | ||||||
|     { |     { | ||||||
| @ -24,7 +25,7 @@ class StartRedis | |||||||
|         $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; |         $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; | ||||||
| 
 | 
 | ||||||
|         $container_name = $this->database->uuid; |         $container_name = $this->database->uuid; | ||||||
|         $this->configuration_dir = database_configuration_dir() . '/' . $container_name; |         $this->configuration_dir = database_configuration_dir().'/'.$container_name; | ||||||
| 
 | 
 | ||||||
|         $this->commands = [ |         $this->commands = [ | ||||||
|             "echo 'Starting {$database->name}.'", |             "echo 'Starting {$database->name}.'", | ||||||
| @ -55,12 +56,12 @@ class StartRedis | |||||||
|                         'test' => [ |                         'test' => [ | ||||||
|                             'CMD-SHELL', |                             'CMD-SHELL', | ||||||
|                             'redis-cli', |                             'redis-cli', | ||||||
|                             'ping' |                             'ping', | ||||||
|                         ], |                         ], | ||||||
|                         'interval' => '5s', |                         'interval' => '5s', | ||||||
|                         'timeout' => '5s', |                         'timeout' => '5s', | ||||||
|                         'retries' => 10, |                         'retries' => 10, | ||||||
|                         'start_period' => '5s' |                         'start_period' => '5s', | ||||||
|                     ], |                     ], | ||||||
|                     'mem_limit' => $this->database->limits_memory, |                     'mem_limit' => $this->database->limits_memory, | ||||||
|                     'memswap_limit' => $this->database->limits_memory_swap, |                     'memswap_limit' => $this->database->limits_memory_swap, | ||||||
| @ -68,27 +69,27 @@ class StartRedis | |||||||
|                     'mem_reservation' => $this->database->limits_memory_reservation, |                     'mem_reservation' => $this->database->limits_memory_reservation, | ||||||
|                     'cpus' => (float) $this->database->limits_cpus, |                     'cpus' => (float) $this->database->limits_cpus, | ||||||
|                     'cpu_shares' => $this->database->limits_cpu_shares, |                     'cpu_shares' => $this->database->limits_cpu_shares, | ||||||
|                 ] |                 ], | ||||||
|             ], |             ], | ||||||
|             'networks' => [ |             'networks' => [ | ||||||
|                 $this->database->destination->network => [ |                 $this->database->destination->network => [ | ||||||
|                     'external' => true, |                     'external' => true, | ||||||
|                     'name' => $this->database->destination->network, |                     'name' => $this->database->destination->network, | ||||||
|                     'attachable' => true, |                     'attachable' => true, | ||||||
|                 ] |                 ], | ||||||
|             ] |             ], | ||||||
|         ]; |         ]; | ||||||
|         if (!is_null($this->database->limits_cpuset)) { |         if (! is_null($this->database->limits_cpuset)) { | ||||||
|             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); |             data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); | ||||||
|         } |         } | ||||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { |         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||||
|             $docker_compose['services'][$container_name]['logging'] = [ |             $docker_compose['services'][$container_name]['logging'] = [ | ||||||
|                 'driver' => 'fluentd', |                 'driver' => 'fluentd', | ||||||
|                 'options' => [ |                 'options' => [ | ||||||
|                     'fluentd-address' => "tcp://127.0.0.1:24224", |                     'fluentd-address' => 'tcp://127.0.0.1:24224', | ||||||
|                     'fluentd-async' => "true", |                     'fluentd-async' => 'true', | ||||||
|                     'fluentd-sub-second-precision' => "true", |                     'fluentd-sub-second-precision' => 'true', | ||||||
|                 ] |                 ], | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|         if (count($this->database->ports_mappings_array) > 0) { |         if (count($this->database->ports_mappings_array) > 0) { | ||||||
| @ -105,10 +106,10 @@ class StartRedis | |||||||
|         if (count($volume_names) > 0) { |         if (count($volume_names) > 0) { | ||||||
|             $docker_compose['volumes'] = $volume_names; |             $docker_compose['volumes'] = $volume_names; | ||||||
|         } |         } | ||||||
|         if (!is_null($this->database->redis_conf) || !empty($this->database->redis_conf)) { |         if (! is_null($this->database->redis_conf) || ! empty($this->database->redis_conf)) { | ||||||
|             $docker_compose['services'][$container_name]['volumes'][] = [ |             $docker_compose['services'][$container_name]['volumes'][] = [ | ||||||
|                 'type' => 'bind', |                 'type' => 'bind', | ||||||
|                 'source' => $this->configuration_dir . '/redis.conf', |                 'source' => $this->configuration_dir.'/redis.conf', | ||||||
|                 'target' => '/usr/local/etc/redis/redis.conf', |                 'target' => '/usr/local/etc/redis/redis.conf', | ||||||
|                 'read_only' => true, |                 'read_only' => true, | ||||||
|             ]; |             ]; | ||||||
| @ -123,6 +124,7 @@ class StartRedis | |||||||
|         $this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull"; |         $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[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d"; | ||||||
|         $this->commands[] = "echo 'Database started.'"; |         $this->commands[] = "echo 'Database started.'"; | ||||||
|  | 
 | ||||||
|         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); |         return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -131,12 +133,13 @@ class StartRedis | |||||||
|         $local_persistent_volumes = []; |         $local_persistent_volumes = []; | ||||||
|         foreach ($this->database->persistentStorages as $persistentStorage) { |         foreach ($this->database->persistentStorages as $persistentStorage) { | ||||||
|             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { |             if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { | ||||||
|                 $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; | ||||||
|             } else { |             } else { | ||||||
|                 $volume_name = $persistentStorage->name; |                 $volume_name = $persistentStorage->name; | ||||||
|                 $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; |                 $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes; |         return $local_persistent_volumes; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -153,6 +156,7 @@ class StartRedis | |||||||
|                 'external' => false, |                 'external' => false, | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $local_persistent_volumes_names; |         return $local_persistent_volumes_names; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -169,6 +173,7 @@ class StartRedis | |||||||
| 
 | 
 | ||||||
|         return $environment_variables->all(); |         return $environment_variables->all(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_custom_redis() |     private function add_custom_redis() | ||||||
|     { |     { | ||||||
|         if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) { |         if (is_null($this->database->redis_conf) || empty($this->database->redis_conf)) { | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ class StopDatabase | |||||||
|     public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database) |     public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database) | ||||||
|     { |     { | ||||||
|         $server = $database->destination->server; |         $server = $database->destination->server; | ||||||
|         if (!$server->isFunctional()) { |         if (! $server->isFunctional()) { | ||||||
|             return 'Server is not functional'; |             return 'Server is not functional'; | ||||||
|         } |         } | ||||||
|         instant_remote_process( |         instant_remote_process( | ||||||
|  | |||||||
| @ -17,7 +17,9 @@ use Lorisleiva\Actions\Concerns\AsAction; | |||||||
| class GetContainersStatus | class GetContainersStatus | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public $applications; |     public $applications; | ||||||
|  | 
 | ||||||
|     public $server; |     public $server; | ||||||
| 
 | 
 | ||||||
|     public function handle(Server $server) |     public function handle(Server $server) | ||||||
| @ -26,9 +28,9 @@ class GetContainersStatus | |||||||
|         //     $server = Server::find(0);
 |         //     $server = Server::find(0);
 | ||||||
|         // }
 |         // }
 | ||||||
|         $this->server = $server; |         $this->server = $server; | ||||||
|         if (!$this->server->isFunctional()) { |         if (! $this->server->isFunctional()) { | ||||||
|             return 'Server is not ready.'; |             return 'Server is not ready.'; | ||||||
|         }; |         } | ||||||
|         $this->applications = $this->server->applications(); |         $this->applications = $this->server->applications(); | ||||||
|         $skip_these_applications = collect([]); |         $skip_these_applications = collect([]); | ||||||
|         foreach ($this->applications as $application) { |         foreach ($this->applications as $application) { | ||||||
| @ -41,7 +43,7 @@ class GetContainersStatus | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         $this->applications = $this->applications->filter(function ($value, $key) use ($skip_these_applications) { |         $this->applications = $this->applications->filter(function ($value, $key) use ($skip_these_applications) { | ||||||
|             return !$skip_these_applications->pluck('id')->contains($value->id); |             return ! $skip_these_applications->pluck('id')->contains($value->id); | ||||||
|         }); |         }); | ||||||
|         $this->old_way(); |         $this->old_way(); | ||||||
|         // if ($this->server->isSwarm()) {
 |         // if ($this->server->isSwarm()) {
 | ||||||
| @ -133,7 +135,7 @@ class GetContainersStatus | |||||||
|                                                 return data_get($value, 'name') === "$uuid-proxy"; |                                                 return data_get($value, 'name') === "$uuid-proxy"; | ||||||
|                                             } |                                             } | ||||||
|                                         })->first(); |                                         })->first(); | ||||||
|                                         if (!$foundTcpProxy) { |                                         if (! $foundTcpProxy) { | ||||||
|                                             StartDatabaseProxy::run($service_db); |                                             StartDatabaseProxy::run($service_db); | ||||||
|                                             // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
 |                                             // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
 | ||||||
|                                         } |                                         } | ||||||
| @ -158,7 +160,7 @@ class GetContainersStatus | |||||||
|                                             return data_get($value, 'name') === "$uuid-proxy"; |                                             return data_get($value, 'name') === "$uuid-proxy"; | ||||||
|                                         } |                                         } | ||||||
|                                     })->first(); |                                     })->first(); | ||||||
|                                     if (!$foundTcpProxy) { |                                     if (! $foundTcpProxy) { | ||||||
|                                         StartDatabaseProxy::run($database); |                                         StartDatabaseProxy::run($database); | ||||||
|                                         $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); |                                         $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); | ||||||
|                                     } |                                     } | ||||||
| @ -177,13 +179,13 @@ class GetContainersStatus | |||||||
|                     $subType = data_get($labels, 'coolify.service.subType'); |                     $subType = data_get($labels, 'coolify.service.subType'); | ||||||
|                     $subId = data_get($labels, 'coolify.service.subId'); |                     $subId = data_get($labels, 'coolify.service.subId'); | ||||||
|                     $service = $services->where('id', $serviceLabelId)->first(); |                     $service = $services->where('id', $serviceLabelId)->first(); | ||||||
|                     if (!$service) { |                     if (! $service) { | ||||||
|                         continue; |                         continue; | ||||||
|                     } |                     } | ||||||
|                     if ($subType === 'application') { |                     if ($subType === 'application') { | ||||||
|                         $service =  $service->applications()->where('id', $subId)->first(); |                         $service = $service->applications()->where('id', $subId)->first(); | ||||||
|                     } else { |                     } else { | ||||||
|                         $service =  $service->databases()->where('id', $subId)->first(); |                         $service = $service->databases()->where('id', $subId)->first(); | ||||||
|                     } |                     } | ||||||
|                     if ($service) { |                     if ($service) { | ||||||
|                         $foundServices[] = "$service->id-$service->name"; |                         $foundServices[] = "$service->id-$service->name"; | ||||||
| @ -239,7 +241,7 @@ class GetContainersStatus | |||||||
|                 $environmentName = data_get($service, 'environment.name'); |                 $environmentName = data_get($service, 'environment.name'); | ||||||
| 
 | 
 | ||||||
|                 if ($projectUuid && $serviceUuid && $environmentName) { |                 if ($projectUuid && $serviceUuid && $environmentName) { | ||||||
|                     $url =  base_url() . '/project/' . $projectUuid . "/" . $environmentName . "/service/" . $serviceUuid; |                     $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid; | ||||||
|                 } else { |                 } else { | ||||||
|                     $url = null; |                     $url = null; | ||||||
|                 } |                 } | ||||||
| @ -265,7 +267,7 @@ class GetContainersStatus | |||||||
|                 $environment = data_get($application, 'environment.name'); |                 $environment = data_get($application, 'environment.name'); | ||||||
| 
 | 
 | ||||||
|                 if ($projectUuid && $applicationUuid && $environment) { |                 if ($projectUuid && $applicationUuid && $environment) { | ||||||
|                     $url =  base_url() . '/project/' . $projectUuid . "/" . $environment . "/application/" . $applicationUuid; |                     $url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid; | ||||||
|                 } else { |                 } else { | ||||||
|                     $url = null; |                     $url = null; | ||||||
|                 } |                 } | ||||||
| @ -290,7 +292,7 @@ class GetContainersStatus | |||||||
|                 $applicationUuid = data_get($preview, 'application.uuid'); |                 $applicationUuid = data_get($preview, 'application.uuid'); | ||||||
| 
 | 
 | ||||||
|                 if ($projectUuid && $applicationUuid && $environmentName) { |                 if ($projectUuid && $applicationUuid && $environmentName) { | ||||||
|                     $url =  base_url() . '/project/' . $projectUuid . "/" . $environmentName . "/application/" . $applicationUuid; |                     $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid; | ||||||
|                 } else { |                 } else { | ||||||
|                     $url = null; |                     $url = null; | ||||||
|                 } |                 } | ||||||
| @ -315,7 +317,7 @@ class GetContainersStatus | |||||||
|                 $databaseUuid = data_get($database, 'uuid'); |                 $databaseUuid = data_get($database, 'uuid'); | ||||||
| 
 | 
 | ||||||
|                 if ($projectUuid && $databaseUuid && $environmentName) { |                 if ($projectUuid && $databaseUuid && $environmentName) { | ||||||
|                     $url = base_url() . '/project/' . $projectUuid . "/" . $environmentName . "/database/" . $databaseUuid; |                     $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid; | ||||||
|                 } else { |                 } else { | ||||||
|                     $url = null; |                     $url = null; | ||||||
|                 } |                 } | ||||||
| @ -332,7 +334,7 @@ class GetContainersStatus | |||||||
|                     return data_get($value, 'name') === 'coolify-proxy'; |                     return data_get($value, 'name') === 'coolify-proxy'; | ||||||
|                 } |                 } | ||||||
|             })->first(); |             })->first(); | ||||||
|             if (!$foundProxyContainer) { |             if (! $foundProxyContainer) { | ||||||
|                 try { |                 try { | ||||||
|                     $shouldStart = CheckProxy::run($this->server); |                     $shouldStart = CheckProxy::run($this->server); | ||||||
|                     if ($shouldStart) { |                     if ($shouldStart) { | ||||||
| @ -351,9 +353,11 @@ class GetContainersStatus | |||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             // send_internal_notification("ContainerStatusJob failed on ({$this->server->id}) with: " . $e->getMessage());
 |             // send_internal_notification("ContainerStatusJob failed on ({$this->server->id}) with: " . $e->getMessage());
 | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function old_way() |     private function old_way() | ||||||
|     { |     { | ||||||
|         if ($this->server->isSwarm()) { |         if ($this->server->isSwarm()) { | ||||||
| @ -361,8 +365,8 @@ class GetContainersStatus | |||||||
|             $containerReplicates = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false); |             $containerReplicates = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false); | ||||||
|         } else { |         } else { | ||||||
|             // Precheck for containers
 |             // Precheck for containers
 | ||||||
|             $containers = instant_remote_process(["docker container ls -q"], $this->server, false); |             $containers = instant_remote_process(['docker container ls -q'], $this->server, false); | ||||||
|             if (!$containers) { |             if (! $containers) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server, false); |             $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server, false); | ||||||
| @ -390,6 +394,7 @@ class GetContainersStatus | |||||||
|                             data_set($container, 'State.Health.Status', 'unhealthy'); |                             data_set($container, 'State.Health.Status', 'unhealthy'); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  | 
 | ||||||
|                     return $container; |                     return $container; | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| @ -463,7 +468,7 @@ class GetContainersStatus | |||||||
|                                                 return data_get($value, 'Name') === "/$uuid-proxy"; |                                                 return data_get($value, 'Name') === "/$uuid-proxy"; | ||||||
|                                             } |                                             } | ||||||
|                                         })->first(); |                                         })->first(); | ||||||
|                                         if (!$foundTcpProxy) { |                                         if (! $foundTcpProxy) { | ||||||
|                                             StartDatabaseProxy::run($service_db); |                                             StartDatabaseProxy::run($service_db); | ||||||
|                                             // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
 |                                             // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$service_db->service->name}", $this->server));
 | ||||||
|                                         } |                                         } | ||||||
| @ -488,7 +493,7 @@ class GetContainersStatus | |||||||
|                                         return data_get($value, 'Name') === "/$uuid-proxy"; |                                         return data_get($value, 'Name') === "/$uuid-proxy"; | ||||||
|                                     } |                                     } | ||||||
|                                 })->first(); |                                 })->first(); | ||||||
|                                 if (!$foundTcpProxy) { |                                 if (! $foundTcpProxy) { | ||||||
|                                     StartDatabaseProxy::run($database); |                                     StartDatabaseProxy::run($database); | ||||||
|                                     $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); |                                     $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); | ||||||
|                                 } |                                 } | ||||||
| @ -507,13 +512,13 @@ class GetContainersStatus | |||||||
|                 $subType = data_get($labels, 'coolify.service.subType'); |                 $subType = data_get($labels, 'coolify.service.subType'); | ||||||
|                 $subId = data_get($labels, 'coolify.service.subId'); |                 $subId = data_get($labels, 'coolify.service.subId'); | ||||||
|                 $service = $services->where('id', $serviceLabelId)->first(); |                 $service = $services->where('id', $serviceLabelId)->first(); | ||||||
|                 if (!$service) { |                 if (! $service) { | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if ($subType === 'application') { |                 if ($subType === 'application') { | ||||||
|                     $service =  $service->applications()->where('id', $subId)->first(); |                     $service = $service->applications()->where('id', $subId)->first(); | ||||||
|                 } else { |                 } else { | ||||||
|                     $service =  $service->databases()->where('id', $subId)->first(); |                     $service = $service->databases()->where('id', $subId)->first(); | ||||||
|                 } |                 } | ||||||
|                 if ($service) { |                 if ($service) { | ||||||
|                     $foundServices[] = "$service->id-$service->name"; |                     $foundServices[] = "$service->id-$service->name"; | ||||||
| @ -569,7 +574,7 @@ class GetContainersStatus | |||||||
|             $environmentName = data_get($service, 'environment.name'); |             $environmentName = data_get($service, 'environment.name'); | ||||||
| 
 | 
 | ||||||
|             if ($projectUuid && $serviceUuid && $environmentName) { |             if ($projectUuid && $serviceUuid && $environmentName) { | ||||||
|                 $url =  base_url() . '/project/' . $projectUuid . "/" . $environmentName . "/service/" . $serviceUuid; |                 $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid; | ||||||
|             } else { |             } else { | ||||||
|                 $url = null; |                 $url = null; | ||||||
|             } |             } | ||||||
| @ -595,7 +600,7 @@ class GetContainersStatus | |||||||
|             $environment = data_get($application, 'environment.name'); |             $environment = data_get($application, 'environment.name'); | ||||||
| 
 | 
 | ||||||
|             if ($projectUuid && $applicationUuid && $environment) { |             if ($projectUuid && $applicationUuid && $environment) { | ||||||
|                 $url =  base_url() . '/project/' . $projectUuid . "/" . $environment . "/application/" . $applicationUuid; |                 $url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid; | ||||||
|             } else { |             } else { | ||||||
|                 $url = null; |                 $url = null; | ||||||
|             } |             } | ||||||
| @ -620,7 +625,7 @@ class GetContainersStatus | |||||||
|             $applicationUuid = data_get($preview, 'application.uuid'); |             $applicationUuid = data_get($preview, 'application.uuid'); | ||||||
| 
 | 
 | ||||||
|             if ($projectUuid && $applicationUuid && $environmentName) { |             if ($projectUuid && $applicationUuid && $environmentName) { | ||||||
|                 $url =  base_url() . '/project/' . $projectUuid . "/" . $environmentName . "/application/" . $applicationUuid; |                 $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid; | ||||||
|             } else { |             } else { | ||||||
|                 $url = null; |                 $url = null; | ||||||
|             } |             } | ||||||
| @ -645,7 +650,7 @@ class GetContainersStatus | |||||||
|             $databaseUuid = data_get($database, 'uuid'); |             $databaseUuid = data_get($database, 'uuid'); | ||||||
| 
 | 
 | ||||||
|             if ($projectUuid && $databaseUuid && $environmentName) { |             if ($projectUuid && $databaseUuid && $environmentName) { | ||||||
|                 $url = base_url() . '/project/' . $projectUuid . "/" . $environmentName . "/database/" . $databaseUuid; |                 $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid; | ||||||
|             } else { |             } else { | ||||||
|                 $url = null; |                 $url = null; | ||||||
|             } |             } | ||||||
| @ -661,7 +666,7 @@ class GetContainersStatus | |||||||
|                 return data_get($value, 'Name') === '/coolify-proxy'; |                 return data_get($value, 'Name') === '/coolify-proxy'; | ||||||
|             } |             } | ||||||
|         })->first(); |         })->first(); | ||||||
|         if (!$foundProxyContainer) { |         if (! $foundProxyContainer) { | ||||||
|             try { |             try { | ||||||
|                 $shouldStart = CheckProxy::run($this->server); |                 $shouldStart = CheckProxy::run($this->server); | ||||||
|                 if ($shouldStart) { |                 if ($shouldStart) { | ||||||
|  | |||||||
| @ -16,12 +16,12 @@ class CreateNewUser implements CreatesNewUsers | |||||||
|     /** |     /** | ||||||
|      * Validate and create a newly registered user. |      * Validate and create a newly registered user. | ||||||
|      * |      * | ||||||
|      * @param array<string, string> $input |      * @param  array<string, string>  $input | ||||||
|      */ |      */ | ||||||
|     public function create(array $input): User |     public function create(array $input): User | ||||||
|     { |     { | ||||||
|         $settings = InstanceSettings::get(); |         $settings = InstanceSettings::get(); | ||||||
|         if (!$settings->is_registration_enabled) { |         if (! $settings->is_registration_enabled) { | ||||||
|             abort(403); |             abort(403); | ||||||
|         } |         } | ||||||
|         Validator::make($input, [ |         Validator::make($input, [ | ||||||
| @ -66,6 +66,7 @@ class CreateNewUser implements CreatesNewUsers | |||||||
|         } |         } | ||||||
|         // Set session variable
 |         // Set session variable
 | ||||||
|         session(['currentTeam' => $user->currentTeam = $team]); |         session(['currentTeam' => $user->currentTeam = $team]); | ||||||
|  | 
 | ||||||
|         return $user; |         return $user; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ class ResetUserPassword implements ResetsUserPasswords | |||||||
|     /** |     /** | ||||||
|      * Validate and reset the user's forgotten password. |      * Validate and reset the user's forgotten password. | ||||||
|      * |      * | ||||||
|      * @param array<string, string> $input |      * @param  array<string, string>  $input | ||||||
|      */ |      */ | ||||||
|     public function reset(User $user, array $input): void |     public function reset(User $user, array $input): void | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ class UpdateUserPassword implements UpdatesUserPasswords | |||||||
|     /** |     /** | ||||||
|      * Validate and update the user's password. |      * Validate and update the user's password. | ||||||
|      * |      * | ||||||
|      * @param array<string, string> $input |      * @param  array<string, string>  $input | ||||||
|      */ |      */ | ||||||
|     public function update(User $user, array $input): void |     public function update(User $user, array $input): void | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation | |||||||
|     /** |     /** | ||||||
|      * Validate and update the given user's profile information. |      * Validate and update the given user's profile information. | ||||||
|      * |      * | ||||||
|      * @param array<string, string> $input |      * @param  array<string, string>  $input | ||||||
|      */ |      */ | ||||||
|     public function update(User $user, array $input): void |     public function update(User $user, array $input): void | ||||||
|     { |     { | ||||||
| @ -45,7 +45,7 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation | |||||||
|     /** |     /** | ||||||
|      * Update the given verified user's profile information. |      * Update the given verified user's profile information. | ||||||
|      * |      * | ||||||
|      * @param array<string, string> $input |      * @param  array<string, string>  $input | ||||||
|      */ |      */ | ||||||
|     protected function updateVerifiedUser(User $user, array $input): void |     protected function updateVerifiedUser(User $user, array $input): void | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -6,10 +6,10 @@ use App\Models\InstanceSettings; | |||||||
| use Illuminate\Support\Facades\Http; | use Illuminate\Support\Facades\Http; | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class CheckResaleLicense | class CheckResaleLicense | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
| @ -18,6 +18,7 @@ class CheckResaleLicense | |||||||
|                 $settings->update([ |                 $settings->update([ | ||||||
|                     'is_resale_license_active' => true, |                     'is_resale_license_active' => true, | ||||||
|                 ]); |                 ]); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             // if (!$settings->resale_license) {
 |             // if (!$settings->resale_license) {
 | ||||||
| @ -38,6 +39,7 @@ class CheckResaleLicense | |||||||
|                 $settings->update([ |                 $settings->update([ | ||||||
|                     'is_resale_license_active' => true, |                     'is_resale_license_active' => true, | ||||||
|                 ]); |                 ]); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $data = Http::withHeaders([ |             $data = Http::withHeaders([ | ||||||
| @ -51,6 +53,7 @@ class CheckResaleLicense | |||||||
|                 $settings->update([ |                 $settings->update([ | ||||||
|                     'is_resale_license_active' => true, |                     'is_resale_license_active' => true, | ||||||
|                 ]); |                 ]); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             if (data_get($data, 'license_key.status') === 'active') { |             if (data_get($data, 'license_key.status') === 'active') { | ||||||
|  | |||||||
| @ -2,13 +2,14 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Proxy; | namespace App\Actions\Proxy; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class CheckConfiguration | class CheckConfiguration | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server, bool $reset = false) |     public function handle(Server $server, bool $reset = false) | ||||||
|     { |     { | ||||||
|         $proxyType = $server->proxyType(); |         $proxyType = $server->proxyType(); | ||||||
| @ -22,12 +23,13 @@ class CheckConfiguration | |||||||
|         ]; |         ]; | ||||||
|         $proxy_configuration = instant_remote_process($payload, $server, false); |         $proxy_configuration = instant_remote_process($payload, $server, false); | ||||||
| 
 | 
 | ||||||
|         if ($reset || !$proxy_configuration || is_null($proxy_configuration)) { |         if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) { | ||||||
|             $proxy_configuration = Str::of(generate_default_proxy_configuration($server))->trim()->value; |             $proxy_configuration = Str::of(generate_default_proxy_configuration($server))->trim()->value; | ||||||
|         } |         } | ||||||
|         if (!$proxy_configuration || is_null($proxy_configuration)) { |         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; |         return $proxy_configuration; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,9 +8,10 @@ use Lorisleiva\Actions\Concerns\AsAction; | |||||||
| class CheckProxy | class CheckProxy | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server, $fromUI = false) |     public function handle(Server $server, $fromUI = false) | ||||||
|     { |     { | ||||||
|         if (!$server->isFunctional()) { |         if (! $server->isFunctional()) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         if ($server->isBuildServer()) { |         if ($server->isBuildServer()) { | ||||||
| @ -18,6 +19,7 @@ class CheckProxy | |||||||
|                 $server->proxy = null; |                 $server->proxy = null; | ||||||
|                 $server->save(); |                 $server->save(); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         $proxyType = $server->proxyType(); |         $proxyType = $server->proxyType(); | ||||||
| @ -25,12 +27,12 @@ class CheckProxy | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         ['uptime' => $uptime, 'error' => $error] = $server->validateConnection(); |         ['uptime' => $uptime, 'error' => $error] = $server->validateConnection(); | ||||||
|         if (!$uptime) { |         if (! $uptime) { | ||||||
|             throw new \Exception($error); |             throw new \Exception($error); | ||||||
|         } |         } | ||||||
|         if (!$server->isProxyShouldRun()) { |         if (! $server->isProxyShouldRun()) { | ||||||
|             if ($fromUI) { |             if ($fromUI) { | ||||||
|                 throw new \Exception("Proxy should not run. You selected the Custom Proxy."); |                 throw new \Exception('Proxy should not run. You selected the Custom Proxy.'); | ||||||
|             } else { |             } else { | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
| @ -42,12 +44,14 @@ class CheckProxy | |||||||
|             if ($status === 'running') { |             if ($status === 'running') { | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return true; |             return true; | ||||||
|         } else { |         } else { | ||||||
|             $status = getContainerStatus($server, 'coolify-proxy'); |             $status = getContainerStatus($server, 'coolify-proxy'); | ||||||
|             if ($status === 'running') { |             if ($status === 'running') { | ||||||
|                 $server->proxy->set('status', 'running'); |                 $server->proxy->set('status', 'running'); | ||||||
|                 $server->save(); |                 $server->save(); | ||||||
|  | 
 | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|             if ($server->settings->is_cloudflare_tunnel) { |             if ($server->settings->is_cloudflare_tunnel) { | ||||||
| @ -76,6 +80,7 @@ class CheckProxy | |||||||
|                     return false; |                     return false; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ use Spatie\Activitylog\Models\Activity; | |||||||
| class StartProxy | class StartProxy | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server, bool $async = true): string|Activity |     public function handle(Server $server, bool $async = true): string|Activity | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
| @ -21,8 +22,8 @@ class StartProxy | |||||||
|             $commands = collect([]); |             $commands = collect([]); | ||||||
|             $proxy_path = $server->proxyPath(); |             $proxy_path = $server->proxyPath(); | ||||||
|             $configuration = CheckConfiguration::run($server); |             $configuration = CheckConfiguration::run($server); | ||||||
|             if (!$configuration) { |             if (! $configuration) { | ||||||
|                 throw new \Exception("Configuration is not synced"); |                 throw new \Exception('Configuration is not synced'); | ||||||
|             } |             } | ||||||
|             SaveConfiguration::run($server, $configuration); |             SaveConfiguration::run($server, $configuration); | ||||||
|             $docker_compose_yml_base64 = base64_encode($configuration); |             $docker_compose_yml_base64 = base64_encode($configuration); | ||||||
| @ -34,11 +35,11 @@ class StartProxy | |||||||
|                     "cd $proxy_path", |                     "cd $proxy_path", | ||||||
|                     "echo 'Creating required Docker Compose file.'", |                     "echo 'Creating required Docker Compose file.'", | ||||||
|                     "echo 'Starting coolify-proxy.'", |                     "echo 'Starting coolify-proxy.'", | ||||||
|                     "docker stack deploy -c docker-compose.yml coolify-proxy", |                     'docker stack deploy -c docker-compose.yml coolify-proxy', | ||||||
|                     "echo 'Proxy started successfully.'" |                     "echo 'Proxy started successfully.'", | ||||||
|                 ]); |                 ]); | ||||||
|             } else { |             } else { | ||||||
|                 $caddfile = "import /dynamic/*.caddy"; |                 $caddfile = 'import /dynamic/*.caddy'; | ||||||
|                 $commands = $commands->merge([ |                 $commands = $commands->merge([ | ||||||
|                     "mkdir -p $proxy_path/dynamic", |                     "mkdir -p $proxy_path/dynamic", | ||||||
|                     "cd $proxy_path", |                     "cd $proxy_path", | ||||||
| @ -47,16 +48,17 @@ class StartProxy | |||||||
|                     "echo 'Pulling docker image.'", |                     "echo 'Pulling docker image.'", | ||||||
|                     'docker compose pull', |                     'docker compose pull', | ||||||
|                     "echo 'Stopping existing coolify-proxy.'", |                     "echo 'Stopping existing coolify-proxy.'", | ||||||
|                     "docker compose down -v --remove-orphans > /dev/null 2>&1", |                     'docker compose down -v --remove-orphans > /dev/null 2>&1', | ||||||
|                     "echo 'Starting coolify-proxy.'", |                     "echo 'Starting coolify-proxy.'", | ||||||
|                     'docker compose up -d --remove-orphans', |                     'docker compose up -d --remove-orphans', | ||||||
|                     "echo 'Proxy started successfully.'" |                     "echo 'Proxy started successfully.'", | ||||||
|                 ]); |                 ]); | ||||||
|                 $commands = $commands->merge(connectProxyToNetworks($server)); |                 $commands = $commands->merge(connectProxyToNetworks($server)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if ($async) { |             if ($async) { | ||||||
|                 $activity = remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server); |                 $activity = remote_process($commands, $server, callEventOnFinish: 'ProxyStarted', callEventData: $server); | ||||||
|  | 
 | ||||||
|                 return $activity; |                 return $activity; | ||||||
|             } else { |             } else { | ||||||
|                 instant_remote_process($commands, $server); |                 instant_remote_process($commands, $server); | ||||||
| @ -64,6 +66,7 @@ class StartProxy | |||||||
|                 $server->proxy->set('type', $proxyType); |                 $server->proxy->set('type', $proxyType); | ||||||
|                 $server->save(); |                 $server->save(); | ||||||
|                 ProxyStarted::dispatch($server); |                 ProxyStarted::dispatch($server); | ||||||
|  | 
 | ||||||
|                 return 'OK'; |                 return 'OK'; | ||||||
|             } |             } | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|  | |||||||
| @ -2,12 +2,13 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Server; | namespace App\Actions\Server; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class CleanupDocker | class CleanupDocker | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server, bool $force = true) |     public function handle(Server $server, bool $force = true) | ||||||
|     { |     { | ||||||
|         if ($force) { |         if ($force) { | ||||||
|  | |||||||
| @ -9,18 +9,19 @@ use Symfony\Component\Yaml\Yaml; | |||||||
| class ConfigureCloudflared | class ConfigureCloudflared | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server, string $cloudflare_token) |     public function handle(Server $server, string $cloudflare_token) | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $config = [ |             $config = [ | ||||||
|                 "services" => [ |                 'services' => [ | ||||||
|                     "coolify-cloudflared" => [ |                     'coolify-cloudflared' => [ | ||||||
|                         "container_name" => "coolify-cloudflared", |                         'container_name' => 'coolify-cloudflared', | ||||||
|                         "image" => "cloudflare/cloudflared:latest", |                         'image' => 'cloudflare/cloudflared:latest', | ||||||
|                         "restart" => RESTART_MODE, |                         'restart' => RESTART_MODE, | ||||||
|                         "network_mode" => "host", |                         'network_mode' => 'host', | ||||||
|                         "command" => "tunnel run", |                         'command' => 'tunnel run', | ||||||
|                         "environment" => [ |                         'environment' => [ | ||||||
|                             "TUNNEL_TOKEN={$cloudflare_token}", |                             "TUNNEL_TOKEN={$cloudflare_token}", | ||||||
|                         ], |                         ], | ||||||
|                     ], |                     ], | ||||||
| @ -29,12 +30,12 @@ class ConfigureCloudflared | |||||||
|             $config = Yaml::dump($config, 12, 2); |             $config = Yaml::dump($config, 12, 2); | ||||||
|             $docker_compose_yml_base64 = base64_encode($config); |             $docker_compose_yml_base64 = base64_encode($config); | ||||||
|             $commands = collect([ |             $commands = collect([ | ||||||
|                 "mkdir -p /tmp/cloudflared", |                 'mkdir -p /tmp/cloudflared', | ||||||
|                 "cd /tmp/cloudflared", |                 'cd /tmp/cloudflared', | ||||||
|                 "echo '$docker_compose_yml_base64' | base64 -d | tee docker-compose.yml > /dev/null", |                 "echo '$docker_compose_yml_base64' | base64 -d | tee docker-compose.yml > /dev/null", | ||||||
|                 "docker compose pull", |                 'docker compose pull', | ||||||
|                 "docker compose down -v --remove-orphans > /dev/null 2>&1", |                 'docker compose down -v --remove-orphans > /dev/null 2>&1', | ||||||
|                 "docker compose up -d --remove-orphans", |                 'docker compose up -d --remove-orphans', | ||||||
|             ]); |             ]); | ||||||
|             instant_remote_process($commands, $server); |             instant_remote_process($commands, $server); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
| @ -42,7 +43,7 @@ class ConfigureCloudflared | |||||||
|             throw $e; |             throw $e; | ||||||
|         } finally { |         } finally { | ||||||
|             $commands = collect([ |             $commands = collect([ | ||||||
|                 "rm -fr /tmp/cloudflared", |                 'rm -fr /tmp/cloudflared', | ||||||
|             ]); |             ]); | ||||||
|             instant_remote_process($commands, $server); |             instant_remote_process($commands, $server); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -2,20 +2,21 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Server; | namespace App\Actions\Server; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use App\Models\StandaloneDocker; | use App\Models\StandaloneDocker; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class InstallDocker | class InstallDocker | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server) |     public function handle(Server $server) | ||||||
|     { |     { | ||||||
|         $supported_os_type = $server->validateOS(); |         $supported_os_type = $server->validateOS(); | ||||||
|         if (!$supported_os_type) { |         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>.'); | ||||||
|         } |         } | ||||||
|         ray('Installing Docker on server: ' . $server->name . ' (' . $server->ip . ')' . ' with OS type: ' . $supported_os_type); |         ray('Installing Docker on server: '.$server->name.' ('.$server->ip.')'.' with OS type: '.$supported_os_type); | ||||||
|         $dockerVersion = '24.0'; |         $dockerVersion = '24.0'; | ||||||
|         $config = base64_encode('{ |         $config = base64_encode('{ | ||||||
|             "log-driver": "json-file", |             "log-driver": "json-file", | ||||||
| @ -36,40 +37,41 @@ class InstallDocker | |||||||
|         if (isDev() && $server->id === 0) { |         if (isDev() && $server->id === 0) { | ||||||
|             $command = $command->merge([ |             $command = $command->merge([ | ||||||
|                 "echo 'Installing Prerequisites...'", |                 "echo 'Installing Prerequisites...'", | ||||||
|                 "sleep 1", |                 'sleep 1', | ||||||
|                 "echo 'Installing Docker Engine...'", |                 "echo 'Installing Docker Engine...'", | ||||||
|                 "echo 'Configuring Docker Engine (merging existing configuration with the required)...'", |                 "echo 'Configuring Docker Engine (merging existing configuration with the required)...'", | ||||||
|                 "sleep 4", |                 'sleep 4', | ||||||
|                 "echo 'Restarting Docker Engine...'", |                 "echo 'Restarting Docker Engine...'", | ||||||
|                 "ls -l /tmp" |                 'ls -l /tmp', | ||||||
|             ]); |             ]); | ||||||
|  | 
 | ||||||
|             return remote_process($command, $server); |             return remote_process($command, $server); | ||||||
|         } else { |         } else { | ||||||
|             if ($supported_os_type->contains('debian')) { |             if ($supported_os_type->contains('debian')) { | ||||||
|                 $command = $command->merge([ |                 $command = $command->merge([ | ||||||
|                     "echo 'Installing Prerequisites...'", |                     "echo 'Installing Prerequisites...'", | ||||||
|                     "apt-get update -y", |                     'apt-get update -y', | ||||||
|                     "command -v curl >/dev/null || apt install -y curl", |                     'command -v curl >/dev/null || apt install -y curl', | ||||||
|                     "command -v wget >/dev/null || apt install -y wget", |                     'command -v wget >/dev/null || apt install -y wget', | ||||||
|                     "command -v git >/dev/null || apt install -y git", |                     'command -v git >/dev/null || apt install -y git', | ||||||
|                     "command -v jq >/dev/null || apt install -y jq", |                     'command -v jq >/dev/null || apt install -y jq', | ||||||
|                 ]); |                 ]); | ||||||
|             } else if ($supported_os_type->contains('rhel')) { |             } elseif ($supported_os_type->contains('rhel')) { | ||||||
|                 $command = $command->merge([ |                 $command = $command->merge([ | ||||||
|                     "echo 'Installing Prerequisites...'", |                     "echo 'Installing Prerequisites...'", | ||||||
|                     "command -v curl >/dev/null || dnf install -y curl", |                     'command -v curl >/dev/null || dnf install -y curl', | ||||||
|                     "command -v wget >/dev/null || dnf install -y wget", |                     'command -v wget >/dev/null || dnf install -y wget', | ||||||
|                     "command -v git >/dev/null || dnf install -y git", |                     'command -v git >/dev/null || dnf install -y git', | ||||||
|                     "command -v jq >/dev/null || dnf install -y jq", |                     'command -v jq >/dev/null || dnf install -y jq', | ||||||
|                 ]); |                 ]); | ||||||
|             } else if ($supported_os_type->contains('sles')) { |             } elseif ($supported_os_type->contains('sles')) { | ||||||
|                 $command = $command->merge([ |                 $command = $command->merge([ | ||||||
|                     "echo 'Installing Prerequisites...'", |                     "echo 'Installing Prerequisites...'", | ||||||
|                     "zypper update -y", |                     'zypper update -y', | ||||||
|                     "command -v curl >/dev/null || zypper install -y curl", |                     'command -v curl >/dev/null || zypper install -y curl', | ||||||
|                     "command -v wget >/dev/null || zypper install -y wget", |                     'command -v wget >/dev/null || zypper install -y wget', | ||||||
|                     "command -v git >/dev/null || zypper install -y git", |                     'command -v git >/dev/null || zypper install -y git', | ||||||
|                     "command -v jq >/dev/null || zypper install -y jq", |                     'command -v jq >/dev/null || zypper install -y jq', | ||||||
|                 ]); |                 ]); | ||||||
|             } else { |             } else { | ||||||
|                 throw new \Exception('Unsupported OS'); |                 throw new \Exception('Unsupported OS'); | ||||||
| @ -78,29 +80,30 @@ class InstallDocker | |||||||
|                 "echo 'Installing Docker Engine...'", |                 "echo 'Installing Docker Engine...'", | ||||||
|                 "curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh || curl https://get.docker.com | sh -s -- --version {$dockerVersion}", |                 "curl https://releases.rancher.com/install-docker/{$dockerVersion}.sh | sh || curl https://get.docker.com | sh -s -- --version {$dockerVersion}", | ||||||
|                 "echo 'Configuring Docker Engine (merging existing configuration with the required)...'", |                 "echo 'Configuring Docker Engine (merging existing configuration with the required)...'", | ||||||
|                 "test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json \"/etc/docker/daemon.json.original-$(date +\"%Y%m%d-%H%M%S\")\"", |                 'test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json "/etc/docker/daemon.json.original-$(date +"%Y%m%d-%H%M%S")"', | ||||||
|                 "test ! -s /etc/docker/daemon.json && echo '{$config}' | base64 -d | tee /etc/docker/daemon.json > /dev/null", |                 "test ! -s /etc/docker/daemon.json && echo '{$config}' | base64 -d | tee /etc/docker/daemon.json > /dev/null", | ||||||
|                 "echo '{$config}' | base64 -d | tee /etc/docker/daemon.json.coolify > /dev/null", |                 "echo '{$config}' | base64 -d | tee /etc/docker/daemon.json.coolify > /dev/null", | ||||||
|                 "jq . /etc/docker/daemon.json.coolify | tee /etc/docker/daemon.json.coolify.pretty > /dev/null", |                 'jq . /etc/docker/daemon.json.coolify | tee /etc/docker/daemon.json.coolify.pretty > /dev/null', | ||||||
|                 "mv /etc/docker/daemon.json.coolify.pretty /etc/docker/daemon.json.coolify", |                 'mv /etc/docker/daemon.json.coolify.pretty /etc/docker/daemon.json.coolify', | ||||||
|                 "jq -s '.[0] * .[1]' /etc/docker/daemon.json.coolify /etc/docker/daemon.json | tee /etc/docker/daemon.json.appended > /dev/null", |                 "jq -s '.[0] * .[1]' /etc/docker/daemon.json.coolify /etc/docker/daemon.json | tee /etc/docker/daemon.json.appended > /dev/null", | ||||||
|                 "mv /etc/docker/daemon.json.appended /etc/docker/daemon.json", |                 'mv /etc/docker/daemon.json.appended /etc/docker/daemon.json', | ||||||
|                 "echo 'Restarting Docker Engine...'", |                 "echo 'Restarting Docker Engine...'", | ||||||
|                 "systemctl enable docker >/dev/null 2>&1 || true", |                 'systemctl enable docker >/dev/null 2>&1 || true', | ||||||
|                 "systemctl restart docker", |                 'systemctl restart docker', | ||||||
|             ]); |             ]); | ||||||
|             if ($server->isSwarm()) { |             if ($server->isSwarm()) { | ||||||
|                 $command = $command->merge([ |                 $command = $command->merge([ | ||||||
|                     "docker network create --attachable --driver overlay coolify-overlay >/dev/null 2>&1 || true", |                     'docker network create --attachable --driver overlay coolify-overlay >/dev/null 2>&1 || true', | ||||||
|                 ]); |                 ]); | ||||||
|             } else { |             } else { | ||||||
|                 $command = $command->merge([ |                 $command = $command->merge([ | ||||||
|                     "docker network create --attachable coolify >/dev/null 2>&1 || true", |                     'docker network create --attachable coolify >/dev/null 2>&1 || true', | ||||||
|                 ]); |                 ]); | ||||||
|                 $command = $command->merge([ |                 $command = $command->merge([ | ||||||
|                     "echo 'Done!'", |                     "echo 'Done!'", | ||||||
|                 ]); |                 ]); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return remote_process($command, $server); |             return remote_process($command, $server); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,21 +2,22 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Server; | namespace App\Actions\Server; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class InstallLogDrain | class InstallLogDrain | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server) |     public function handle(Server $server) | ||||||
|     { |     { | ||||||
|         if ($server->settings->is_logdrain_newrelic_enabled) { |         if ($server->settings->is_logdrain_newrelic_enabled) { | ||||||
|             $type = 'newrelic'; |             $type = 'newrelic'; | ||||||
|         } else if ($server->settings->is_logdrain_highlight_enabled) { |         } elseif ($server->settings->is_logdrain_highlight_enabled) { | ||||||
|             $type = 'highlight'; |             $type = 'highlight'; | ||||||
|         } else if ($server->settings->is_logdrain_axiom_enabled) { |         } elseif ($server->settings->is_logdrain_axiom_enabled) { | ||||||
|             $type = 'axiom'; |             $type = 'axiom'; | ||||||
|         } else if ($server->settings->is_logdrain_custom_enabled) { |         } elseif ($server->settings->is_logdrain_custom_enabled) { | ||||||
|             $type = 'custom'; |             $type = 'custom'; | ||||||
|         } else { |         } else { | ||||||
|             $type = 'none'; |             $type = 'none'; | ||||||
| @ -25,11 +26,12 @@ class InstallLogDrain | |||||||
|             if ($type === 'none') { |             if ($type === 'none') { | ||||||
|                 $command = [ |                 $command = [ | ||||||
|                     "echo 'Stopping old Fluent Bit'", |                     "echo 'Stopping old Fluent Bit'", | ||||||
|                     "docker rm -f coolify-log-drain || true", |                     'docker rm -f coolify-log-drain || true', | ||||||
|                 ]; |                 ]; | ||||||
|  | 
 | ||||||
|                 return instant_remote_process($command, $server); |                 return instant_remote_process($command, $server); | ||||||
|             } else if ($type === 'newrelic') { |             } elseif ($type === 'newrelic') { | ||||||
|                 if (!$server->settings->is_logdrain_newrelic_enabled) { |                 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(" |                 $config = base64_encode(" | ||||||
| @ -59,11 +61,11 @@ class InstallLogDrain | |||||||
|     # https://log-api.newrelic.com/log/v1 - US
 |     # https://log-api.newrelic.com/log/v1 - US
 | ||||||
|     base_uri \${BASE_URI} |     base_uri \${BASE_URI} | ||||||
| ");
 | ");
 | ||||||
|             } else if ($type === 'highlight') { |             } elseif ($type === 'highlight') { | ||||||
|                 if (!$server->settings->is_logdrain_highlight_enabled) { |                 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(" |                 $config = base64_encode(' | ||||||
| [SERVICE] | [SERVICE] | ||||||
|     Flush     5 |     Flush     5 | ||||||
|     Daemon    off |     Daemon    off | ||||||
| @ -71,7 +73,7 @@ class InstallLogDrain | |||||||
|     Parsers_File  parsers.conf |     Parsers_File  parsers.conf | ||||||
| [INPUT] | [INPUT] | ||||||
|     Name              forward |     Name              forward | ||||||
|     tag               \${HIGHLIGHT_PROJECT_ID} |     tag               ${HIGHLIGHT_PROJECT_ID} | ||||||
|     Buffer_Chunk_Size 1M |     Buffer_Chunk_Size 1M | ||||||
|     Buffer_Max_Size   6M |     Buffer_Max_Size   6M | ||||||
| [OUTPUT] | [OUTPUT] | ||||||
| @ -79,9 +81,9 @@ class InstallLogDrain | |||||||
|     Match               * |     Match               * | ||||||
|     Host                otel.highlight.io |     Host                otel.highlight.io | ||||||
|     Port                24224 |     Port                24224 | ||||||
| ");
 | '); | ||||||
|             } else if ($type === 'axiom') { |             } elseif ($type === 'axiom') { | ||||||
|                 if (!$server->settings->is_logdrain_axiom_enabled) { |                 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(" |                 $config = base64_encode(" | ||||||
| @ -116,8 +118,8 @@ class InstallLogDrain | |||||||
|     json_date_format iso8601 |     json_date_format iso8601 | ||||||
|     tls On |     tls On | ||||||
| ");
 | ");
 | ||||||
|             } else if ($type === 'custom') { |             } elseif ($type === 'custom') { | ||||||
|                 if (!$server->settings->is_logdrain_custom_enabled) { |                 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); |                 $config = base64_encode($server->settings->logdrain_custom_config); | ||||||
| @ -133,7 +135,7 @@ class InstallLogDrain | |||||||
|     Regex       /^(?!\s*$).+/ |     Regex       /^(?!\s*$).+/ | ||||||
| ");
 | ");
 | ||||||
|             } |             } | ||||||
|             $compose = base64_encode(" |             $compose = base64_encode(' | ||||||
| services: | services: | ||||||
|   coolify-log-drain: |   coolify-log-drain: | ||||||
|     image: cr.fluentbit.io/fluent/fluent-bit:2.0 |     image: cr.fluentbit.io/fluent/fluent-bit:2.0 | ||||||
| @ -147,7 +149,7 @@ services: | |||||||
|     ports: |     ports: | ||||||
|       - 127.0.0.1:24224:24224 |       - 127.0.0.1:24224:24224 | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
| ");
 | '); | ||||||
|             $readme = base64_encode('# New Relic Log Drain
 |             $readme = base64_encode('# New Relic Log Drain
 | ||||||
| This log drain is based on [Fluent Bit](https://fluentbit.io/) and New Relic Log Forwarder. | This log drain is based on [Fluent Bit](https://fluentbit.io/) and New Relic Log Forwarder. | ||||||
| 
 | 
 | ||||||
| @ -160,11 +162,11 @@ Files: | |||||||
|             $base_uri = $server->settings->logdrain_newrelic_base_uri; |             $base_uri = $server->settings->logdrain_newrelic_base_uri; | ||||||
|             $base_path = config('coolify.base_config_path'); |             $base_path = config('coolify.base_config_path'); | ||||||
| 
 | 
 | ||||||
|             $config_path = $base_path . '/log-drains'; |             $config_path = $base_path.'/log-drains'; | ||||||
|             $fluent_bit_config = $config_path . '/fluent-bit.conf'; |             $fluent_bit_config = $config_path.'/fluent-bit.conf'; | ||||||
|             $parsers_config = $config_path . '/parsers.conf'; |             $parsers_config = $config_path.'/parsers.conf'; | ||||||
|             $compose_path = $config_path . '/docker-compose.yml'; |             $compose_path = $config_path.'/docker-compose.yml'; | ||||||
|             $readme_path = $config_path . '/README.md'; |             $readme_path = $config_path.'/README.md'; | ||||||
|             $command = [ |             $command = [ | ||||||
|                 "echo 'Saving configuration'", |                 "echo 'Saving configuration'", | ||||||
|                 "mkdir -p $config_path", |                 "mkdir -p $config_path", | ||||||
| @ -180,18 +182,18 @@ Files: | |||||||
|                     "echo LICENSE_KEY=$license_key >> $config_path/.env", |                     "echo LICENSE_KEY=$license_key >> $config_path/.env", | ||||||
|                     "echo BASE_URI=$base_uri >> $config_path/.env", |                     "echo BASE_URI=$base_uri >> $config_path/.env", | ||||||
|                 ]; |                 ]; | ||||||
|             } else if ($type === 'highlight') { |             } elseif ($type === 'highlight') { | ||||||
|                 $add_envs_command = [ |                 $add_envs_command = [ | ||||||
|                     "echo HIGHLIGHT_PROJECT_ID={$server->settings->logdrain_highlight_project_id} >> $config_path/.env", |                     "echo HIGHLIGHT_PROJECT_ID={$server->settings->logdrain_highlight_project_id} >> $config_path/.env", | ||||||
|                 ]; |                 ]; | ||||||
|             } else if ($type === 'axiom') { |             } elseif ($type === 'axiom') { | ||||||
|                 $add_envs_command = [ |                 $add_envs_command = [ | ||||||
|                     "echo AXIOM_DATASET_NAME={$server->settings->logdrain_axiom_dataset_name} >> $config_path/.env", |                     "echo AXIOM_DATASET_NAME={$server->settings->logdrain_axiom_dataset_name} >> $config_path/.env", | ||||||
|                     "echo AXIOM_API_KEY={$server->settings->logdrain_axiom_api_key} >> $config_path/.env", |                     "echo AXIOM_API_KEY={$server->settings->logdrain_axiom_api_key} >> $config_path/.env", | ||||||
|                 ]; |                 ]; | ||||||
|             } else if ($type === 'custom') { |             } elseif ($type === 'custom') { | ||||||
|                 $add_envs_command = [ |                 $add_envs_command = [ | ||||||
|                     "touch $config_path/.env" |                     "touch $config_path/.env", | ||||||
|                 ]; |                 ]; | ||||||
|             } else { |             } else { | ||||||
|                 throw new \Exception('Unknown log drain type.'); |                 throw new \Exception('Unknown log drain type.'); | ||||||
| @ -203,6 +205,7 @@ Files: | |||||||
|                 "cd $config_path && docker compose up -d --remove-orphans", |                 "cd $config_path && docker compose up -d --remove-orphans", | ||||||
|             ]; |             ]; | ||||||
|             $command = array_merge($command, $add_envs_command, $restart_command); |             $command = array_merge($command, $add_envs_command, $restart_command); | ||||||
|  | 
 | ||||||
|             return instant_remote_process($command, $server); |             return instant_remote_process($command, $server); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|  | |||||||
| @ -2,12 +2,13 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Server; | namespace App\Actions\Server; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class StartSentinel | class StartSentinel | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Server $server, $version = 'latest', bool $restart = false) |     public function handle(Server $server, $version = 'latest', bool $restart = false) | ||||||
|     { |     { | ||||||
|         if ($restart) { |         if ($restart) { | ||||||
| @ -15,8 +16,8 @@ class StartSentinel | |||||||
|         } |         } | ||||||
|         instant_remote_process([ |         instant_remote_process([ | ||||||
|             "docker run --rm --pull always -d -e \"SCHEDULER=true\" --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify/metrics:/app/metrics -v /data/coolify/logs:/app/logs --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 ghcr.io/coollabsio/sentinel:$version", |             "docker run --rm --pull always -d -e \"SCHEDULER=true\" --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify/metrics:/app/metrics -v /data/coolify/logs:/app/logs --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 ghcr.io/coollabsio/sentinel:$version", | ||||||
|             "chown -R 9999:root /data/coolify/metrics /data/coolify/logs", |             'chown -R 9999:root /data/coolify/metrics /data/coolify/logs', | ||||||
|             "chmod -R 700 /data/coolify/metrics /data/coolify/logs" |             'chmod -R 700 /data/coolify/metrics /data/coolify/logs', | ||||||
|         ], $server, false); |         ], $server, false); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,15 +2,18 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Server; | namespace App\Actions\Server; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\InstanceSettings; | use App\Models\InstanceSettings; | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class UpdateCoolify | class UpdateCoolify | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public ?Server $server = null; |     public ?Server $server = null; | ||||||
|  | 
 | ||||||
|     public ?string $latestVersion = null; |     public ?string $latestVersion = null; | ||||||
|  | 
 | ||||||
|     public ?string $currentVersion = null; |     public ?string $currentVersion = null; | ||||||
| 
 | 
 | ||||||
|     public function handle($manual_update = false) |     public function handle($manual_update = false) | ||||||
| @ -19,14 +22,14 @@ class UpdateCoolify | |||||||
|             $settings = InstanceSettings::get(); |             $settings = InstanceSettings::get(); | ||||||
|             ray('Running InstanceAutoUpdateJob'); |             ray('Running InstanceAutoUpdateJob'); | ||||||
|             $this->server = Server::find(0); |             $this->server = Server::find(0); | ||||||
|             if (!$this->server) { |             if (! $this->server) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             CleanupDocker::run($this->server, false); |             CleanupDocker::run($this->server, false); | ||||||
|             $this->latestVersion = get_latest_version_of_coolify(); |             $this->latestVersion = get_latest_version_of_coolify(); | ||||||
|             $this->currentVersion = config('version'); |             $this->currentVersion = config('version'); | ||||||
|             if (!$manual_update) { |             if (! $manual_update) { | ||||||
|                 if (!$settings->is_auto_update_enabled) { |                 if (! $settings->is_auto_update_enabled) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 if ($this->latestVersion === $this->currentVersion) { |                 if ($this->latestVersion === $this->currentVersion) { | ||||||
| @ -46,14 +49,15 @@ class UpdateCoolify | |||||||
|     { |     { | ||||||
|         if (isDev()) { |         if (isDev()) { | ||||||
|             remote_process([ |             remote_process([ | ||||||
|                 "sleep 10" |                 'sleep 10', | ||||||
|             ], $this->server); |             ], $this->server); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         remote_process([ |         remote_process([ | ||||||
|             "curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh", |             'curl -fsSL https://cdn.coollabs.io/coolify/upgrade.sh -o /data/coolify/source/upgrade.sh', | ||||||
|             "bash /data/coolify/source/upgrade.sh $this->latestVersion" |             "bash /data/coolify/source/upgrade.sh $this->latestVersion", | ||||||
|         ], $this->server); |         ], $this->server); | ||||||
|         return; | 
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,12 +2,13 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Service; | namespace App\Actions\Service; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Service; | use App\Models\Service; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class DeleteService | class DeleteService | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Service $service) |     public function handle(Service $service) | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|  | |||||||
| @ -2,26 +2,27 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Service; | namespace App\Actions\Service; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Service; | use App\Models\Service; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| use Symfony\Component\Yaml\Yaml; | use Symfony\Component\Yaml\Yaml; | ||||||
| 
 | 
 | ||||||
| class StartService | class StartService | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Service $service) |     public function handle(Service $service) | ||||||
|     { |     { | ||||||
|         ray('Starting service: ' . $service->name); |         ray('Starting service: '.$service->name); | ||||||
|         $service->saveComposeConfigs(); |         $service->saveComposeConfigs(); | ||||||
|         $commands[] = "cd " . $service->workdir(); |         $commands[] = 'cd '.$service->workdir(); | ||||||
|         $commands[] = "echo 'Saved configuration files to {$service->workdir()}.'"; |         $commands[] = "echo 'Saved configuration files to {$service->workdir()}.'"; | ||||||
|         $commands[] = "echo 'Creating Docker network.'"; |         $commands[] = "echo 'Creating Docker network.'"; | ||||||
|         $commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid"; |         $commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid"; | ||||||
|         $commands[] = "echo Starting service."; |         $commands[] = 'echo Starting service.'; | ||||||
|         $commands[] = "echo 'Pulling images.'"; |         $commands[] = "echo 'Pulling images.'"; | ||||||
|         $commands[] = "docker compose pull"; |         $commands[] = 'docker compose pull'; | ||||||
|         $commands[] = "echo 'Starting containers.'"; |         $commands[] = "echo 'Starting containers.'"; | ||||||
|         $commands[] = "docker compose up -d --remove-orphans --force-recreate --build"; |         $commands[] = 'docker compose up -d --remove-orphans --force-recreate --build'; | ||||||
|         $commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true"; |         $commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true"; | ||||||
|         if (data_get($service, 'connect_to_docker_network')) { |         if (data_get($service, 'connect_to_docker_network')) { | ||||||
|             $compose = data_get($service, 'docker_compose', []); |             $compose = data_get($service, 'docker_compose', []); | ||||||
| @ -32,6 +33,7 @@ class StartService | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         $activity = remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged'); |         $activity = remote_process($commands, $service->server, type_uuid: $service->uuid, callEventOnFinish: 'ServiceStatusChanged'); | ||||||
|  | 
 | ||||||
|         return $activity; |         return $activity; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,20 +2,21 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Actions\Service; | namespace App\Actions\Service; | ||||||
| 
 | 
 | ||||||
| use Lorisleiva\Actions\Concerns\AsAction; |  | ||||||
| use App\Models\Service; | use App\Models\Service; | ||||||
|  | use Lorisleiva\Actions\Concerns\AsAction; | ||||||
| 
 | 
 | ||||||
| class StopService | class StopService | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Service $service) |     public function handle(Service $service) | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $server = $service->destination->server; |             $server = $service->destination->server; | ||||||
|             if (!$server->isFunctional()) { |             if (! $server->isFunctional()) { | ||||||
|                 return 'Server is not functional'; |                 return 'Server is not functional'; | ||||||
|             } |             } | ||||||
|             ray('Stopping service: ' . $service->name); |             ray('Stopping service: '.$service->name); | ||||||
|             $applications = $service->applications()->get(); |             $applications = $service->applications()->get(); | ||||||
|             foreach ($applications as $application) { |             foreach ($applications as $application) { | ||||||
|                 instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server); |                 instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server); | ||||||
| @ -33,6 +34,7 @@ class StopService | |||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             echo $e->getMessage(); |             echo $e->getMessage(); | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return $e->getMessage(); |             return $e->getMessage(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,18 +8,21 @@ use Lorisleiva\Actions\Concerns\AsAction; | |||||||
| class ComplexStatusCheck | class ComplexStatusCheck | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Application $application) |     public function handle(Application $application) | ||||||
|     { |     { | ||||||
|         $servers = $application->additional_servers; |         $servers = $application->additional_servers; | ||||||
|         $servers->push($application->destination->server); |         $servers->push($application->destination->server); | ||||||
|         foreach ($servers as $server) { |         foreach ($servers as $server) { | ||||||
|             $is_main_server = $application->destination->server->id === $server->id; |             $is_main_server = $application->destination->server->id === $server->id; | ||||||
|             if (!$server->isFunctional()) { |             if (! $server->isFunctional()) { | ||||||
|                 if ($is_main_server) { |                 if ($is_main_server) { | ||||||
|                     $application->update(['status' => 'exited:unhealthy']); |                     $application->update(['status' => 'exited:unhealthy']); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } else { |                 } else { | ||||||
|                     $application->additional_servers()->updateExistingPivot($server->id, ['status' => 'exited:unhealthy']); |                     $application->additional_servers()->updateExistingPivot($server->id, ['status' => 'exited:unhealthy']); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -44,9 +47,11 @@ class ComplexStatusCheck | |||||||
|             } else { |             } else { | ||||||
|                 if ($is_main_server) { |                 if ($is_main_server) { | ||||||
|                     $application->update(['status' => 'exited:unhealthy']); |                     $application->update(['status' => 'exited:unhealthy']); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } else { |                 } else { | ||||||
|                     $application->additional_servers()->updateExistingPivot($server->id, ['status' => 'exited:unhealthy']); |                     $application->additional_servers()->updateExistingPivot($server->id, ['status' => 'exited:unhealthy']); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -8,17 +8,20 @@ use Lorisleiva\Actions\Concerns\AsAction; | |||||||
| class PullImage | class PullImage | ||||||
| { | { | ||||||
|     use AsAction; |     use AsAction; | ||||||
|  | 
 | ||||||
|     public function handle(Service $resource) |     public function handle(Service $resource) | ||||||
|     { |     { | ||||||
|         $resource->saveComposeConfigs(); |         $resource->saveComposeConfigs(); | ||||||
| 
 | 
 | ||||||
|         $commands[] = "cd " . $resource->workdir(); |         $commands[] = 'cd '.$resource->workdir(); | ||||||
|         $commands[] = "echo 'Saved configuration files to {$resource->workdir()}.'"; |         $commands[] = "echo 'Saved configuration files to {$resource->workdir()}.'"; | ||||||
|         $commands[] = "docker compose pull"; |         $commands[] = 'docker compose pull'; | ||||||
| 
 | 
 | ||||||
|         $server = data_get($resource, 'server'); |         $server = data_get($resource, 'server'); | ||||||
| 
 | 
 | ||||||
|         if (!$server) return; |         if (! $server) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         instant_remote_process($commands, $resource->server); |         instant_remote_process($commands, $resource->server); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Console\Commands; | namespace App\Console\Commands; | ||||||
| 
 | 
 | ||||||
| use App\Models\Server; |  | ||||||
| use App\Models\User; | use App\Models\User; | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
| 
 | 
 | ||||||
| @ -29,9 +28,10 @@ class AdminRemoveUser extends Command | |||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $email = $this->argument('email'); |             $email = $this->argument('email'); | ||||||
|             $confirm = $this->confirm('Are you sure you want to remove user with email: ' . $email . '?'); |             $confirm = $this->confirm('Are you sure you want to remove user with email: '.$email.'?'); | ||||||
|             if (!$confirm) { |             if (! $confirm) { | ||||||
|                 $this->info('User removal cancelled.'); |                 $this->info('User removal cancelled.'); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $this->info("Removing user with email: $email"); |             $this->info("Removing user with email: $email"); | ||||||
| @ -40,6 +40,7 @@ class AdminRemoveUser extends Command | |||||||
|             foreach ($teams as $team) { |             foreach ($teams as $team) { | ||||||
|                 if ($team->members->count() > 1) { |                 if ($team->members->count() > 1) { | ||||||
|                     $this->error('User is a member of a team with more than one member. Please remove user from team first.'); |                     $this->error('User is a member of a team with more than one member. Please remove user from team first.'); | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 $team->delete(); |                 $team->delete(); | ||||||
| @ -48,6 +49,7 @@ class AdminRemoveUser extends Command | |||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             $this->error('Failed to remove user.'); |             $this->error('Failed to remove user.'); | ||||||
|             $this->error($e->getMessage()); |             $this->error($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use Illuminate\Console\Command; | |||||||
| class CleanupApplicationDeploymentQueue extends Command | class CleanupApplicationDeploymentQueue extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'cleanup:application-deployment-queue {--team-id=}'; |     protected $signature = 'cleanup:application-deployment-queue {--team-id=}'; | ||||||
|  | 
 | ||||||
|     protected $description = 'CleanupApplicationDeploymentQueue'; |     protected $description = 'CleanupApplicationDeploymentQueue'; | ||||||
| 
 | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
| @ -15,10 +16,10 @@ class CleanupApplicationDeploymentQueue extends Command | |||||||
|         $team_id = $this->option('team-id'); |         $team_id = $this->option('team-id'); | ||||||
|         $servers = \App\Models\Server::where('team_id', $team_id)->get(); |         $servers = \App\Models\Server::where('team_id', $team_id)->get(); | ||||||
|         foreach ($servers as $server) { |         foreach ($servers as $server) { | ||||||
|             $deployments = ApplicationDeploymentQueue::whereIn("status", ["in_progress", "queued"])->where("server_id", $server->id)->get(); |             $deployments = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->where('server_id', $server->id)->get(); | ||||||
|             foreach ($deployments as $deployment) { |             foreach ($deployments as $deployment) { | ||||||
|                 $deployment->update(['status' => 'failed']); |                 $deployment->update(['status' => 'failed']); | ||||||
|                 instant_remote_process(['docker rm -f ' . $deployment->deployment_uuid], $server, false); |                 instant_remote_process(['docker rm -f '.$deployment->deployment_uuid], $server, false); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use Illuminate\Support\Facades\DB; | |||||||
| class CleanupDatabase extends Command | class CleanupDatabase extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'cleanup:database {--yes}'; |     protected $signature = 'cleanup:database {--yes}'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Cleanup database'; |     protected $description = 'Cleanup database'; | ||||||
| 
 | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use Illuminate\Support\Facades\Redis; | |||||||
| class CleanupQueue extends Command | class CleanupQueue extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'cleanup:queue'; |     protected $signature = 'cleanup:queue'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Cleanup Queue'; |     protected $description = 'Cleanup Queue'; | ||||||
| 
 | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ use Illuminate\Console\Command; | |||||||
| class CleanupStuckedResources extends Command | class CleanupStuckedResources extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'cleanup:stucked-resources'; |     protected $signature = 'cleanup:stucked-resources'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Cleanup Stucked Resources'; |     protected $description = 'Cleanup Stucked Resources'; | ||||||
| 
 | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
| @ -28,6 +29,7 @@ class CleanupStuckedResources extends Command | |||||||
|         echo "Running cleanup stucked resources.\n"; |         echo "Running cleanup stucked resources.\n"; | ||||||
|         $this->cleanup_stucked_resources(); |         $this->cleanup_stucked_resources(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function cleanup_stucked_resources() |     private function cleanup_stucked_resources() | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
| @ -142,7 +144,7 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $scheduled_tasks = ScheduledTask::all(); |             $scheduled_tasks = ScheduledTask::all(); | ||||||
|             foreach ($scheduled_tasks as $scheduled_task) { |             foreach ($scheduled_tasks as $scheduled_task) { | ||||||
|                 if (!$scheduled_task->service && !$scheduled_task->application) { |                 if (! $scheduled_task->service && ! $scheduled_task->application) { | ||||||
|                     echo "Deleting stuck scheduledtask: {$scheduled_task->name}\n"; |                     echo "Deleting stuck scheduledtask: {$scheduled_task->name}\n"; | ||||||
|                     $scheduled_task->delete(); |                     $scheduled_task->delete(); | ||||||
|                 } |                 } | ||||||
| @ -155,19 +157,22 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $applications = Application::all(); |             $applications = Application::all(); | ||||||
|             foreach ($applications as $application) { |             foreach ($applications as $application) { | ||||||
|                 if (!data_get($application, 'environment')) { |                 if (! data_get($application, 'environment')) { | ||||||
|                     echo 'Application without environment: ' . $application->name . '\n'; |                     echo 'Application without environment: '.$application->name.'\n'; | ||||||
|                     $application->forceDelete(); |                     $application->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!$application->destination()) { |                 if (! $application->destination()) { | ||||||
|                     echo 'Application without destination: ' . $application->name . '\n'; |                     echo 'Application without destination: '.$application->name.'\n'; | ||||||
|                     $application->forceDelete(); |                     $application->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!data_get($application, 'destination.server')) { |                 if (! data_get($application, 'destination.server')) { | ||||||
|                     echo 'Application without server: ' . $application->name . '\n'; |                     echo 'Application without server: '.$application->name.'\n'; | ||||||
|                     $application->forceDelete(); |                     $application->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -177,19 +182,22 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $postgresqls = StandalonePostgresql::all()->where('id', '!=', 0); |             $postgresqls = StandalonePostgresql::all()->where('id', '!=', 0); | ||||||
|             foreach ($postgresqls as $postgresql) { |             foreach ($postgresqls as $postgresql) { | ||||||
|                 if (!data_get($postgresql, 'environment')) { |                 if (! data_get($postgresql, 'environment')) { | ||||||
|                     echo 'Postgresql without environment: ' . $postgresql->name . '\n'; |                     echo 'Postgresql without environment: '.$postgresql->name.'\n'; | ||||||
|                     $postgresql->forceDelete(); |                     $postgresql->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!$postgresql->destination()) { |                 if (! $postgresql->destination()) { | ||||||
|                     echo 'Postgresql without destination: ' . $postgresql->name . '\n'; |                     echo 'Postgresql without destination: '.$postgresql->name.'\n'; | ||||||
|                     $postgresql->forceDelete(); |                     $postgresql->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!data_get($postgresql, 'destination.server')) { |                 if (! data_get($postgresql, 'destination.server')) { | ||||||
|                     echo 'Postgresql without server: ' . $postgresql->name . '\n'; |                     echo 'Postgresql without server: '.$postgresql->name.'\n'; | ||||||
|                     $postgresql->forceDelete(); |                     $postgresql->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -199,19 +207,22 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $redis = StandaloneRedis::all(); |             $redis = StandaloneRedis::all(); | ||||||
|             foreach ($redis as $redis) { |             foreach ($redis as $redis) { | ||||||
|                 if (!data_get($redis, 'environment')) { |                 if (! data_get($redis, 'environment')) { | ||||||
|                     echo 'Redis without environment: ' . $redis->name . '\n'; |                     echo 'Redis without environment: '.$redis->name.'\n'; | ||||||
|                     $redis->forceDelete(); |                     $redis->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!$redis->destination()) { |                 if (! $redis->destination()) { | ||||||
|                     echo 'Redis without destination: ' . $redis->name . '\n'; |                     echo 'Redis without destination: '.$redis->name.'\n'; | ||||||
|                     $redis->forceDelete(); |                     $redis->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!data_get($redis, 'destination.server')) { |                 if (! data_get($redis, 'destination.server')) { | ||||||
|                     echo 'Redis without server: ' . $redis->name . '\n'; |                     echo 'Redis without server: '.$redis->name.'\n'; | ||||||
|                     $redis->forceDelete(); |                     $redis->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -222,19 +233,22 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $mongodbs = StandaloneMongodb::all(); |             $mongodbs = StandaloneMongodb::all(); | ||||||
|             foreach ($mongodbs as $mongodb) { |             foreach ($mongodbs as $mongodb) { | ||||||
|                 if (!data_get($mongodb, 'environment')) { |                 if (! data_get($mongodb, 'environment')) { | ||||||
|                     echo 'Mongodb without environment: ' . $mongodb->name . '\n'; |                     echo 'Mongodb without environment: '.$mongodb->name.'\n'; | ||||||
|                     $mongodb->forceDelete(); |                     $mongodb->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!$mongodb->destination()) { |                 if (! $mongodb->destination()) { | ||||||
|                     echo 'Mongodb without destination: ' . $mongodb->name . '\n'; |                     echo 'Mongodb without destination: '.$mongodb->name.'\n'; | ||||||
|                     $mongodb->forceDelete(); |                     $mongodb->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!data_get($mongodb, 'destination.server')) { |                 if (! data_get($mongodb, 'destination.server')) { | ||||||
|                     echo 'Mongodb without server:  ' . $mongodb->name . '\n'; |                     echo 'Mongodb without server:  '.$mongodb->name.'\n'; | ||||||
|                     $mongodb->forceDelete(); |                     $mongodb->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -245,19 +259,22 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $mysqls = StandaloneMysql::all(); |             $mysqls = StandaloneMysql::all(); | ||||||
|             foreach ($mysqls as $mysql) { |             foreach ($mysqls as $mysql) { | ||||||
|                 if (!data_get($mysql, 'environment')) { |                 if (! data_get($mysql, 'environment')) { | ||||||
|                     echo 'Mysql without environment: ' . $mysql->name . '\n'; |                     echo 'Mysql without environment: '.$mysql->name.'\n'; | ||||||
|                     $mysql->forceDelete(); |                     $mysql->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!$mysql->destination()) { |                 if (! $mysql->destination()) { | ||||||
|                     echo 'Mysql without destination: ' . $mysql->name . '\n'; |                     echo 'Mysql without destination: '.$mysql->name.'\n'; | ||||||
|                     $mysql->forceDelete(); |                     $mysql->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!data_get($mysql, 'destination.server')) { |                 if (! data_get($mysql, 'destination.server')) { | ||||||
|                     echo 'Mysql without server: ' . $mysql->name . '\n'; |                     echo 'Mysql without server: '.$mysql->name.'\n'; | ||||||
|                     $mysql->forceDelete(); |                     $mysql->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -268,19 +285,22 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $mariadbs = StandaloneMariadb::all(); |             $mariadbs = StandaloneMariadb::all(); | ||||||
|             foreach ($mariadbs as $mariadb) { |             foreach ($mariadbs as $mariadb) { | ||||||
|                 if (!data_get($mariadb, 'environment')) { |                 if (! data_get($mariadb, 'environment')) { | ||||||
|                     echo 'Mariadb without environment: ' . $mariadb->name . '\n'; |                     echo 'Mariadb without environment: '.$mariadb->name.'\n'; | ||||||
|                     $mariadb->forceDelete(); |                     $mariadb->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!$mariadb->destination()) { |                 if (! $mariadb->destination()) { | ||||||
|                     echo 'Mariadb without destination: ' . $mariadb->name . '\n'; |                     echo 'Mariadb without destination: '.$mariadb->name.'\n'; | ||||||
|                     $mariadb->forceDelete(); |                     $mariadb->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!data_get($mariadb, 'destination.server')) { |                 if (! data_get($mariadb, 'destination.server')) { | ||||||
|                     echo 'Mariadb without server: ' . $mariadb->name . '\n'; |                     echo 'Mariadb without server: '.$mariadb->name.'\n'; | ||||||
|                     $mariadb->forceDelete(); |                     $mariadb->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -291,19 +311,22 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $services = Service::all(); |             $services = Service::all(); | ||||||
|             foreach ($services as $service) { |             foreach ($services as $service) { | ||||||
|                 if (!data_get($service, 'environment')) { |                 if (! data_get($service, 'environment')) { | ||||||
|                     echo 'Service without environment: ' . $service->name . '\n'; |                     echo 'Service without environment: '.$service->name.'\n'; | ||||||
|                     $service->forceDelete(); |                     $service->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!$service->destination()) { |                 if (! $service->destination()) { | ||||||
|                     echo 'Service without destination: ' . $service->name . '\n'; |                     echo 'Service without destination: '.$service->name.'\n'; | ||||||
|                     $service->forceDelete(); |                     $service->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if (!data_get($service, 'server')) { |                 if (! data_get($service, 'server')) { | ||||||
|                     echo 'Service without server: ' . $service->name . '\n'; |                     echo 'Service without server: '.$service->name.'\n'; | ||||||
|                     $service->forceDelete(); |                     $service->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -313,9 +336,10 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $serviceApplications = ServiceApplication::all(); |             $serviceApplications = ServiceApplication::all(); | ||||||
|             foreach ($serviceApplications as $service) { |             foreach ($serviceApplications as $service) { | ||||||
|                 if (!data_get($service, 'service')) { |                 if (! data_get($service, 'service')) { | ||||||
|                     echo 'ServiceApplication without service: ' . $service->name . '\n'; |                     echo 'ServiceApplication without service: '.$service->name.'\n'; | ||||||
|                     $service->forceDelete(); |                     $service->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -325,9 +349,10 @@ class CleanupStuckedResources extends Command | |||||||
|         try { |         try { | ||||||
|             $serviceDatabases = ServiceDatabase::all(); |             $serviceDatabases = ServiceDatabase::all(); | ||||||
|             foreach ($serviceDatabases as $service) { |             foreach ($serviceDatabases as $service) { | ||||||
|                 if (!data_get($service, 'service')) { |                 if (! data_get($service, 'service')) { | ||||||
|                     echo 'ServiceDatabase without service: ' . $service->name . '\n'; |                     echo 'ServiceDatabase without service: '.$service->name.'\n'; | ||||||
|                     $service->forceDelete(); |                     $service->forceDelete(); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use Illuminate\Console\Command; | |||||||
| class CleanupUnreachableServers extends Command | class CleanupUnreachableServers extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'cleanup:unreachable-servers'; |     protected $signature = 'cleanup:unreachable-servers'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Cleanup Unreachable Servers (7 days)'; |     protected $description = 'Cleanup Unreachable Servers (7 days)'; | ||||||
| 
 | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
| @ -19,7 +20,7 @@ class CleanupUnreachableServers extends Command | |||||||
|                 echo "Cleanup unreachable server ($server->id) with name $server->name"; |                 echo "Cleanup unreachable server ($server->id) with name $server->name"; | ||||||
|                 send_internal_notification("Server $server->name is unreachable for 7 days. Cleaning up..."); |                 send_internal_notification("Server $server->name is unreachable for 7 days. Cleaning up..."); | ||||||
|                 $server->update([ |                 $server->update([ | ||||||
|                     'ip' => '1.2.3.4' |                     'ip' => '1.2.3.4', | ||||||
|                 ]); |                 ]); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ use Illuminate\Support\Facades\Process; | |||||||
| class Dev extends Command | class Dev extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'dev:init'; |     protected $signature = 'dev:init'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Init the app in dev mode'; |     protected $description = 'Init the app in dev mode'; | ||||||
| 
 | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
| @ -21,7 +22,7 @@ class Dev extends Command | |||||||
|         } |         } | ||||||
|         // Seed database if it's empty
 |         // Seed database if it's empty
 | ||||||
|         $settings = InstanceSettings::find(0); |         $settings = InstanceSettings::find(0); | ||||||
|         if (!$settings) { |         if (! $settings) { | ||||||
|             echo "Initializing instance, seeding database.\n"; |             echo "Initializing instance, seeding database.\n"; | ||||||
|             Artisan::call('migrate --seed'); |             Artisan::call('migrate --seed'); | ||||||
|         } else { |         } else { | ||||||
|  | |||||||
| @ -2,12 +2,10 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Console\Commands; | namespace App\Console\Commands; | ||||||
| 
 | 
 | ||||||
| use App\Jobs\DatabaseBackupStatusJob; |  | ||||||
| use App\Jobs\SendConfirmationForWaitlistJob; | use App\Jobs\SendConfirmationForWaitlistJob; | ||||||
| use App\Models\Application; | use App\Models\Application; | ||||||
| use App\Models\ApplicationPreview; | use App\Models\ApplicationPreview; | ||||||
| use App\Models\ScheduledDatabaseBackup; | use App\Models\ScheduledDatabaseBackup; | ||||||
| use App\Models\ScheduledDatabaseBackupExecution; |  | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use App\Models\StandalonePostgresql; | use App\Models\StandalonePostgresql; | ||||||
| use App\Models\Team; | use App\Models\Team; | ||||||
| @ -49,7 +47,9 @@ class Emails extends Command | |||||||
|      * Execute the console command. |      * Execute the console command. | ||||||
|      */ |      */ | ||||||
|     private ?MailMessage $mail = null; |     private ?MailMessage $mail = null; | ||||||
|  | 
 | ||||||
|     private ?string $email = null; |     private ?string $email = null; | ||||||
|  | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         $type = select( |         $type = select( | ||||||
| @ -73,21 +73,22 @@ class Emails extends Command | |||||||
|         ); |         ); | ||||||
|         $emailsGathered = ['realusers-before-trial', 'realusers-server-lost-connection']; |         $emailsGathered = ['realusers-before-trial', 'realusers-server-lost-connection']; | ||||||
|         if (isDev()) { |         if (isDev()) { | ||||||
|             $this->email = "test@example.com"; |             $this->email = 'test@example.com'; | ||||||
|         } else { |         } else { | ||||||
|             if (!in_array($type, $emailsGathered)) { |             if (! in_array($type, $emailsGathered)) { | ||||||
|                 $this->email = text('Email Address to send to:'); |                 $this->email = text('Email Address to send to:'); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         set_transanctional_email_settings(); |         set_transanctional_email_settings(); | ||||||
| 
 | 
 | ||||||
|         $this->mail = new MailMessage(); |         $this->mail = new MailMessage(); | ||||||
|         $this->mail->subject("Test Email"); |         $this->mail->subject('Test Email'); | ||||||
|         switch ($type) { |         switch ($type) { | ||||||
|             case 'updates': |             case 'updates': | ||||||
|                 $teams = Team::all(); |                 $teams = Team::all(); | ||||||
|                 if (!$teams || $teams->isEmpty()) { |                 if (! $teams || $teams->isEmpty()) { | ||||||
|                     echo 'No teams found.' . PHP_EOL; |                     echo 'No teams found.'.PHP_EOL; | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 $emails = []; |                 $emails = []; | ||||||
| @ -99,7 +100,7 @@ class Emails extends Command | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 $emails = array_unique($emails); |                 $emails = array_unique($emails); | ||||||
|                 $this->info("Sending to " . count($emails) . " emails."); |                 $this->info('Sending to '.count($emails).' emails.'); | ||||||
|                 foreach ($emails as $email) { |                 foreach ($emails as $email) { | ||||||
|                     $this->info($email); |                     $this->info($email); | ||||||
|                 } |                 } | ||||||
| @ -111,7 +112,7 @@ class Emails extends Command | |||||||
|                         $unsubscribeUrl = route('unsubscribe.marketing.emails', [ |                         $unsubscribeUrl = route('unsubscribe.marketing.emails', [ | ||||||
|                             'token' => encrypt($email), |                             'token' => encrypt($email), | ||||||
|                         ]); |                         ]); | ||||||
|                         $this->mail->view('emails.updates', ["unsubscribeUrl" => $unsubscribeUrl]); |                         $this->mail->view('emails.updates', ['unsubscribeUrl' => $unsubscribeUrl]); | ||||||
|                         $this->sendEmail($email); |                         $this->sendEmail($email); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -157,7 +158,7 @@ class Emails extends Command | |||||||
|             case 'application-deployment-failed': |             case 'application-deployment-failed': | ||||||
|                 $application = Application::all()->first(); |                 $application = Application::all()->first(); | ||||||
|                 $preview = ApplicationPreview::all()->first(); |                 $preview = ApplicationPreview::all()->first(); | ||||||
|                 if (!$preview) { |                 if (! $preview) { | ||||||
|                     $preview = ApplicationPreview::create([ |                     $preview = ApplicationPreview::create([ | ||||||
|                         'application_id' => $application->id, |                         'application_id' => $application->id, | ||||||
|                         'pull_request_id' => 1, |                         'pull_request_id' => 1, | ||||||
| @ -178,7 +179,7 @@ class Emails extends Command | |||||||
|             case 'backup-failed': |             case 'backup-failed': | ||||||
|                 $backup = ScheduledDatabaseBackup::all()->first(); |                 $backup = ScheduledDatabaseBackup::all()->first(); | ||||||
|                 $db = StandalonePostgresql::all()->first(); |                 $db = StandalonePostgresql::all()->first(); | ||||||
|                 if (!$backup) { |                 if (! $backup) { | ||||||
|                     $backup = ScheduledDatabaseBackup::create([ |                     $backup = ScheduledDatabaseBackup::create([ | ||||||
|                         'enabled' => true, |                         'enabled' => true, | ||||||
|                         'frequency' => 'daily', |                         'frequency' => 'daily', | ||||||
| @ -188,14 +189,14 @@ class Emails extends Command | |||||||
|                         'team_id' => 0, |                         'team_id' => 0, | ||||||
|                     ]); |                     ]); | ||||||
|                 } |                 } | ||||||
|                 $output = 'Because of an error, the backup of the database ' . $db->name . ' failed.'; |                 $output = 'Because of an error, the backup of the database '.$db->name.' failed.'; | ||||||
|                 $this->mail = (new BackupFailed($backup, $db, $output))->toMail(); |                 $this->mail = (new BackupFailed($backup, $db, $output))->toMail(); | ||||||
|                 $this->sendEmail(); |                 $this->sendEmail(); | ||||||
|                 break; |                 break; | ||||||
|             case 'backup-success': |             case 'backup-success': | ||||||
|                 $backup = ScheduledDatabaseBackup::all()->first(); |                 $backup = ScheduledDatabaseBackup::all()->first(); | ||||||
|                 $db = StandalonePostgresql::all()->first(); |                 $db = StandalonePostgresql::all()->first(); | ||||||
|                 if (!$backup) { |                 if (! $backup) { | ||||||
|                     $backup = ScheduledDatabaseBackup::create([ |                     $backup = ScheduledDatabaseBackup::create([ | ||||||
|                         'enabled' => true, |                         'enabled' => true, | ||||||
|                         'frequency' => 'daily', |                         'frequency' => 'daily', | ||||||
| @ -244,8 +245,9 @@ class Emails extends Command | |||||||
|                 $this->mail->view('emails.before-trial-conversion'); |                 $this->mail->view('emails.before-trial-conversion'); | ||||||
|                 $this->mail->subject('Trial period has been added for all subscription plans.'); |                 $this->mail->subject('Trial period has been added for all subscription plans.'); | ||||||
|                 $teams = Team::doesntHave('subscription')->where('id', '!=', 0)->get(); |                 $teams = Team::doesntHave('subscription')->where('id', '!=', 0)->get(); | ||||||
|                 if (!$teams || $teams->isEmpty()) { |                 if (! $teams || $teams->isEmpty()) { | ||||||
|                     echo 'No teams found.' . PHP_EOL; |                     echo 'No teams found.'.PHP_EOL; | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 $emails = []; |                 $emails = []; | ||||||
| @ -257,7 +259,7 @@ class Emails extends Command | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 $emails = array_unique($emails); |                 $emails = array_unique($emails); | ||||||
|                 $this->info("Sending to " . count($emails) . " emails."); |                 $this->info('Sending to '.count($emails).' emails.'); | ||||||
|                 foreach ($emails as $email) { |                 foreach ($emails as $email) { | ||||||
|                     $this->info($email); |                     $this->info($email); | ||||||
|                 } |                 } | ||||||
| @ -271,7 +273,7 @@ class Emails extends Command | |||||||
|             case 'realusers-server-lost-connection': |             case 'realusers-server-lost-connection': | ||||||
|                 $serverId = text('Server Id'); |                 $serverId = text('Server Id'); | ||||||
|                 $server = Server::find($serverId); |                 $server = Server::find($serverId); | ||||||
|                 if (!$server) { |                 if (! $server) { | ||||||
|                     throw new Exception('Server not found'); |                     throw new Exception('Server not found'); | ||||||
|                 } |                 } | ||||||
|                 $admins = []; |                 $admins = []; | ||||||
| @ -281,7 +283,7 @@ class Emails extends Command | |||||||
|                         $admins[] = $member->email; |                         $admins[] = $member->email; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 $this->info('Sending to ' . count($admins) . ' admins.'); |                 $this->info('Sending to '.count($admins).' admins.'); | ||||||
|                 foreach ($admins as $admin) { |                 foreach ($admins as $admin) { | ||||||
|                     $this->info($admin); |                     $this->info($admin); | ||||||
|                 } |                 } | ||||||
| @ -289,14 +291,15 @@ class Emails extends Command | |||||||
|                 $this->mail->view('emails.server-lost-connection', [ |                 $this->mail->view('emails.server-lost-connection', [ | ||||||
|                     'name' => $server->name, |                     'name' => $server->name, | ||||||
|                 ]); |                 ]); | ||||||
|                 $this->mail->subject('Action required: Server ' . $server->name . ' lost connection.'); |                 $this->mail->subject('Action required: Server '.$server->name.' lost connection.'); | ||||||
|                 foreach ($admins as $email) { |                 foreach ($admins as $email) { | ||||||
|                     $this->sendEmail($email); |                     $this->sendEmail($email); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     private function sendEmail(string $email = null) | 
 | ||||||
|  |     private function sendEmail(?string $email = null) | ||||||
|     { |     { | ||||||
|         if ($email) { |         if ($email) { | ||||||
|             $this->email = $email; |             $this->email = $email; | ||||||
| @ -307,7 +310,7 @@ class Emails extends Command | |||||||
|             fn (Message $message) => $message |             fn (Message $message) => $message | ||||||
|                 ->to($this->email) |                 ->to($this->email) | ||||||
|                 ->subject($this->mail->subject) |                 ->subject($this->mail->subject) | ||||||
|                 ->html((string)$this->mail->render()) |                 ->html((string) $this->mail->render()) | ||||||
|         ); |         ); | ||||||
|         $this->info("Email sent to $this->email successfully. 📧"); |         $this->info("Email sent to $this->email successfully. 📧"); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -7,7 +7,9 @@ use Illuminate\Console\Command; | |||||||
| class Horizon extends Command | class Horizon extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'start:horizon'; |     protected $signature = 'start:horizon'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Start Horizon'; |     protected $description = 'Start Horizon'; | ||||||
|  | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         if (config('coolify.is_horizon_enabled')) { |         if (config('coolify.is_horizon_enabled')) { | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ use Illuminate\Support\Facades\Http; | |||||||
| class Init extends Command | class Init extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'app:init {--full-cleanup} {--cleanup-deployments}'; |     protected $signature = 'app:init {--full-cleanup} {--cleanup-deployments}'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Cleanup instance related stuffs'; |     protected $description = 'Cleanup instance related stuffs'; | ||||||
| 
 | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
| @ -26,6 +27,7 @@ class Init extends Command | |||||||
|         if ($cleanup_deployments) { |         if ($cleanup_deployments) { | ||||||
|             echo "Running cleanup deployments.\n"; |             echo "Running cleanup deployments.\n"; | ||||||
|             $this->cleanup_in_progress_application_deployments(); |             $this->cleanup_in_progress_application_deployments(); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if ($full_cleanup) { |         if ($full_cleanup) { | ||||||
| @ -35,7 +37,7 @@ class Init extends Command | |||||||
|             $this->cleanup_stucked_helper_containers(); |             $this->cleanup_stucked_helper_containers(); | ||||||
|             $this->call('cleanup:queue'); |             $this->call('cleanup:queue'); | ||||||
|             $this->call('cleanup:stucked-resources'); |             $this->call('cleanup:stucked-resources'); | ||||||
|             if (!isCloud()) { |             if (! isCloud()) { | ||||||
|                 try { |                 try { | ||||||
|                     $server = Server::find(0)->first(); |                     $server = Server::find(0)->first(); | ||||||
|                     $server->setupDynamicProxyConfiguration(); |                     $server->setupDynamicProxyConfiguration(); | ||||||
| @ -45,13 +47,14 @@ class Init extends Command | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             $settings = InstanceSettings::get(); |             $settings = InstanceSettings::get(); | ||||||
|             if (!is_null(env('AUTOUPDATE', null))) { |             if (! is_null(env('AUTOUPDATE', null))) { | ||||||
|                 if (env('AUTOUPDATE') == true) { |                 if (env('AUTOUPDATE') == true) { | ||||||
|                     $settings->update(['is_auto_update_enabled' => true]); |                     $settings->update(['is_auto_update_enabled' => true]); | ||||||
|                 } else { |                 } else { | ||||||
|                     $settings->update(['is_auto_update_enabled' => false]); |                     $settings->update(['is_auto_update_enabled' => false]); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         $this->cleanup_stucked_helper_containers(); |         $this->cleanup_stucked_helper_containers(); | ||||||
| @ -66,7 +69,7 @@ class Init extends Command | |||||||
|                 echo "Restoring coolify db backup\n"; |                 echo "Restoring coolify db backup\n"; | ||||||
|                 $database->restore(); |                 $database->restore(); | ||||||
|                 $scheduledBackup = ScheduledDatabaseBackup::find(0); |                 $scheduledBackup = ScheduledDatabaseBackup::find(0); | ||||||
|                 if (!$scheduledBackup) { |                 if (! $scheduledBackup) { | ||||||
|                     ScheduledDatabaseBackup::create([ |                     ScheduledDatabaseBackup::create([ | ||||||
|                         'id' => 0, |                         'id' => 0, | ||||||
|                         'enabled' => true, |                         'enabled' => true, | ||||||
| @ -82,6 +85,7 @@ class Init extends Command | |||||||
|             echo "Error in restoring coolify db backup: {$e->getMessage()}\n"; |             echo "Error in restoring coolify db backup: {$e->getMessage()}\n"; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function cleanup_stucked_helper_containers() |     private function cleanup_stucked_helper_containers() | ||||||
|     { |     { | ||||||
|         $servers = Server::all(); |         $servers = Server::all(); | ||||||
| @ -91,6 +95,7 @@ class Init extends Command | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function alive() |     private function alive() | ||||||
|     { |     { | ||||||
|         $id = config('app.id'); |         $id = config('app.id'); | ||||||
| @ -99,6 +104,7 @@ class Init extends Command | |||||||
|         $do_not_track = data_get($settings, 'do_not_track'); |         $do_not_track = data_get($settings, 'do_not_track'); | ||||||
|         if ($do_not_track == true) { |         if ($do_not_track == true) { | ||||||
|             echo "Skipping alive as do_not_track is enabled\n"; |             echo "Skipping alive as do_not_track is enabled\n"; | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         try { |         try { | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| namespace App\Console\Commands; | namespace App\Console\Commands; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
|  | 
 | ||||||
| use function Termwind\ask; | use function Termwind\ask; | ||||||
| use function Termwind\render; | use function Termwind\render; | ||||||
| use function Termwind\style; | use function Termwind\style; | ||||||
| @ -32,6 +33,7 @@ class NotifyDemo extends Command | |||||||
| 
 | 
 | ||||||
|         if (blank($channel)) { |         if (blank($channel)) { | ||||||
|             $this->showHelp(); |             $this->showHelp(); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -35,6 +35,7 @@ class RootChangeEmail extends Command | |||||||
|             $this->info('Root user\'s email updated successfully.'); |             $this->info('Root user\'s email updated successfully.'); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             $this->error('Failed to update root user\'s email.'); |             $this->error('Failed to update root user\'s email.'); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ class RootResetPassword extends Command | |||||||
|         $passwordAgain = password('Again'); |         $passwordAgain = password('Again'); | ||||||
|         if ($password != $passwordAgain) { |         if ($password != $passwordAgain) { | ||||||
|             $this->error('Passwords do not match.'); |             $this->error('Passwords do not match.'); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         $this->info('Updating root password...'); |         $this->info('Updating root password...'); | ||||||
| @ -42,6 +43,7 @@ class RootResetPassword extends Command | |||||||
|             $this->info('Root password updated successfully.'); |             $this->info('Root password updated successfully.'); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             $this->error('Failed to update root password.'); |             $this->error('Failed to update root password.'); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -7,7 +7,9 @@ use Illuminate\Console\Command; | |||||||
| class Scheduler extends Command | class Scheduler extends Command | ||||||
| { | { | ||||||
|     protected $signature = 'start:scheduler'; |     protected $signature = 'start:scheduler'; | ||||||
|  | 
 | ||||||
|     protected $description = 'Start Scheduler'; |     protected $description = 'Start Scheduler'; | ||||||
|  | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         if (config('coolify.is_scheduler_enabled')) { |         if (config('coolify.is_scheduler_enabled')) { | ||||||
|  | |||||||
| @ -48,11 +48,13 @@ class ServicesDelete extends Command | |||||||
|             $this->deleteServer(); |             $this->deleteServer(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function deleteServer() |     private function deleteServer() | ||||||
|     { |     { | ||||||
|         $servers = Server::all(); |         $servers = Server::all(); | ||||||
|         if ($servers->count() === 0) { |         if ($servers->count() === 0) { | ||||||
|             $this->error('There are no applications to delete.'); |             $this->error('There are no applications to delete.'); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         $serversToDelete = multiselect( |         $serversToDelete = multiselect( | ||||||
| @ -64,19 +66,21 @@ class ServicesDelete extends Command | |||||||
|             $toDelete = $servers->where('id', $server)->first(); |             $toDelete = $servers->where('id', $server)->first(); | ||||||
|             if ($toDelete) { |             if ($toDelete) { | ||||||
|                 $this->info($toDelete); |                 $this->info($toDelete); | ||||||
|                 $confirmed = confirm("Are you sure you want to delete all selected resources?"); |                 $confirmed = confirm('Are you sure you want to delete all selected resources?'); | ||||||
|                 if (!$confirmed) { |                 if (! $confirmed) { | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 $toDelete->delete(); |                 $toDelete->delete(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function deleteApplication() |     private function deleteApplication() | ||||||
|     { |     { | ||||||
|         $applications = Application::all(); |         $applications = Application::all(); | ||||||
|         if ($applications->count() === 0) { |         if ($applications->count() === 0) { | ||||||
|             $this->error('There are no applications to delete.'); |             $this->error('There are no applications to delete.'); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         $applicationsToDelete = multiselect( |         $applicationsToDelete = multiselect( | ||||||
| @ -88,19 +92,21 @@ class ServicesDelete extends Command | |||||||
|             $toDelete = $applications->where('id', $application)->first(); |             $toDelete = $applications->where('id', $application)->first(); | ||||||
|             if ($toDelete) { |             if ($toDelete) { | ||||||
|                 $this->info($toDelete); |                 $this->info($toDelete); | ||||||
|                 $confirmed = confirm("Are you sure you want to delete all selected resources? "); |                 $confirmed = confirm('Are you sure you want to delete all selected resources? '); | ||||||
|                 if (!$confirmed) { |                 if (! $confirmed) { | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 DeleteResourceJob::dispatch($toDelete); |                 DeleteResourceJob::dispatch($toDelete); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function deleteDatabase() |     private function deleteDatabase() | ||||||
|     { |     { | ||||||
|         $databases = StandalonePostgresql::all(); |         $databases = StandalonePostgresql::all(); | ||||||
|         if ($databases->count() === 0) { |         if ($databases->count() === 0) { | ||||||
|             $this->error('There are no databases to delete.'); |             $this->error('There are no databases to delete.'); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         $databasesToDelete = multiselect( |         $databasesToDelete = multiselect( | ||||||
| @ -112,19 +118,21 @@ class ServicesDelete extends Command | |||||||
|             $toDelete = $databases->where('id', $database)->first(); |             $toDelete = $databases->where('id', $database)->first(); | ||||||
|             if ($toDelete) { |             if ($toDelete) { | ||||||
|                 $this->info($toDelete); |                 $this->info($toDelete); | ||||||
|                 $confirmed = confirm("Are you sure you want to delete all selected resources?"); |                 $confirmed = confirm('Are you sure you want to delete all selected resources?'); | ||||||
|                 if (!$confirmed) { |                 if (! $confirmed) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 DeleteResourceJob::dispatch($toDelete); |                 DeleteResourceJob::dispatch($toDelete); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function deleteService() |     private function deleteService() | ||||||
|     { |     { | ||||||
|         $services = Service::all(); |         $services = Service::all(); | ||||||
|         if ($services->count() === 0) { |         if ($services->count() === 0) { | ||||||
|             $this->error('There are no services to delete.'); |             $this->error('There are no services to delete.'); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         $servicesToDelete = multiselect( |         $servicesToDelete = multiselect( | ||||||
| @ -136,8 +144,8 @@ class ServicesDelete extends Command | |||||||
|             $toDelete = $services->where('id', $service)->first(); |             $toDelete = $services->where('id', $service)->first(); | ||||||
|             if ($toDelete) { |             if ($toDelete) { | ||||||
|                 $this->info($toDelete); |                 $this->info($toDelete); | ||||||
|                 $confirmed = confirm("Are you sure you want to delete all selected resources?"); |                 $confirmed = confirm('Are you sure you want to delete all selected resources?'); | ||||||
|                 if (!$confirmed) { |                 if (! $confirmed) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 DeleteResourceJob::dispatch($toDelete); |                 DeleteResourceJob::dispatch($toDelete); | ||||||
|  | |||||||
| @ -50,12 +50,13 @@ class ServicesGenerate extends Command | |||||||
|         // $this->info($content);
 |         // $this->info($content);
 | ||||||
|         $ignore = collect(preg_grep('/^# ignore:/', explode("\n", $content)))->values(); |         $ignore = collect(preg_grep('/^# ignore:/', explode("\n", $content)))->values(); | ||||||
|         if ($ignore->count() > 0) { |         if ($ignore->count() > 0) { | ||||||
|             $ignore = (bool)str($ignore[0])->after('# ignore:')->trim()->value(); |             $ignore = (bool) str($ignore[0])->after('# ignore:')->trim()->value(); | ||||||
|         } else { |         } else { | ||||||
|             $ignore = false; |             $ignore = false; | ||||||
|         } |         } | ||||||
|         if ($ignore) { |         if ($ignore) { | ||||||
|             $this->info("Ignoring $file"); |             $this->info("Ignoring $file"); | ||||||
|  | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         $this->info("Processing $file"); |         $this->info("Processing $file"); | ||||||
| @ -125,6 +126,7 @@ class ServicesGenerate extends Command | |||||||
|             $env_file_base64 = base64_encode($env_file_content); |             $env_file_base64 = base64_encode($env_file_content); | ||||||
|             $payload['envs'] = $env_file_base64; |             $payload['envs'] = $env_file_base64; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $payload; |         return $payload; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -33,30 +33,31 @@ class SyncBunny extends Command | |||||||
|         $that = $this; |         $that = $this; | ||||||
|         $only_template = $this->option('templates'); |         $only_template = $this->option('templates'); | ||||||
|         $only_version = $this->option('release'); |         $only_version = $this->option('release'); | ||||||
|         $bunny_cdn = "https://cdn.coollabs.io"; |         $bunny_cdn = 'https://cdn.coollabs.io'; | ||||||
|         $bunny_cdn_path = "coolify"; |         $bunny_cdn_path = 'coolify'; | ||||||
|         $bunny_cdn_storage_name = "coolcdn"; |         $bunny_cdn_storage_name = 'coolcdn'; | ||||||
| 
 | 
 | ||||||
|         $parent_dir = realpath(dirname(__FILE__) . '/../../..'); |         $parent_dir = realpath(dirname(__FILE__).'/../../..'); | ||||||
| 
 | 
 | ||||||
|         $compose_file = "docker-compose.yml"; |         $compose_file = 'docker-compose.yml'; | ||||||
|         $compose_file_prod = "docker-compose.prod.yml"; |         $compose_file_prod = 'docker-compose.prod.yml'; | ||||||
|         $install_script = "install.sh"; |         $install_script = 'install.sh'; | ||||||
|         $upgrade_script = "upgrade.sh"; |         $upgrade_script = 'upgrade.sh'; | ||||||
|         $production_env = ".env.production"; |         $production_env = '.env.production'; | ||||||
|         $service_template = "service-templates.json"; |         $service_template = 'service-templates.json'; | ||||||
| 
 | 
 | ||||||
|         $versions = "versions.json"; |         $versions = 'versions.json'; | ||||||
| 
 | 
 | ||||||
|         PendingRequest::macro('storage', function ($fileName) use ($that) { |         PendingRequest::macro('storage', function ($fileName) use ($that) { | ||||||
|             $headers = [ |             $headers = [ | ||||||
|                 'AccessKey' => env('BUNNY_STORAGE_API_KEY'), |                 'AccessKey' => env('BUNNY_STORAGE_API_KEY'), | ||||||
|                 'Accept' => 'application/json', |                 'Accept' => 'application/json', | ||||||
|                 'Content-Type' => 'application/octet-stream' |                 'Content-Type' => 'application/octet-stream', | ||||||
|             ]; |             ]; | ||||||
|             $fileStream = fopen($fileName, "r"); |             $fileStream = fopen($fileName, 'r'); | ||||||
|             $file = fread($fileStream, filesize($fileName)); |             $file = fread($fileStream, filesize($fileName)); | ||||||
|             $that->info('Uploading: ' . $fileName); |             $that->info('Uploading: '.$fileName); | ||||||
|  | 
 | ||||||
|             return PendingRequest::baseUrl('https://storage.bunnycdn.com')->withHeaders($headers)->withBody($file)->throw(); |             return PendingRequest::baseUrl('https://storage.bunnycdn.com')->withHeaders($headers)->withBody($file)->throw(); | ||||||
|         }); |         }); | ||||||
|         PendingRequest::macro('purge', function ($url) use ($that) { |         PendingRequest::macro('purge', function ($url) use ($that) { | ||||||
| @ -64,20 +65,21 @@ class SyncBunny extends Command | |||||||
|                 'AccessKey' => env('BUNNY_API_KEY'), |                 'AccessKey' => env('BUNNY_API_KEY'), | ||||||
|                 'Accept' => 'application/json', |                 'Accept' => 'application/json', | ||||||
|             ]; |             ]; | ||||||
|             $that->info('Purging: ' . $url); |             $that->info('Purging: '.$url); | ||||||
|  | 
 | ||||||
|             return PendingRequest::withHeaders($headers)->get('https://api.bunny.net/purge', [ |             return PendingRequest::withHeaders($headers)->get('https://api.bunny.net/purge', [ | ||||||
|                 "url" => $url, |                 'url' => $url, | ||||||
|                 "async" => false |                 'async' => false, | ||||||
|             ]); |             ]); | ||||||
|         }); |         }); | ||||||
|         try { |         try { | ||||||
|             if (!$only_template && !$only_version) { |             if (! $only_template && ! $only_version) { | ||||||
|                 $this->info('About to sync files (docker-compose.prod.yaml, upgrade.sh, install.sh, etc) to BunnyCDN.'); |                 $this->info('About to sync files (docker-compose.prod.yaml, upgrade.sh, install.sh, etc) to BunnyCDN.'); | ||||||
|             } |             } | ||||||
|             if ($only_template) { |             if ($only_template) { | ||||||
|                 $this->info('About to sync service-templates.json to BunnyCDN.'); |                 $this->info('About to sync service-templates.json to BunnyCDN.'); | ||||||
|                 $confirmed = confirm("Are you sure you want to sync?"); |                 $confirmed = confirm('Are you sure you want to sync?'); | ||||||
|                 if (!$confirmed) { |                 if (! $confirmed) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 Http::pool(fn (Pool $pool) => [ |                 Http::pool(fn (Pool $pool) => [ | ||||||
| @ -85,15 +87,16 @@ class SyncBunny extends Command | |||||||
|                     $pool->purge("$bunny_cdn/$bunny_cdn_path/$service_template"), |                     $pool->purge("$bunny_cdn/$bunny_cdn_path/$service_template"), | ||||||
|                 ]); |                 ]); | ||||||
|                 $this->info('Service template uploaded & purged...'); |                 $this->info('Service template uploaded & purged...'); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } else if ($only_version) { |             } elseif ($only_version) { | ||||||
|                 $this->info('About to sync versions.json to BunnyCDN.'); |                 $this->info('About to sync versions.json to BunnyCDN.'); | ||||||
|                 $file = file_get_contents("$parent_dir/$versions"); |                 $file = file_get_contents("$parent_dir/$versions"); | ||||||
|                 $json = json_decode($file, true); |                 $json = json_decode($file, true); | ||||||
|                 $actual_version = data_get($json, 'coolify.v4.version'); |                 $actual_version = data_get($json, 'coolify.v4.version'); | ||||||
| 
 | 
 | ||||||
|                 $confirmed = confirm("Are you sure you want to sync to {$actual_version}?"); |                 $confirmed = confirm("Are you sure you want to sync to {$actual_version}?"); | ||||||
|                 if (!$confirmed) { |                 if (! $confirmed) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 Http::pool(fn (Pool $pool) => [ |                 Http::pool(fn (Pool $pool) => [ | ||||||
| @ -101,10 +104,10 @@ class SyncBunny extends Command | |||||||
|                     $pool->purge("$bunny_cdn/$bunny_cdn_path/$versions"), |                     $pool->purge("$bunny_cdn/$bunny_cdn_path/$versions"), | ||||||
|                 ]); |                 ]); | ||||||
|                 $this->info('versions.json uploaded & purged...'); |                 $this->info('versions.json uploaded & purged...'); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|             Http::pool(fn (Pool $pool) => [ |             Http::pool(fn (Pool $pool) => [ | ||||||
|                 $pool->storage(fileName: "$parent_dir/$compose_file")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file"), |                 $pool->storage(fileName: "$parent_dir/$compose_file")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file"), | ||||||
|                 $pool->storage(fileName: "$parent_dir/$compose_file_prod")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file_prod"), |                 $pool->storage(fileName: "$parent_dir/$compose_file_prod")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file_prod"), | ||||||
| @ -119,9 +122,9 @@ class SyncBunny extends Command | |||||||
|                 $pool->purge("$bunny_cdn/$bunny_cdn_path/$upgrade_script"), |                 $pool->purge("$bunny_cdn/$bunny_cdn_path/$upgrade_script"), | ||||||
|                 $pool->purge("$bunny_cdn/$bunny_cdn_path/$install_script"), |                 $pool->purge("$bunny_cdn/$bunny_cdn_path/$install_script"), | ||||||
|             ]); |             ]); | ||||||
|             $this->info("All files uploaded & purged..."); |             $this->info('All files uploaded & purged...'); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             $this->error("Error: " . $e->getMessage()); |             $this->error('Error: '.$e->getMessage()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,7 +13,9 @@ use Illuminate\Support\Str; | |||||||
| class WaitlistInvite extends Command | class WaitlistInvite extends Command | ||||||
| { | { | ||||||
|     public Waitlist|User|null $next_patient = null; |     public Waitlist|User|null $next_patient = null; | ||||||
|     public string|null $password = null; | 
 | ||||||
|  |     public ?string $password = null; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * The name and signature of the console command. |      * The name and signature of the console command. | ||||||
|      * |      * | ||||||
| @ -38,7 +40,9 @@ class WaitlistInvite extends Command | |||||||
|             $this->main(); |             $this->main(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     private function main() { | 
 | ||||||
|  |     private function main() | ||||||
|  |     { | ||||||
|         if ($this->argument('email')) { |         if ($this->argument('email')) { | ||||||
|             if ($this->option('only-email')) { |             if ($this->option('only-email')) { | ||||||
|                 $this->next_patient = User::whereEmail($this->argument('email'))->first(); |                 $this->next_patient = User::whereEmail($this->argument('email'))->first(); | ||||||
| @ -50,8 +54,9 @@ class WaitlistInvite extends Command | |||||||
|             } else { |             } else { | ||||||
|                 $this->next_patient = Waitlist::where('email', $this->argument('email'))->first(); |                 $this->next_patient = Waitlist::where('email', $this->argument('email'))->first(); | ||||||
|             } |             } | ||||||
|             if (!$this->next_patient) { |             if (! $this->next_patient) { | ||||||
|                 $this->error("{$this->argument('email')} not found in the waitlist."); |                 $this->error("{$this->argument('email')} not found in the waitlist."); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
| @ -60,6 +65,7 @@ class WaitlistInvite extends Command | |||||||
|         if ($this->next_patient) { |         if ($this->next_patient) { | ||||||
|             if ($this->option('only-email')) { |             if ($this->option('only-email')) { | ||||||
|                 $this->send_email(); |                 $this->send_email(); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $this->register_user(); |             $this->register_user(); | ||||||
| @ -69,10 +75,11 @@ class WaitlistInvite extends Command | |||||||
|             $this->info('No verified user found in the waitlist. 👀'); |             $this->info('No verified user found in the waitlist. 👀'); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function register_user() |     private function register_user() | ||||||
|     { |     { | ||||||
|         $already_registered = User::whereEmail($this->next_patient->email)->first(); |         $already_registered = User::whereEmail($this->next_patient->email)->first(); | ||||||
|         if (!$already_registered) { |         if (! $already_registered) { | ||||||
|             $this->password = Str::password(); |             $this->password = Str::password(); | ||||||
|             User::create([ |             User::create([ | ||||||
|                 'name' => Str::of($this->next_patient->email)->before('@'), |                 'name' => Str::of($this->next_patient->email)->before('@'), | ||||||
| @ -85,11 +92,13 @@ class WaitlistInvite extends Command | |||||||
|             throw new \Exception('User already registered'); |             throw new \Exception('User already registered'); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function remove_from_waitlist() |     private function remove_from_waitlist() | ||||||
|     { |     { | ||||||
|         $this->next_patient->delete(); |         $this->next_patient->delete(); | ||||||
|         $this->info("User removed from waitlist successfully."); |         $this->info('User removed from waitlist successfully.'); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function send_email() |     private function send_email() | ||||||
|     { |     { | ||||||
|         $token = Crypt::encryptString("{$this->next_patient->email}@@@$this->password"); |         $token = Crypt::encryptString("{$this->next_patient->email}@@@$this->password"); | ||||||
| @ -100,6 +109,6 @@ class WaitlistInvite extends Command | |||||||
|         ]); |         ]); | ||||||
|         $mail->subject('Congratulations! You are invited to join Coolify Cloud.'); |         $mail->subject('Congratulations! You are invited to join Coolify Cloud.'); | ||||||
|         send_user_an_email($mail, $this->next_patient->email); |         send_user_an_email($mail, $this->next_patient->email); | ||||||
|         $this->info("Email sent successfully. 📧"); |         $this->info('Email sent successfully. 📧'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,13 +4,13 @@ namespace App\Console; | |||||||
| 
 | 
 | ||||||
| use App\Jobs\CheckLogDrainContainerJob; | use App\Jobs\CheckLogDrainContainerJob; | ||||||
| use App\Jobs\CleanupInstanceStuffsJob; | use App\Jobs\CleanupInstanceStuffsJob; | ||||||
| use App\Jobs\DatabaseBackupJob; |  | ||||||
| use App\Jobs\ScheduledTaskJob; |  | ||||||
| use App\Jobs\ContainerStatusJob; | use App\Jobs\ContainerStatusJob; | ||||||
|  | use App\Jobs\DatabaseBackupJob; | ||||||
| use App\Jobs\PullCoolifyImageJob; | use App\Jobs\PullCoolifyImageJob; | ||||||
| use App\Jobs\PullHelperImageJob; | use App\Jobs\PullHelperImageJob; | ||||||
| use App\Jobs\PullSentinelImageJob; | use App\Jobs\PullSentinelImageJob; | ||||||
| use App\Jobs\PullTemplatesFromCDN; | use App\Jobs\PullTemplatesFromCDN; | ||||||
|  | use App\Jobs\ScheduledTaskJob; | ||||||
| use App\Jobs\ServerStatusJob; | use App\Jobs\ServerStatusJob; | ||||||
| use App\Models\ScheduledDatabaseBackup; | use App\Models\ScheduledDatabaseBackup; | ||||||
| use App\Models\ScheduledTask; | use App\Models\ScheduledTask; | ||||||
| @ -22,6 +22,7 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel; | |||||||
| class Kernel extends ConsoleKernel | class Kernel extends ConsoleKernel | ||||||
| { | { | ||||||
|     private $all_servers; |     private $all_servers; | ||||||
|  | 
 | ||||||
|     protected function schedule(Schedule $schedule): void |     protected function schedule(Schedule $schedule): void | ||||||
|     { |     { | ||||||
|         $this->all_servers = Server::all(); |         $this->all_servers = Server::all(); | ||||||
| @ -55,6 +56,7 @@ class Kernel extends ConsoleKernel | |||||||
|             $schedule->command('uploads:clear')->everyTwoMinutes(); |             $schedule->command('uploads:clear')->everyTwoMinutes(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function pull_images($schedule) |     private function pull_images($schedule) | ||||||
|     { |     { | ||||||
|         $servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4'); |         $servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4'); | ||||||
| @ -65,6 +67,7 @@ class Kernel extends ConsoleKernel | |||||||
|             $schedule->job(new PullHelperImageJob($server))->everyFiveMinutes()->onOneServer(); |             $schedule->job(new PullHelperImageJob($server))->everyFiveMinutes()->onOneServer(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function check_resources($schedule) |     private function check_resources($schedule) | ||||||
|     { |     { | ||||||
|         if (isCloud()) { |         if (isCloud()) { | ||||||
| @ -86,6 +89,7 @@ class Kernel extends ConsoleKernel | |||||||
|             $schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer(); |             $schedule->job(new ServerStatusJob($server))->everyMinute()->onOneServer(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function check_scheduled_backups($schedule) |     private function check_scheduled_backups($schedule) | ||||||
|     { |     { | ||||||
|         $scheduled_backups = ScheduledDatabaseBackup::all(); |         $scheduled_backups = ScheduledDatabaseBackup::all(); | ||||||
| @ -93,12 +97,13 @@ class Kernel extends ConsoleKernel | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         foreach ($scheduled_backups as $scheduled_backup) { |         foreach ($scheduled_backups as $scheduled_backup) { | ||||||
|             if (!$scheduled_backup->enabled) { |             if (! $scheduled_backup->enabled) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             if (is_null(data_get($scheduled_backup, 'database'))) { |             if (is_null(data_get($scheduled_backup, 'database'))) { | ||||||
|                 ray('database not found'); |                 ray('database not found'); | ||||||
|                 $scheduled_backup->delete(); |                 $scheduled_backup->delete(); | ||||||
|  | 
 | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -124,9 +129,10 @@ class Kernel extends ConsoleKernel | |||||||
|             $service = $scheduled_task->service; |             $service = $scheduled_task->service; | ||||||
|             $application = $scheduled_task->application; |             $application = $scheduled_task->application; | ||||||
| 
 | 
 | ||||||
|             if (!$application && !$service) { |             if (! $application && ! $service) { | ||||||
|                 ray('application/service attached to scheduled task does not exist'); |                 ray('application/service attached to scheduled task does not exist'); | ||||||
|                 $scheduled_task->delete(); |                 $scheduled_task->delete(); | ||||||
|  | 
 | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             if ($application) { |             if ($application) { | ||||||
| @ -150,7 +156,7 @@ class Kernel extends ConsoleKernel | |||||||
| 
 | 
 | ||||||
|     protected function commands(): void |     protected function commands(): void | ||||||
|     { |     { | ||||||
|         $this->load(__DIR__ . '/Commands'); |         $this->load(__DIR__.'/Commands'); | ||||||
| 
 | 
 | ||||||
|         require base_path('routes/console.php'); |         require base_path('routes/console.php'); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -12,18 +12,18 @@ use Spatie\LaravelData\Data; | |||||||
| class CoolifyTaskArgs extends Data | class CoolifyTaskArgs extends Data | ||||||
| { | { | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         public string  $server_uuid, |         public string $server_uuid, | ||||||
|         public string  $command, |         public string $command, | ||||||
|         public string  $type, |         public string $type, | ||||||
|         public ?string $type_uuid = null, |         public ?string $type_uuid = null, | ||||||
|         public ?int $process_id = null, |         public ?int $process_id = null, | ||||||
|         public ?Model  $model = null, |         public ?Model $model = null, | ||||||
|         public ?string  $status = null , |         public ?string $status = null, | ||||||
|         public bool    $ignore_errors = false, |         public bool $ignore_errors = false, | ||||||
|         public $call_event_on_finish = null, |         public $call_event_on_finish = null, | ||||||
|         public $call_event_data = null |         public $call_event_data = null | ||||||
|     ) { |     ) { | ||||||
|         if(is_null($status)){ |         if (is_null($status)) { | ||||||
|             $this->status = ProcessStatus::QUEUED->value; |             $this->status = ProcessStatus::QUEUED->value; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ use Spatie\LaravelData\Data; | |||||||
| class ServerMetadata extends Data | class ServerMetadata extends Data | ||||||
| { | { | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         public ?ProxyTypes  $type, |         public ?ProxyTypes $type, | ||||||
|         public ?ProxyStatus $status |         public ?ProxyStatus $status | ||||||
|     ) { |     ) { | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,9 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Events; | namespace App\Events; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Broadcasting\Channel; |  | ||||||
| use Illuminate\Broadcasting\InteractsWithSockets; | use Illuminate\Broadcasting\InteractsWithSockets; | ||||||
| use Illuminate\Broadcasting\PresenceChannel; |  | ||||||
| use Illuminate\Broadcasting\PrivateChannel; | use Illuminate\Broadcasting\PrivateChannel; | ||||||
| use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | ||||||
| use Illuminate\Foundation\Events\Dispatchable; | use Illuminate\Foundation\Events\Dispatchable; | ||||||
| @ -13,14 +11,16 @@ use Illuminate\Queue\SerializesModels; | |||||||
| class ApplicationStatusChanged implements ShouldBroadcast | class ApplicationStatusChanged implements ShouldBroadcast | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithSockets, SerializesModels; |     use Dispatchable, InteractsWithSockets, SerializesModels; | ||||||
|  | 
 | ||||||
|     public $teamId; |     public $teamId; | ||||||
|  | 
 | ||||||
|     public function __construct($teamId = null) |     public function __construct($teamId = null) | ||||||
|     { |     { | ||||||
|         if (is_null($teamId)) { |         if (is_null($teamId)) { | ||||||
|             $teamId = auth()->user()->currentTeam()->id ?? null; |             $teamId = auth()->user()->currentTeam()->id ?? null; | ||||||
|         } |         } | ||||||
|         if (is_null($teamId)) { |         if (is_null($teamId)) { | ||||||
|             throw new \Exception("Team id is null"); |             throw new \Exception('Team id is null'); | ||||||
|         } |         } | ||||||
|         $this->teamId = $teamId; |         $this->teamId = $teamId; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,9 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Events; | namespace App\Events; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Broadcasting\Channel; |  | ||||||
| use Illuminate\Broadcasting\InteractsWithSockets; | use Illuminate\Broadcasting\InteractsWithSockets; | ||||||
| use Illuminate\Broadcasting\PresenceChannel; |  | ||||||
| use Illuminate\Broadcasting\PrivateChannel; | use Illuminate\Broadcasting\PrivateChannel; | ||||||
| use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | ||||||
| use Illuminate\Foundation\Events\Dispatchable; | use Illuminate\Foundation\Events\Dispatchable; | ||||||
| @ -13,14 +11,16 @@ use Illuminate\Queue\SerializesModels; | |||||||
| class BackupCreated implements ShouldBroadcast | class BackupCreated implements ShouldBroadcast | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithSockets, SerializesModels; |     use Dispatchable, InteractsWithSockets, SerializesModels; | ||||||
|  | 
 | ||||||
|     public $teamId; |     public $teamId; | ||||||
|  | 
 | ||||||
|     public function __construct($teamId = null) |     public function __construct($teamId = null) | ||||||
|     { |     { | ||||||
|         if (is_null($teamId)) { |         if (is_null($teamId)) { | ||||||
|             $teamId = auth()->user()->currentTeam()->id ?? null; |             $teamId = auth()->user()->currentTeam()->id ?? null; | ||||||
|         } |         } | ||||||
|         if (is_null($teamId)) { |         if (is_null($teamId)) { | ||||||
|             throw new \Exception("Team id is null"); |             throw new \Exception('Team id is null'); | ||||||
|         } |         } | ||||||
|         $this->teamId = $teamId; |         $this->teamId = $teamId; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,9 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Events; | namespace App\Events; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Broadcasting\Channel; |  | ||||||
| use Illuminate\Broadcasting\InteractsWithSockets; | use Illuminate\Broadcasting\InteractsWithSockets; | ||||||
| use Illuminate\Broadcasting\PresenceChannel; |  | ||||||
| use Illuminate\Broadcasting\PrivateChannel; | use Illuminate\Broadcasting\PrivateChannel; | ||||||
| use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | ||||||
| use Illuminate\Foundation\Events\Dispatchable; | use Illuminate\Foundation\Events\Dispatchable; | ||||||
| @ -13,14 +11,16 @@ use Illuminate\Queue\SerializesModels; | |||||||
| class DatabaseStatusChanged implements ShouldBroadcast | class DatabaseStatusChanged implements ShouldBroadcast | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithSockets, SerializesModels; |     use Dispatchable, InteractsWithSockets, SerializesModels; | ||||||
|  | 
 | ||||||
|     public $userId; |     public $userId; | ||||||
|  | 
 | ||||||
|     public function __construct($userId = null) |     public function __construct($userId = null) | ||||||
|     { |     { | ||||||
|         if (is_null($userId)) { |         if (is_null($userId)) { | ||||||
|             $userId = auth()->user()->id ?? null; |             $userId = auth()->user()->id ?? null; | ||||||
|         } |         } | ||||||
|         if (is_null($userId)) { |         if (is_null($userId)) { | ||||||
|             throw new \Exception("User id is null"); |             throw new \Exception('User id is null'); | ||||||
|         } |         } | ||||||
|         $this->userId = $userId; |         $this->userId = $userId; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ use Illuminate\Queue\SerializesModels; | |||||||
| class ProxyStarted | class ProxyStarted | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithSockets, SerializesModels; |     use Dispatchable, InteractsWithSockets, SerializesModels; | ||||||
|  | 
 | ||||||
|     public function __construct(public $data) |     public function __construct(public $data) | ||||||
|     { |     { | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,9 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Events; | namespace App\Events; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Broadcasting\Channel; |  | ||||||
| use Illuminate\Broadcasting\InteractsWithSockets; | use Illuminate\Broadcasting\InteractsWithSockets; | ||||||
| use Illuminate\Broadcasting\PresenceChannel; |  | ||||||
| use Illuminate\Broadcasting\PrivateChannel; | use Illuminate\Broadcasting\PrivateChannel; | ||||||
| use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | ||||||
| use Illuminate\Foundation\Events\Dispatchable; | use Illuminate\Foundation\Events\Dispatchable; | ||||||
| @ -13,14 +11,16 @@ use Illuminate\Queue\SerializesModels; | |||||||
| class ProxyStatusChanged implements ShouldBroadcast | class ProxyStatusChanged implements ShouldBroadcast | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithSockets, SerializesModels; |     use Dispatchable, InteractsWithSockets, SerializesModels; | ||||||
|  | 
 | ||||||
|     public $teamId; |     public $teamId; | ||||||
|  | 
 | ||||||
|     public function __construct($teamId = null) |     public function __construct($teamId = null) | ||||||
|     { |     { | ||||||
|         if (is_null($teamId)) { |         if (is_null($teamId)) { | ||||||
|             $teamId = auth()->user()->currentTeam()->id ?? null; |             $teamId = auth()->user()->currentTeam()->id ?? null; | ||||||
|         } |         } | ||||||
|         if (is_null($teamId)) { |         if (is_null($teamId)) { | ||||||
|             throw new \Exception("Team id is null"); |             throw new \Exception('Team id is null'); | ||||||
|         } |         } | ||||||
|         $this->teamId = $teamId; |         $this->teamId = $teamId; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,9 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Events; | namespace App\Events; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Broadcasting\Channel; |  | ||||||
| use Illuminate\Broadcasting\InteractsWithSockets; | use Illuminate\Broadcasting\InteractsWithSockets; | ||||||
| use Illuminate\Broadcasting\PresenceChannel; |  | ||||||
| use Illuminate\Broadcasting\PrivateChannel; | use Illuminate\Broadcasting\PrivateChannel; | ||||||
| use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | ||||||
| use Illuminate\Foundation\Events\Dispatchable; | use Illuminate\Foundation\Events\Dispatchable; | ||||||
| @ -13,14 +11,16 @@ use Illuminate\Queue\SerializesModels; | |||||||
| class ServiceStatusChanged implements ShouldBroadcast | class ServiceStatusChanged implements ShouldBroadcast | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithSockets, SerializesModels; |     use Dispatchable, InteractsWithSockets, SerializesModels; | ||||||
|  | 
 | ||||||
|     public $userId; |     public $userId; | ||||||
|  | 
 | ||||||
|     public function __construct($userId = null) |     public function __construct($userId = null) | ||||||
|     { |     { | ||||||
|         if (is_null($userId)) { |         if (is_null($userId)) { | ||||||
|             $userId = auth()->user()->id ?? null; |             $userId = auth()->user()->id ?? null; | ||||||
|         } |         } | ||||||
|         if (is_null($userId)) { |         if (is_null($userId)) { | ||||||
|             throw new \Exception("User id is null"); |             throw new \Exception('User id is null'); | ||||||
|         } |         } | ||||||
|         $this->userId = $userId; |         $this->userId = $userId; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,9 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Events; | namespace App\Events; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Broadcasting\Channel; |  | ||||||
| use Illuminate\Broadcasting\InteractsWithSockets; | use Illuminate\Broadcasting\InteractsWithSockets; | ||||||
| use Illuminate\Broadcasting\PresenceChannel; |  | ||||||
| use Illuminate\Broadcasting\PrivateChannel; | use Illuminate\Broadcasting\PrivateChannel; | ||||||
| use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | use Illuminate\Contracts\Broadcasting\ShouldBroadcast; | ||||||
| use Illuminate\Foundation\Events\Dispatchable; | use Illuminate\Foundation\Events\Dispatchable; | ||||||
| @ -13,7 +11,9 @@ use Illuminate\Queue\SerializesModels; | |||||||
| class TestEvent implements ShouldBroadcast | class TestEvent implements ShouldBroadcast | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithSockets, SerializesModels; |     use Dispatchable, InteractsWithSockets, SerializesModels; | ||||||
|  | 
 | ||||||
|     public $teamId; |     public $teamId; | ||||||
|  | 
 | ||||||
|     public function __construct() |     public function __construct() | ||||||
|     { |     { | ||||||
|         $this->teamId = auth()->user()->currentTeam()->id; |         $this->teamId = auth()->user()->currentTeam()->id; | ||||||
|  | |||||||
| @ -13,7 +13,6 @@ use Throwable; | |||||||
| 
 | 
 | ||||||
| class Handler extends ExceptionHandler | class Handler extends ExceptionHandler | ||||||
| { | { | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * A list of exception types with their corresponding custom log levels. |      * A list of exception types with their corresponding custom log levels. | ||||||
|      * |      * | ||||||
| @ -22,14 +21,16 @@ class Handler extends ExceptionHandler | |||||||
|     protected $levels = [ |     protected $levels = [ | ||||||
|         //
 |         //
 | ||||||
|     ]; |     ]; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * A list of the exception types that are not reported. |      * A list of the exception types that are not reported. | ||||||
|      * |      * | ||||||
|      * @var array<int, class-string<\Throwable>> |      * @var array<int, class-string<\Throwable>> | ||||||
|      */ |      */ | ||||||
|     protected $dontReport = [ |     protected $dontReport = [ | ||||||
|         ProcessException::class |         ProcessException::class, | ||||||
|     ]; |     ]; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * A list of the inputs that are never flashed to the session on validation exceptions. |      * A list of the inputs that are never flashed to the session on validation exceptions. | ||||||
|      * |      * | ||||||
| @ -40,6 +41,7 @@ class Handler extends ExceptionHandler | |||||||
|         'password', |         'password', | ||||||
|         'password_confirmation', |         'password_confirmation', | ||||||
|     ]; |     ]; | ||||||
|  | 
 | ||||||
|     private InstanceSettings $settings; |     private InstanceSettings $settings; | ||||||
| 
 | 
 | ||||||
|     protected function unauthenticated($request, AuthenticationException $exception) |     protected function unauthenticated($request, AuthenticationException $exception) | ||||||
| @ -47,8 +49,10 @@ class Handler extends ExceptionHandler | |||||||
|         if ($request->is('api/*') || $request->expectsJson() || $this->shouldReturnJson($request, $exception)) { |         if ($request->is('api/*') || $request->expectsJson() || $this->shouldReturnJson($request, $exception)) { | ||||||
|             return response()->json(['message' => $exception->getMessage()], 401); |             return response()->json(['message' => $exception->getMessage()], 401); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return redirect()->guest($exception->redirectTo() ?? route('login')); |         return redirect()->guest($exception->redirectTo() ?? route('login')); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Register the exception handling callbacks for the application. |      * Register the exception handling callbacks for the application. | ||||||
|      */ |      */ | ||||||
| @ -72,7 +76,7 @@ class Handler extends ExceptionHandler | |||||||
|                     $scope->setUser( |                     $scope->setUser( | ||||||
|                         [ |                         [ | ||||||
|                             'email' => $email, |                             'email' => $email, | ||||||
|                             'instanceAdmin' => $instanceAdmin |                             'instanceAdmin' => $instanceAdmin, | ||||||
|                         ] |                         ] | ||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -6,5 +6,4 @@ use Exception; | |||||||
| 
 | 
 | ||||||
| class ProcessException extends Exception | class ProcessException extends Exception | ||||||
| { | { | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -27,18 +27,20 @@ class Deploy extends Controller | |||||||
|             return invalid_token(); |             return invalid_token(); | ||||||
|         } |         } | ||||||
|         $servers = Server::whereTeamId($teamId)->get(); |         $servers = Server::whereTeamId($teamId)->get(); | ||||||
|         $deployments_per_server = ApplicationDeploymentQueue::whereIn("status", ["in_progress", "queued"])->whereIn("server_id", $servers->pluck("id"))->get([ |         $deployments_per_server = ApplicationDeploymentQueue::whereIn('status', ['in_progress', 'queued'])->whereIn('server_id', $servers->pluck('id'))->get([ | ||||||
|             "id", |             'id', | ||||||
|             "application_id", |             'application_id', | ||||||
|             "application_name", |             'application_name', | ||||||
|             "deployment_url", |             'deployment_url', | ||||||
|             "pull_request_id", |             'pull_request_id', | ||||||
|             "server_name", |             'server_name', | ||||||
|             "server_id", |             'server_id', | ||||||
|             "status" |             'status', | ||||||
|         ])->sortBy('id')->toArray(); |         ])->sortBy('id')->toArray(); | ||||||
|  | 
 | ||||||
|         return response()->json($deployments_per_server, 200); |         return response()->json($deployments_per_server, 200); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function deploy(Request $request) |     public function deploy(Request $request) | ||||||
|     { |     { | ||||||
|         $teamId = get_team_id_from_token(); |         $teamId = get_team_id_from_token(); | ||||||
| @ -54,11 +56,13 @@ class Deploy extends Controller | |||||||
|         } |         } | ||||||
|         if ($tags) { |         if ($tags) { | ||||||
|             return $this->by_tags($tags, $teamId, $force); |             return $this->by_tags($tags, $teamId, $force); | ||||||
|         } else if ($uuids) { |         } elseif ($uuids) { | ||||||
|             return $this->by_uuids($uuids, $teamId, $force); |             return $this->by_uuids($uuids, $teamId, $force); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return response()->json(['error' => 'You must provide uuid or tag.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400); |         return response()->json(['error' => 'You must provide uuid or tag.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 400); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function by_uuids(string $uuid, int $teamId, bool $force = false) |     private function by_uuids(string $uuid, int $teamId, bool $force = false) | ||||||
|     { |     { | ||||||
|         $uuids = explode(',', $uuid); |         $uuids = explode(',', $uuid); | ||||||
| @ -82,10 +86,13 @@ class Deploy extends Controller | |||||||
|         } |         } | ||||||
|         if ($deployments->count() > 0) { |         if ($deployments->count() > 0) { | ||||||
|             $payload->put('deployments', $deployments->toArray()); |             $payload->put('deployments', $deployments->toArray()); | ||||||
|  | 
 | ||||||
|             return response()->json($payload->toArray(), 200); |             return response()->json($payload->toArray(), 200); | ||||||
|         } |         } | ||||||
|         return response()->json(['error' => "No resources found.", 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404); | 
 | ||||||
|  |         return response()->json(['error' => 'No resources found.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function by_tags(string $tags, int $team_id, bool $force = false) |     public function by_tags(string $tags, int $team_id, bool $force = false) | ||||||
|     { |     { | ||||||
|         $tags = explode(',', $tags); |         $tags = explode(',', $tags); | ||||||
| @ -99,7 +106,7 @@ class Deploy extends Controller | |||||||
|         $payload = collect(); |         $payload = collect(); | ||||||
|         foreach ($tags as $tag) { |         foreach ($tags as $tag) { | ||||||
|             $found_tag = Tag::where(['name' => $tag, 'team_id' => $team_id])->first(); |             $found_tag = Tag::where(['name' => $tag, 'team_id' => $team_id])->first(); | ||||||
|             if (!$found_tag) { |             if (! $found_tag) { | ||||||
|                 // $message->push("Tag {$tag} not found.");
 |                 // $message->push("Tag {$tag} not found.");
 | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| @ -107,6 +114,7 @@ class Deploy extends Controller | |||||||
|             $services = $found_tag->services()->get(); |             $services = $found_tag->services()->get(); | ||||||
|             if ($applications->count() === 0 && $services->count() === 0) { |             if ($applications->count() === 0 && $services->count() === 0) { | ||||||
|                 $message->push("No resources found for tag {$tag}."); |                 $message->push("No resources found for tag {$tag}."); | ||||||
|  | 
 | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             foreach ($applications as $resource) { |             foreach ($applications as $resource) { | ||||||
| @ -127,11 +135,13 @@ class Deploy extends Controller | |||||||
|             if ($deployments->count() > 0) { |             if ($deployments->count() > 0) { | ||||||
|                 $payload->put('details', $deployments->toArray()); |                 $payload->put('details', $deployments->toArray()); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return response()->json($payload->toArray(), 200); |             return response()->json($payload->toArray(), 200); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return response()->json(['error' => "No resources found with this tag.", 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404); |         return response()->json(['error' => 'No resources found with this tag.', 'docs' => 'https://coolify.io/docs/api-reference/deploy-webhook'], 404); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function deploy_resource($resource, bool $force = false): array |     public function deploy_resource($resource, bool $force = false): array | ||||||
|     { |     { | ||||||
|         $message = null; |         $message = null; | ||||||
| @ -148,58 +158,59 @@ class Deploy extends Controller | |||||||
|                 force_rebuild: $force, |                 force_rebuild: $force, | ||||||
|             ); |             ); | ||||||
|             $message = "Application {$resource->name} deployment queued."; |             $message = "Application {$resource->name} deployment queued."; | ||||||
|         } else if ($type === 'App\Models\StandalonePostgresql') { |         } elseif ($type === 'App\Models\StandalonePostgresql') { | ||||||
|             StartPostgresql::run($resource); |             StartPostgresql::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\StandaloneRedis') { |         } elseif ($type === 'App\Models\StandaloneRedis') { | ||||||
|             StartRedis::run($resource); |             StartRedis::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\StandaloneKeydb') { |         } elseif ($type === 'App\Models\StandaloneKeydb') { | ||||||
|             StartKeydb::run($resource); |             StartKeydb::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\StandaloneDragonfly') { |         } elseif ($type === 'App\Models\StandaloneDragonfly') { | ||||||
|             StartDragonfly::run($resource); |             StartDragonfly::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\StandaloneClickhouse') { |         } elseif ($type === 'App\Models\StandaloneClickhouse') { | ||||||
|             StartClickhouse::run($resource); |             StartClickhouse::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\StandaloneMongodb') { |         } elseif ($type === 'App\Models\StandaloneMongodb') { | ||||||
|             StartMongodb::run($resource); |             StartMongodb::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\StandaloneMysql') { |         } elseif ($type === 'App\Models\StandaloneMysql') { | ||||||
|             StartMysql::run($resource); |             StartMysql::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\StandaloneMariadb') { |         } elseif ($type === 'App\Models\StandaloneMariadb') { | ||||||
|             StartMariadb::run($resource); |             StartMariadb::run($resource); | ||||||
|             $resource->update([ |             $resource->update([ | ||||||
|                 'started_at' => now(), |                 'started_at' => now(), | ||||||
|             ]); |             ]); | ||||||
|             $message = "Database {$resource->name} started."; |             $message = "Database {$resource->name} started."; | ||||||
|         } else if ($type === 'App\Models\Service') { |         } elseif ($type === 'App\Models\Service') { | ||||||
|             StartService::run($resource); |             StartService::run($resource); | ||||||
|             $message = "Service {$resource->name} started. It could take a while, be patient."; |             $message = "Service {$resource->name} started. It could take a while, be patient."; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return ['message' => $message, 'deployment_uuid' => $deployment_uuid]; |         return ['message' => $message, 'deployment_uuid' => $deployment_uuid]; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ class Domains extends Controller | |||||||
|                             'ip' => $settings->public_ipv6, |                             'ip' => $settings->public_ipv6, | ||||||
|                         ]); |                         ]); | ||||||
|                     } |                     } | ||||||
|                     if (!$settings->public_ipv4 && !$settings->public_ipv6) { |                     if (! $settings->public_ipv4 && ! $settings->public_ipv6) { | ||||||
|                         $domains->push([ |                         $domains->push([ | ||||||
|                             'domain' => $fqdn, |                             'domain' => $fqdn, | ||||||
|                             'ip' => $ip, |                             'ip' => $ip, | ||||||
| @ -74,7 +74,7 @@ class Domains extends Controller | |||||||
|                                     'ip' => $settings->public_ipv6, |                                     'ip' => $settings->public_ipv6, | ||||||
|                                 ]); |                                 ]); | ||||||
|                             } |                             } | ||||||
|                             if (!$settings->public_ipv4 && !$settings->public_ipv6) { |                             if (! $settings->public_ipv4 && ! $settings->public_ipv6) { | ||||||
|                                 $domains->push([ |                                 $domains->push([ | ||||||
|                                     'domain' => $fqdn, |                                     'domain' => $fqdn, | ||||||
|                                     'ip' => $ip, |                                     'ip' => $ip, | ||||||
|  | |||||||
| @ -15,8 +15,10 @@ class Project extends Controller | |||||||
|             return invalid_token(); |             return invalid_token(); | ||||||
|         } |         } | ||||||
|         $projects = ModelsProject::whereTeamId($teamId)->select('id', 'name', 'uuid')->get(); |         $projects = ModelsProject::whereTeamId($teamId)->select('id', 'name', 'uuid')->get(); | ||||||
|  | 
 | ||||||
|         return response()->json($projects); |         return response()->json($projects); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function project_by_uuid(Request $request) |     public function project_by_uuid(Request $request) | ||||||
|     { |     { | ||||||
|         $teamId = get_team_id_from_token(); |         $teamId = get_team_id_from_token(); | ||||||
| @ -24,8 +26,10 @@ class Project extends Controller | |||||||
|             return invalid_token(); |             return invalid_token(); | ||||||
|         } |         } | ||||||
|         $project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first()->load(['environments']); |         $project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first()->load(['environments']); | ||||||
|  | 
 | ||||||
|         return response()->json($project); |         return response()->json($project); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function environment_details(Request $request) |     public function environment_details(Request $request) | ||||||
|     { |     { | ||||||
|         $teamId = get_team_id_from_token(); |         $teamId = get_team_id_from_token(); | ||||||
| @ -34,6 +38,7 @@ class Project extends Controller | |||||||
|         } |         } | ||||||
|         $project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first(); |         $project = ModelsProject::whereTeamId($teamId)->whereUuid(request()->uuid)->first(); | ||||||
|         $environment = $project->environments()->whereName(request()->environment_name)->first()->load(['applications', 'postgresqls', 'redis', 'mongodbs', 'mysqls', 'mariadbs', 'services']); |         $environment = $project->environments()->whereName(request()->environment_name)->first()->load(['applications', 'postgresqls', 'redis', 'mongodbs', 'mysqls', 'mariadbs', 'services']); | ||||||
|  | 
 | ||||||
|         return response()->json($environment); |         return response()->json($environment); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,9 +30,10 @@ class Resources extends Controller | |||||||
|                 $payload['status'] = $resource->status; |                 $payload['status'] = $resource->status; | ||||||
|             } |             } | ||||||
|             $payload['type'] = $resource->type(); |             $payload['type'] = $resource->type(); | ||||||
|  | 
 | ||||||
|             return $payload; |             return $payload; | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|         return response()->json($resources); |         return response()->json($resources); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,10 +17,13 @@ class Server extends Controller | |||||||
|         $servers = ModelsServer::whereTeamId($teamId)->select('id', 'name', 'uuid', 'ip', 'user', 'port')->get()->load(['settings'])->map(function ($server) { |         $servers = ModelsServer::whereTeamId($teamId)->select('id', 'name', 'uuid', 'ip', 'user', 'port')->get()->load(['settings'])->map(function ($server) { | ||||||
|             $server['is_reachable'] = $server->settings->is_reachable; |             $server['is_reachable'] = $server->settings->is_reachable; | ||||||
|             $server['is_usable'] = $server->settings->is_usable; |             $server['is_usable'] = $server->settings->is_usable; | ||||||
|  | 
 | ||||||
|             return $server; |             return $server; | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|         return response()->json($servers); |         return response()->json($servers); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function server_by_uuid(Request $request) |     public function server_by_uuid(Request $request) | ||||||
|     { |     { | ||||||
|         $with_resources = $request->query('resources'); |         $with_resources = $request->query('resources'); | ||||||
| @ -47,11 +50,13 @@ class Server extends Controller | |||||||
|                 } else { |                 } else { | ||||||
|                     $payload['status'] = $resource->status; |                     $payload['status'] = $resource->status; | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 return $payload; |                 return $payload; | ||||||
|             }); |             }); | ||||||
|         } else { |         } else { | ||||||
|             $server->load(['settings']); |             $server->load(['settings']); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return response()->json($server); |         return response()->json($server); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,8 +14,10 @@ class Team extends Controller | |||||||
|             return invalid_token(); |             return invalid_token(); | ||||||
|         } |         } | ||||||
|         $teams = auth()->user()->teams; |         $teams = auth()->user()->teams; | ||||||
|  | 
 | ||||||
|         return response()->json($teams); |         return response()->json($teams); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function team_by_id(Request $request) |     public function team_by_id(Request $request) | ||||||
|     { |     { | ||||||
|         $id = $request->id; |         $id = $request->id; | ||||||
| @ -26,10 +28,12 @@ class Team extends Controller | |||||||
|         $teams = auth()->user()->teams; |         $teams = auth()->user()->teams; | ||||||
|         $team = $teams->where('id', $id)->first(); |         $team = $teams->where('id', $id)->first(); | ||||||
|         if (is_null($team)) { |         if (is_null($team)) { | ||||||
|             return response()->json(['error' => 'Team not found.',  "docs" => "https://coolify.io/docs/api-reference/get-team-by-teamid"], 404); |             return response()->json(['error' => 'Team not found.',  'docs' => 'https://coolify.io/docs/api-reference/get-team-by-teamid'], 404); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return response()->json($team); |         return response()->json($team); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function members_by_id(Request $request) |     public function members_by_id(Request $request) | ||||||
|     { |     { | ||||||
|         $id = $request->id; |         $id = $request->id; | ||||||
| @ -40,10 +44,12 @@ class Team extends Controller | |||||||
|         $teams = auth()->user()->teams; |         $teams = auth()->user()->teams; | ||||||
|         $team = $teams->where('id', $id)->first(); |         $team = $teams->where('id', $id)->first(); | ||||||
|         if (is_null($team)) { |         if (is_null($team)) { | ||||||
|             return response()->json(['error' => 'Team not found.', "docs" => "https://coolify.io/docs/api-reference/get-team-by-teamid-members"], 404); |             return response()->json(['error' => 'Team not found.', 'docs' => 'https://coolify.io/docs/api-reference/get-team-by-teamid-members'], 404); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return response()->json($team->members); |         return response()->json($team->members); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function current_team(Request $request) |     public function current_team(Request $request) | ||||||
|     { |     { | ||||||
|         $teamId = get_team_id_from_token(); |         $teamId = get_team_id_from_token(); | ||||||
| @ -51,8 +57,10 @@ class Team extends Controller | |||||||
|             return invalid_token(); |             return invalid_token(); | ||||||
|         } |         } | ||||||
|         $team = auth()->user()->currentTeam(); |         $team = auth()->user()->currentTeam(); | ||||||
|  | 
 | ||||||
|         return response()->json($team); |         return response()->json($team); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function current_team_members(Request $request) |     public function current_team_members(Request $request) | ||||||
|     { |     { | ||||||
|         $teamId = get_team_id_from_token(); |         $teamId = get_team_id_from_token(); | ||||||
| @ -60,6 +68,7 @@ class Team extends Controller | |||||||
|             return invalid_token(); |             return invalid_token(); | ||||||
|         } |         } | ||||||
|         $team = auth()->user()->currentTeam(); |         $team = auth()->user()->currentTeam(); | ||||||
|  | 
 | ||||||
|         return response()->json($team->members); |         return response()->json($team->members); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,40 +14,49 @@ use Illuminate\Routing\Controller as BaseController; | |||||||
| use Illuminate\Support\Facades\Auth; | use Illuminate\Support\Facades\Auth; | ||||||
| use Illuminate\Support\Facades\Crypt; | use Illuminate\Support\Facades\Crypt; | ||||||
| use Illuminate\Support\Facades\Hash; | use Illuminate\Support\Facades\Hash; | ||||||
|  | use Illuminate\Support\Facades\Password; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Laravel\Fortify\Fortify; |  | ||||||
| use Laravel\Fortify\Contracts\FailedPasswordResetLinkRequestResponse; | use Laravel\Fortify\Contracts\FailedPasswordResetLinkRequestResponse; | ||||||
| use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse; | use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse; | ||||||
| use Illuminate\Support\Facades\Password; | use Laravel\Fortify\Fortify; | ||||||
| 
 | 
 | ||||||
| class Controller extends BaseController | class Controller extends BaseController | ||||||
| { | { | ||||||
|     use AuthorizesRequests, ValidatesRequests; |     use AuthorizesRequests, ValidatesRequests; | ||||||
| 
 | 
 | ||||||
|     public function realtime_test() { |     public function realtime_test() | ||||||
|  |     { | ||||||
|         if (auth()->user()?->currentTeam()->id !== 0) { |         if (auth()->user()?->currentTeam()->id !== 0) { | ||||||
|             return redirect(RouteServiceProvider::HOME); |             return redirect(RouteServiceProvider::HOME); | ||||||
|         } |         } | ||||||
|         TestEvent::dispatch(); |         TestEvent::dispatch(); | ||||||
|  | 
 | ||||||
|         return 'Look at your other tab.'; |         return 'Look at your other tab.'; | ||||||
|     } |     } | ||||||
|     public function verify() { | 
 | ||||||
|  |     public function verify() | ||||||
|  |     { | ||||||
|         return view('auth.verify-email'); |         return view('auth.verify-email'); | ||||||
|     } |     } | ||||||
|     public function email_verify(EmailVerificationRequest $request) { | 
 | ||||||
|  |     public function email_verify(EmailVerificationRequest $request) | ||||||
|  |     { | ||||||
|         $request->fulfill(); |         $request->fulfill(); | ||||||
|         $name = request()->user()?->name; |         $name = request()->user()?->name; | ||||||
|  | 
 | ||||||
|         // send_internal_notification("User {$name} verified their email address.");
 |         // send_internal_notification("User {$name} verified their email address.");
 | ||||||
|         return redirect(RouteServiceProvider::HOME); |         return redirect(RouteServiceProvider::HOME); | ||||||
|     } |     } | ||||||
|     public function forgot_password(Request $request) { | 
 | ||||||
|  |     public function forgot_password(Request $request) | ||||||
|  |     { | ||||||
|         if (is_transactional_emails_active()) { |         if (is_transactional_emails_active()) { | ||||||
|             $arrayOfRequest = $request->only(Fortify::email()); |             $arrayOfRequest = $request->only(Fortify::email()); | ||||||
|             $request->merge([ |             $request->merge([ | ||||||
|                 'email' => Str::lower($arrayOfRequest['email']), |                 'email' => Str::lower($arrayOfRequest['email']), | ||||||
|             ]); |             ]); | ||||||
|             $type = set_transanctional_email_settings(); |             $type = set_transanctional_email_settings(); | ||||||
|             if (!$type) { |             if (! $type) { | ||||||
|                 return response()->json(['message' => 'Transactional emails are not active'], 400); |                 return response()->json(['message' => 'Transactional emails are not active'], 400); | ||||||
|             } |             } | ||||||
|             $request->validate([Fortify::email() => 'required|email']); |             $request->validate([Fortify::email() => 'required|email']); | ||||||
| @ -60,10 +69,13 @@ class Controller extends BaseController | |||||||
|             if ($status == Password::RESET_THROTTLED) { |             if ($status == Password::RESET_THROTTLED) { | ||||||
|                 return response('Already requested a password reset in the past minutes.', 400); |                 return response('Already requested a password reset in the past minutes.', 400); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return app(FailedPasswordResetLinkRequestResponse::class, ['status' => $status]); |             return app(FailedPasswordResetLinkRequestResponse::class, ['status' => $status]); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return response()->json(['message' => 'Transactional emails are not active'], 400); |         return response()->json(['message' => 'Transactional emails are not active'], 400); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function link() |     public function link() | ||||||
|     { |     { | ||||||
|         $token = request()->get('token'); |         $token = request()->get('token'); | ||||||
| @ -72,7 +84,7 @@ class Controller extends BaseController | |||||||
|             $email = Str::of($decrypted)->before('@@@'); |             $email = Str::of($decrypted)->before('@@@'); | ||||||
|             $password = Str::of($decrypted)->after('@@@'); |             $password = Str::of($decrypted)->after('@@@'); | ||||||
|             $user = User::whereEmail($email)->first(); |             $user = User::whereEmail($email)->first(); | ||||||
|             if (!$user) { |             if (! $user) { | ||||||
|                 return redirect()->route('login'); |                 return redirect()->route('login'); | ||||||
|             } |             } | ||||||
|             if (Hash::check($password, $user->password)) { |             if (Hash::check($password, $user->password)) { | ||||||
| @ -90,9 +102,11 @@ class Controller extends BaseController | |||||||
|                 } |                 } | ||||||
|                 Auth::login($user); |                 Auth::login($user); | ||||||
|                 session(['currentTeam' => $team]); |                 session(['currentTeam' => $team]); | ||||||
|  | 
 | ||||||
|                 return redirect()->route('dashboard'); |                 return redirect()->route('dashboard'); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return redirect()->route('login')->with('error', 'Invalid credentials.'); |         return redirect()->route('login')->with('error', 'Invalid credentials.'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -108,11 +122,12 @@ class Controller extends BaseController | |||||||
|                 if ($resetPassword) { |                 if ($resetPassword) { | ||||||
|                     $user->update([ |                     $user->update([ | ||||||
|                         'password' => Hash::make($invitationUuid), |                         'password' => Hash::make($invitationUuid), | ||||||
|                         'force_password_reset' => true |                         'force_password_reset' => true, | ||||||
|                     ]); |                     ]); | ||||||
|                 } |                 } | ||||||
|                 if ($user->teams()->where('team_id', $invitation->team->id)->exists()) { |                 if ($user->teams()->where('team_id', $invitation->team->id)->exists()) { | ||||||
|                     $invitation->delete(); |                     $invitation->delete(); | ||||||
|  | 
 | ||||||
|                     return redirect()->route('team.index'); |                     return redirect()->route('team.index'); | ||||||
|                 } |                 } | ||||||
|                 $user->teams()->attach($invitation->team->id, ['role' => $invitation->role]); |                 $user->teams()->attach($invitation->team->id, ['role' => $invitation->role]); | ||||||
| @ -121,6 +136,7 @@ class Controller extends BaseController | |||||||
|                     return redirect()->route('login'); |                     return redirect()->route('login'); | ||||||
|                 } |                 } | ||||||
|                 refreshSession($invitation->team); |                 refreshSession($invitation->team); | ||||||
|  | 
 | ||||||
|                 return redirect()->route('team.index'); |                 return redirect()->route('team.index'); | ||||||
|             } else { |             } else { | ||||||
|                 abort(401); |                 abort(401); | ||||||
| @ -143,6 +159,7 @@ class Controller extends BaseController | |||||||
|                 abort(401); |                 abort(401); | ||||||
|             } |             } | ||||||
|             $invitation->delete(); |             $invitation->delete(); | ||||||
|  | 
 | ||||||
|             return redirect()->route('team.index'); |             return redirect()->route('team.index'); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             throw $e; |             throw $e; | ||||||
|  | |||||||
| @ -12,34 +12,35 @@ class MagicController extends Controller | |||||||
|     public function servers() |     public function servers() | ||||||
|     { |     { | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'servers' => Server::isUsable()->get() |             'servers' => Server::isUsable()->get(), | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function destinations() |     public function destinations() | ||||||
|     { |     { | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'destinations' => Server::destinationsByServer(request()->query('server_id'))->sortBy('name') |             'destinations' => Server::destinationsByServer(request()->query('server_id'))->sortBy('name'), | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function projects() |     public function projects() | ||||||
|     { |     { | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'projects' => Project::ownedByCurrentTeam()->get() |             'projects' => Project::ownedByCurrentTeam()->get(), | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function environments() |     public function environments() | ||||||
|     { |     { | ||||||
|         $project = Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->first(); |         $project = Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->first(); | ||||||
|         if (!$project) { |         if (! $project) { | ||||||
|             return response()->json([ |             return response()->json([ | ||||||
|                 'environments' => [] |                 'environments' => [], | ||||||
|             ]); |             ]); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'environments' => $project->environments |             'environments' => $project->environments, | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -49,8 +50,9 @@ class MagicController extends Controller | |||||||
|             ['name' => request()->query('name') ?? generate_random_name()], |             ['name' => request()->query('name') ?? generate_random_name()], | ||||||
|             ['team_id' => currentTeam()->id] |             ['team_id' => currentTeam()->id] | ||||||
|         ); |         ); | ||||||
|  | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'project_uuid' => $project->uuid |             'project_uuid' => $project->uuid, | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -60,6 +62,7 @@ class MagicController extends Controller | |||||||
|             ['name' => request()->query('name') ?? generate_random_name()], |             ['name' => request()->query('name') ?? generate_random_name()], | ||||||
|             ['project_id' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->firstOrFail()->id] |             ['project_id' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->firstOrFail()->id] | ||||||
|         ); |         ); | ||||||
|  | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'environment_name' => $environment->name, |             'environment_name' => $environment->name, | ||||||
|         ]); |         ]); | ||||||
| @ -75,6 +78,7 @@ class MagicController extends Controller | |||||||
|         ); |         ); | ||||||
|         auth()->user()->teams()->attach($team, ['role' => 'admin']); |         auth()->user()->teams()->attach($team, ['role' => 'admin']); | ||||||
|         refreshSession(); |         refreshSession(); | ||||||
|  | 
 | ||||||
|         return redirect(request()->header('Referer')); |         return redirect(request()->header('Referer')); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,15 +2,15 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||||||
| 
 | 
 | ||||||
| use App\Http\Controllers\Controller; |  | ||||||
| use App\Models\User; | use App\Models\User; | ||||||
| 
 |  | ||||||
| use Illuminate\Support\Facades\Auth; | use Illuminate\Support\Facades\Auth; | ||||||
| 
 | 
 | ||||||
| class OauthController extends Controller { | class OauthController extends Controller | ||||||
|  | { | ||||||
|     public function redirect(string $provider) |     public function redirect(string $provider) | ||||||
|     { |     { | ||||||
|         $socialite_provider = get_socialite_provider($provider); |         $socialite_provider = get_socialite_provider($provider); | ||||||
|  | 
 | ||||||
|         return $socialite_provider->redirect(); |         return $socialite_provider->redirect(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -19,16 +19,18 @@ class OauthController extends Controller { | |||||||
|         try { |         try { | ||||||
|             $oauthUser = get_socialite_provider($provider)->user(); |             $oauthUser = get_socialite_provider($provider)->user(); | ||||||
|             $user = User::whereEmail($oauthUser->email)->first(); |             $user = User::whereEmail($oauthUser->email)->first(); | ||||||
|             if (!$user) { |             if (! $user) { | ||||||
|                 $user = User::create([ |                 $user = User::create([ | ||||||
|                     'name' => $oauthUser->name, |                     'name' => $oauthUser->name, | ||||||
|                     'email' => $oauthUser->email, |                     'email' => $oauthUser->email, | ||||||
|                 ]); |                 ]); | ||||||
|             } |             } | ||||||
|             Auth::login($user); |             Auth::login($user); | ||||||
|  | 
 | ||||||
|             return redirect('/'); |             return redirect('/'); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return redirect()->route('login')->withErrors([__('auth.failed.callback')]); |             return redirect()->route('login')->withErrors([__('auth.failed.callback')]); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,14 +2,11 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Routing\Controller as BaseController; |  | ||||||
| use Illuminate\Http\JsonResponse; |  | ||||||
| use Pion\Laravel\ChunkUpload\Exceptions\UploadFailedException; |  | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Illuminate\Http\UploadedFile; | use Illuminate\Http\UploadedFile; | ||||||
|  | use Illuminate\Routing\Controller as BaseController; | ||||||
| use Illuminate\Support\Facades\Storage; | use Illuminate\Support\Facades\Storage; | ||||||
| use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException; | use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException; | ||||||
| use Pion\Laravel\ChunkUpload\Handler\AbstractHandler; |  | ||||||
| use Pion\Laravel\ChunkUpload\Handler\HandlerFactory; | use Pion\Laravel\ChunkUpload\Handler\HandlerFactory; | ||||||
| use Pion\Laravel\ChunkUpload\Receiver\FileReceiver; | use Pion\Laravel\ChunkUpload\Receiver\FileReceiver; | ||||||
| 
 | 
 | ||||||
| @ -21,7 +18,7 @@ class UploadController extends BaseController | |||||||
|         if (is_null($resource)) { |         if (is_null($resource)) { | ||||||
|             return response()->json(['error' => 'You do not have permission for this database'], 500); |             return response()->json(['error' => 'You do not have permission for this database'], 500); | ||||||
|         } |         } | ||||||
|         $receiver = new FileReceiver("file", $request, HandlerFactory::classFromRequest($request)); |         $receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request)); | ||||||
| 
 | 
 | ||||||
|         if ($receiver->isUploaded() === false) { |         if ($receiver->isUploaded() === false) { | ||||||
|             throw new UploadMissingFileException(); |             throw new UploadMissingFileException(); | ||||||
| @ -34,9 +31,10 @@ class UploadController extends BaseController | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $handler = $save->handler(); |         $handler = $save->handler(); | ||||||
|  | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             "done" => $handler->getPercentageDone(), |             'done' => $handler->getPercentageDone(), | ||||||
|             'status' => true |             'status' => true, | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|     // protected function saveFileToS3($file)
 |     // protected function saveFileToS3($file)
 | ||||||
| @ -64,19 +62,20 @@ class UploadController extends BaseController | |||||||
|     { |     { | ||||||
|         $mime = str_replace('/', '-', $file->getMimeType()); |         $mime = str_replace('/', '-', $file->getMimeType()); | ||||||
|         $filePath = "upload/{$resource->uuid}"; |         $filePath = "upload/{$resource->uuid}"; | ||||||
|         $finalPath = storage_path("app/" . $filePath); |         $finalPath = storage_path('app/'.$filePath); | ||||||
|         $file->move($finalPath, 'restore'); |         $file->move($finalPath, 'restore'); | ||||||
| 
 | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'mime_type' => $mime |             'mime_type' => $mime, | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     protected function createFilename(UploadedFile $file) |     protected function createFilename(UploadedFile $file) | ||||||
|     { |     { | ||||||
|         $extension = $file->getClientOriginalExtension(); |         $extension = $file->getClientOriginalExtension(); | ||||||
|         $filename = str_replace("." . $extension, "", $file->getClientOriginalName()); // Filename without extension
 |         $filename = str_replace('.'.$extension, '', $file->getClientOriginalName()); // Filename without extension
 | ||||||
| 
 | 
 | ||||||
|         $filename .= "_" . md5(time()) . "." . $extension; |         $filename .= '_'.md5(time()).'.'.$extension; | ||||||
| 
 | 
 | ||||||
|         return $filename; |         return $filename; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -20,25 +20,26 @@ class Bitbucket extends Controller | |||||||
|                 $epoch = now()->valueOf(); |                 $epoch = now()->valueOf(); | ||||||
|                 $data = [ |                 $data = [ | ||||||
|                     'attributes' => $request->attributes->all(), |                     'attributes' => $request->attributes->all(), | ||||||
|                     'request'    => $request->request->all(), |                     'request' => $request->request->all(), | ||||||
|                     'query'      => $request->query->all(), |                     'query' => $request->query->all(), | ||||||
|                     'server'     => $request->server->all(), |                     'server' => $request->server->all(), | ||||||
|                     'files'      => $request->files->all(), |                     'files' => $request->files->all(), | ||||||
|                     'cookies'    => $request->cookies->all(), |                     'cookies' => $request->cookies->all(), | ||||||
|                     'headers'    => $request->headers->all(), |                     'headers' => $request->headers->all(), | ||||||
|                     'content'    => $request->getContent(), |                     'content' => $request->getContent(), | ||||||
|                 ]; |                 ]; | ||||||
|                 $json = json_encode($data); |                 $json = json_encode($data); | ||||||
|                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Bitbicket::manual_bitbucket", $json); |                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Bitbicket::manual_bitbucket", $json); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $return_payloads = collect([]); |             $return_payloads = collect([]); | ||||||
|             $payload = $request->collect(); |             $payload = $request->collect(); | ||||||
|             $headers = $request->headers->all(); |             $headers = $request->headers->all(); | ||||||
|             $x_bitbucket_token = data_get($headers, 'x-hub-signature.0', ""); |             $x_bitbucket_token = data_get($headers, 'x-hub-signature.0', ''); | ||||||
|             $x_bitbucket_event = data_get($headers, 'x-event-key.0', ""); |             $x_bitbucket_event = data_get($headers, 'x-event-key.0', ''); | ||||||
|             $handled_events = collect(['repo:push', 'pullrequest:created', 'pullrequest:rejected', 'pullrequest:fulfilled']); |             $handled_events = collect(['repo:push', 'pullrequest:created', 'pullrequest:rejected', 'pullrequest:fulfilled']); | ||||||
|             if (!$handled_events->contains($x_bitbucket_event)) { |             if (! $handled_events->contains($x_bitbucket_event)) { | ||||||
|                 return response([ |                 return response([ | ||||||
|                     'status' => 'failed', |                     'status' => 'failed', | ||||||
|                     'message' => 'Nothing to do. Event not handled.', |                     'message' => 'Nothing to do. Event not handled.', | ||||||
| @ -48,13 +49,13 @@ class Bitbucket extends Controller | |||||||
|                 $branch = data_get($payload, 'push.changes.0.new.name'); |                 $branch = data_get($payload, 'push.changes.0.new.name'); | ||||||
|                 $full_name = data_get($payload, 'repository.full_name'); |                 $full_name = data_get($payload, 'repository.full_name'); | ||||||
|                 $commit = data_get($payload, 'push.changes.0.new.target.hash'); |                 $commit = data_get($payload, 'push.changes.0.new.target.hash'); | ||||||
|                 if (!$branch) { |                 if (! $branch) { | ||||||
|                     return response([ |                     return response([ | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Nothing to do. No branch found in the request.', |                         'message' => 'Nothing to do. No branch found in the request.', | ||||||
|                     ]); |                     ]); | ||||||
|                 } |                 } | ||||||
|                 ray('Manual webhook bitbucket push event with branch: ' . $branch); |                 ray('Manual webhook bitbucket push event with branch: '.$branch); | ||||||
|             } |             } | ||||||
|             if ($x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') { |             if ($x_bitbucket_event === 'pullrequest:created' || $x_bitbucket_event === 'pullrequest:rejected' || $x_bitbucket_event === 'pullrequest:fulfilled') { | ||||||
|                 $branch = data_get($payload, 'pullrequest.destination.branch.name'); |                 $branch = data_get($payload, 'pullrequest.destination.branch.name'); | ||||||
| @ -76,30 +77,32 @@ class Bitbucket extends Controller | |||||||
|                 $webhook_secret = data_get($application, 'manual_webhook_secret_bitbucket'); |                 $webhook_secret = data_get($application, 'manual_webhook_secret_bitbucket'); | ||||||
|                 $payload = $request->getContent(); |                 $payload = $request->getContent(); | ||||||
| 
 | 
 | ||||||
|                 list($algo, $hash) = explode('=', $x_bitbucket_token, 2); |                 [$algo, $hash] = explode('=', $x_bitbucket_token, 2); | ||||||
|                 $payloadHash = hash_hmac($algo, $payload, $webhook_secret); |                 $payloadHash = hash_hmac($algo, $payload, $webhook_secret); | ||||||
|                 if (!hash_equals($hash, $payloadHash) && !isDev()) { |                 if (! hash_equals($hash, $payloadHash) && ! isDev()) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'application' => $application->name, |                         'application' => $application->name, | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Invalid signature.', |                         'message' => 'Invalid signature.', | ||||||
|                     ]); |                     ]); | ||||||
|                     ray('Invalid signature'); |                     ray('Invalid signature'); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 $isFunctional = $application->destination->server->isFunctional(); |                 $isFunctional = $application->destination->server->isFunctional(); | ||||||
|                 if (!$isFunctional) { |                 if (! $isFunctional) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'application' => $application->name, |                         'application' => $application->name, | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Server is not functional.', |                         'message' => 'Server is not functional.', | ||||||
|                     ]); |                     ]); | ||||||
|                     ray('Server is not functional: ' . $application->destination->server->name); |                     ray('Server is not functional: '.$application->destination->server->name); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if ($x_bitbucket_event === 'repo:push') { |                 if ($x_bitbucket_event === 'repo:push') { | ||||||
|                     if ($application->isDeployable()) { |                     if ($application->isDeployable()) { | ||||||
|                         ray('Deploying ' . $application->name . ' with branch ' . $branch); |                         ray('Deploying '.$application->name.' with branch '.$branch); | ||||||
|                         $deployment_uuid = new Cuid2(7); |                         $deployment_uuid = new Cuid2(7); | ||||||
|                         queue_application_deployment( |                         queue_application_deployment( | ||||||
|                             application: $application, |                             application: $application, | ||||||
| @ -123,10 +126,10 @@ class Bitbucket extends Controller | |||||||
|                 } |                 } | ||||||
|                 if ($x_bitbucket_event === 'pullrequest:created') { |                 if ($x_bitbucket_event === 'pullrequest:created') { | ||||||
|                     if ($application->isPRDeployable()) { |                     if ($application->isPRDeployable()) { | ||||||
|                         ray('Deploying preview for ' . $application->name . ' with branch ' . $branch . ' and base branch ' . $base_branch . ' and pull request id ' . $pull_request_id); |                         ray('Deploying preview for '.$application->name.' with branch '.$branch.' and base branch '.$base_branch.' and pull request id '.$pull_request_id); | ||||||
|                         $deployment_uuid = new Cuid2(7); |                         $deployment_uuid = new Cuid2(7); | ||||||
|                         $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); |                         $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); | ||||||
|                         if (!$found) { |                         if (! $found) { | ||||||
|                             ApplicationPreview::create([ |                             ApplicationPreview::create([ | ||||||
|                                 'git_type' => 'bitbucket', |                                 'git_type' => 'bitbucket', | ||||||
|                                 'application_id' => $application->id, |                                 'application_id' => $application->id, | ||||||
| @ -178,9 +181,11 @@ class Bitbucket extends Controller | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             ray($return_payloads); |             ray($return_payloads); | ||||||
|  | 
 | ||||||
|             return response($return_payloads); |             return response($return_payloads); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             ray($e); |             ray($e); | ||||||
|  | 
 | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -27,20 +27,22 @@ class Gitea extends Controller | |||||||
|                 })->first(); |                 })->first(); | ||||||
|                 if ($gitea_delivery_found) { |                 if ($gitea_delivery_found) { | ||||||
|                     ray('Webhook already found'); |                     ray('Webhook already found'); | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 $data = [ |                 $data = [ | ||||||
|                     'attributes' => $request->attributes->all(), |                     'attributes' => $request->attributes->all(), | ||||||
|                     'request'    => $request->request->all(), |                     'request' => $request->request->all(), | ||||||
|                     'query'      => $request->query->all(), |                     'query' => $request->query->all(), | ||||||
|                     'server'     => $request->server->all(), |                     'server' => $request->server->all(), | ||||||
|                     'files'      => $request->files->all(), |                     'files' => $request->files->all(), | ||||||
|                     'cookies'    => $request->cookies->all(), |                     'cookies' => $request->cookies->all(), | ||||||
|                     'headers'    => $request->headers->all(), |                     'headers' => $request->headers->all(), | ||||||
|                     'content'    => $request->getContent(), |                     'content' => $request->getContent(), | ||||||
|                 ]; |                 ]; | ||||||
|                 $json = json_encode($data); |                 $json = json_encode($data); | ||||||
|                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitea::manual_{$x_gitea_delivery}", $json); |                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitea::manual_{$x_gitea_delivery}", $json); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $x_gitea_event = Str::lower($request->header('X-Gitea-Event')); |             $x_gitea_event = Str::lower($request->header('X-Gitea-Event')); | ||||||
| @ -66,7 +68,7 @@ class Gitea extends Controller | |||||||
|                 $modified_files = data_get($payload, 'commits.*.modified'); |                 $modified_files = data_get($payload, 'commits.*.modified'); | ||||||
|                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); |                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); | ||||||
|                 ray($changed_files); |                 ray($changed_files); | ||||||
|                 ray('Manual Webhook Gitea Push Event with branch: ' . $branch); |                 ray('Manual Webhook Gitea Push Event with branch: '.$branch); | ||||||
|             } |             } | ||||||
|             if ($x_gitea_event === 'pull_request') { |             if ($x_gitea_event === 'pull_request') { | ||||||
|                 $action = data_get($payload, 'action'); |                 $action = data_get($payload, 'action'); | ||||||
| @ -75,9 +77,9 @@ class Gitea extends Controller | |||||||
|                 $pull_request_html_url = data_get($payload, 'pull_request.html_url'); |                 $pull_request_html_url = data_get($payload, 'pull_request.html_url'); | ||||||
|                 $branch = data_get($payload, 'pull_request.head.ref'); |                 $branch = data_get($payload, 'pull_request.head.ref'); | ||||||
|                 $base_branch = data_get($payload, 'pull_request.base.ref'); |                 $base_branch = data_get($payload, 'pull_request.base.ref'); | ||||||
|                 ray('Webhook Gitea Pull Request Event with branch: ' . $branch . ' and base branch: ' . $base_branch . ' and pull request id: ' . $pull_request_id); |                 ray('Webhook Gitea Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id); | ||||||
|             } |             } | ||||||
|             if (!$branch) { |             if (! $branch) { | ||||||
|                 return response('Nothing to do. No branch found in the request.'); |                 return response('Nothing to do. No branch found in the request.'); | ||||||
|             } |             } | ||||||
|             $applications = Application::where('git_repository', 'like', "%$full_name%"); |             $applications = Application::where('git_repository', 'like', "%$full_name%"); | ||||||
| @ -96,29 +98,31 @@ class Gitea extends Controller | |||||||
|             foreach ($applications as $application) { |             foreach ($applications as $application) { | ||||||
|                 $webhook_secret = data_get($application, 'manual_webhook_secret_gitea'); |                 $webhook_secret = data_get($application, 'manual_webhook_secret_gitea'); | ||||||
|                 $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); |                 $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); | ||||||
|                 if (!hash_equals($x_hub_signature_256, $hmac) && !isDev()) { |                 if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) { | ||||||
|                     ray('Invalid signature'); |                     ray('Invalid signature'); | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'application' => $application->name, |                         'application' => $application->name, | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Invalid signature.', |                         'message' => 'Invalid signature.', | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 $isFunctional = $application->destination->server->isFunctional(); |                 $isFunctional = $application->destination->server->isFunctional(); | ||||||
|                 if (!$isFunctional) { |                 if (! $isFunctional) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'application' => $application->name, |                         'application' => $application->name, | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Server is not functional.', |                         'message' => 'Server is not functional.', | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if ($x_gitea_event === 'push') { |                 if ($x_gitea_event === 'push') { | ||||||
|                     if ($application->isDeployable()) { |                     if ($application->isDeployable()) { | ||||||
|                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); |                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); | ||||||
|                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { |                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { | ||||||
|                             ray('Deploying ' . $application->name . ' with branch ' . $branch); |                             ray('Deploying '.$application->name.' with branch '.$branch); | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             queue_application_deployment( |                             queue_application_deployment( | ||||||
|                                 application: $application, |                                 application: $application, | ||||||
| @ -160,7 +164,7 @@ class Gitea extends Controller | |||||||
|                         if ($application->isPRDeployable()) { |                         if ($application->isPRDeployable()) { | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); |                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); | ||||||
|                             if (!$found) { |                             if (! $found) { | ||||||
|                                 ApplicationPreview::create([ |                                 ApplicationPreview::create([ | ||||||
|                                     'git_type' => 'gitea', |                                     'git_type' => 'gitea', | ||||||
|                                     'application_id' => $application->id, |                                     'application_id' => $application->id, | ||||||
| @ -213,9 +217,11 @@ class Gitea extends Controller | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             ray($return_payloads); |             ray($return_payloads); | ||||||
|  | 
 | ||||||
|             return response($return_payloads); |             return response($return_payloads); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -33,20 +33,22 @@ class Github extends Controller | |||||||
|                 })->first(); |                 })->first(); | ||||||
|                 if ($github_delivery_found) { |                 if ($github_delivery_found) { | ||||||
|                     ray('Webhook already found'); |                     ray('Webhook already found'); | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 $data = [ |                 $data = [ | ||||||
|                     'attributes' => $request->attributes->all(), |                     'attributes' => $request->attributes->all(), | ||||||
|                     'request'    => $request->request->all(), |                     'request' => $request->request->all(), | ||||||
|                     'query'      => $request->query->all(), |                     'query' => $request->query->all(), | ||||||
|                     'server'     => $request->server->all(), |                     'server' => $request->server->all(), | ||||||
|                     'files'      => $request->files->all(), |                     'files' => $request->files->all(), | ||||||
|                     'cookies'    => $request->cookies->all(), |                     'cookies' => $request->cookies->all(), | ||||||
|                     'headers'    => $request->headers->all(), |                     'headers' => $request->headers->all(), | ||||||
|                     'content'    => $request->getContent(), |                     'content' => $request->getContent(), | ||||||
|                 ]; |                 ]; | ||||||
|                 $json = json_encode($data); |                 $json = json_encode($data); | ||||||
|                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::manual_{$x_github_delivery}", $json); |                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::manual_{$x_github_delivery}", $json); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $x_github_event = Str::lower($request->header('X-GitHub-Event')); |             $x_github_event = Str::lower($request->header('X-GitHub-Event')); | ||||||
| @ -71,7 +73,7 @@ class Github extends Controller | |||||||
|                 $removed_files = data_get($payload, 'commits.*.removed'); |                 $removed_files = data_get($payload, 'commits.*.removed'); | ||||||
|                 $modified_files = data_get($payload, 'commits.*.modified'); |                 $modified_files = data_get($payload, 'commits.*.modified'); | ||||||
|                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); |                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); | ||||||
|                 ray('Manual Webhook GitHub Push Event with branch: ' . $branch); |                 ray('Manual Webhook GitHub Push Event with branch: '.$branch); | ||||||
|             } |             } | ||||||
|             if ($x_github_event === 'pull_request') { |             if ($x_github_event === 'pull_request') { | ||||||
|                 $action = data_get($payload, 'action'); |                 $action = data_get($payload, 'action'); | ||||||
| @ -80,9 +82,9 @@ class Github extends Controller | |||||||
|                 $pull_request_html_url = data_get($payload, 'pull_request.html_url'); |                 $pull_request_html_url = data_get($payload, 'pull_request.html_url'); | ||||||
|                 $branch = data_get($payload, 'pull_request.head.ref'); |                 $branch = data_get($payload, 'pull_request.head.ref'); | ||||||
|                 $base_branch = data_get($payload, 'pull_request.base.ref'); |                 $base_branch = data_get($payload, 'pull_request.base.ref'); | ||||||
|                 ray('Webhook GitHub Pull Request Event with branch: ' . $branch . ' and base branch: ' . $base_branch . ' and pull request id: ' . $pull_request_id); |                 ray('Webhook GitHub Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id); | ||||||
|             } |             } | ||||||
|             if (!$branch) { |             if (! $branch) { | ||||||
|                 return response('Nothing to do. No branch found in the request.'); |                 return response('Nothing to do. No branch found in the request.'); | ||||||
|             } |             } | ||||||
|             $applications = Application::where('git_repository', 'like', "%$full_name%"); |             $applications = Application::where('git_repository', 'like', "%$full_name%"); | ||||||
| @ -101,29 +103,31 @@ class Github extends Controller | |||||||
|             foreach ($applications as $application) { |             foreach ($applications as $application) { | ||||||
|                 $webhook_secret = data_get($application, 'manual_webhook_secret_github'); |                 $webhook_secret = data_get($application, 'manual_webhook_secret_github'); | ||||||
|                 $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); |                 $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); | ||||||
|                 if (!hash_equals($x_hub_signature_256, $hmac) && !isDev()) { |                 if (! hash_equals($x_hub_signature_256, $hmac) && ! isDev()) { | ||||||
|                     ray('Invalid signature'); |                     ray('Invalid signature'); | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'application' => $application->name, |                         'application' => $application->name, | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Invalid signature.', |                         'message' => 'Invalid signature.', | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 $isFunctional = $application->destination->server->isFunctional(); |                 $isFunctional = $application->destination->server->isFunctional(); | ||||||
|                 if (!$isFunctional) { |                 if (! $isFunctional) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'application' => $application->name, |                         'application' => $application->name, | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Server is not functional.', |                         'message' => 'Server is not functional.', | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if ($x_github_event === 'push') { |                 if ($x_github_event === 'push') { | ||||||
|                     if ($application->isDeployable()) { |                     if ($application->isDeployable()) { | ||||||
|                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); |                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); | ||||||
|                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { |                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { | ||||||
|                             ray('Deploying ' . $application->name . ' with branch ' . $branch); |                             ray('Deploying '.$application->name.' with branch '.$branch); | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             queue_application_deployment( |                             queue_application_deployment( | ||||||
|                                 application: $application, |                                 application: $application, | ||||||
| @ -165,7 +169,7 @@ class Github extends Controller | |||||||
|                         if ($application->isPRDeployable()) { |                         if ($application->isPRDeployable()) { | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); |                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); | ||||||
|                             if (!$found) { |                             if (! $found) { | ||||||
|                                 ApplicationPreview::create([ |                                 ApplicationPreview::create([ | ||||||
|                                     'git_type' => 'github', |                                     'git_type' => 'github', | ||||||
|                                     'application_id' => $application->id, |                                     'application_id' => $application->id, | ||||||
| @ -218,12 +222,15 @@ class Github extends Controller | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             ray($return_payloads); |             ray($return_payloads); | ||||||
|  | 
 | ||||||
|             return response($return_payloads); |             return response($return_payloads); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function normal(Request $request) |     public function normal(Request $request) | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
| @ -239,20 +246,22 @@ class Github extends Controller | |||||||
|                 })->first(); |                 })->first(); | ||||||
|                 if ($github_delivery_found) { |                 if ($github_delivery_found) { | ||||||
|                     ray('Webhook already found'); |                     ray('Webhook already found'); | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 $data = [ |                 $data = [ | ||||||
|                     'attributes' => $request->attributes->all(), |                     'attributes' => $request->attributes->all(), | ||||||
|                     'request'    => $request->request->all(), |                     'request' => $request->request->all(), | ||||||
|                     'query'      => $request->query->all(), |                     'query' => $request->query->all(), | ||||||
|                     'server'     => $request->server->all(), |                     'server' => $request->server->all(), | ||||||
|                     'files'      => $request->files->all(), |                     'files' => $request->files->all(), | ||||||
|                     'cookies'    => $request->cookies->all(), |                     'cookies' => $request->cookies->all(), | ||||||
|                     'headers'    => $request->headers->all(), |                     'headers' => $request->headers->all(), | ||||||
|                     'content'    => $request->getContent(), |                     'content' => $request->getContent(), | ||||||
|                 ]; |                 ]; | ||||||
|                 $json = json_encode($data); |                 $json = json_encode($data); | ||||||
|                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::normal_{$x_github_delivery}", $json); |                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::normal_{$x_github_delivery}", $json); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $x_github_event = Str::lower($request->header('X-GitHub-Event')); |             $x_github_event = Str::lower($request->header('X-GitHub-Event')); | ||||||
| @ -270,7 +279,7 @@ class Github extends Controller | |||||||
|             $webhook_secret = data_get($github_app, 'webhook_secret'); |             $webhook_secret = data_get($github_app, 'webhook_secret'); | ||||||
|             $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); |             $hmac = hash_hmac('sha256', $request->getContent(), $webhook_secret); | ||||||
|             if (config('app.env') !== 'local') { |             if (config('app.env') !== 'local') { | ||||||
|                 if (!hash_equals($x_hub_signature_256, $hmac)) { |                 if (! hash_equals($x_hub_signature_256, $hmac)) { | ||||||
|                     return response('Invalid signature.'); |                     return response('Invalid signature.'); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -280,6 +289,7 @@ class Github extends Controller | |||||||
|                 if ($action === 'new_permissions_accepted') { |                 if ($action === 'new_permissions_accepted') { | ||||||
|                     GithubAppPermissionJob::dispatch($github_app); |                     GithubAppPermissionJob::dispatch($github_app); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 return response('cool'); |                 return response('cool'); | ||||||
|             } |             } | ||||||
|             if ($x_github_event === 'push') { |             if ($x_github_event === 'push') { | ||||||
| @ -292,7 +302,7 @@ class Github extends Controller | |||||||
|                 $removed_files = data_get($payload, 'commits.*.removed'); |                 $removed_files = data_get($payload, 'commits.*.removed'); | ||||||
|                 $modified_files = data_get($payload, 'commits.*.modified'); |                 $modified_files = data_get($payload, 'commits.*.modified'); | ||||||
|                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); |                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); | ||||||
|                 ray('Webhook GitHub Push Event: ' . $id . ' with branch: ' . $branch); |                 ray('Webhook GitHub Push Event: '.$id.' with branch: '.$branch); | ||||||
|             } |             } | ||||||
|             if ($x_github_event === 'pull_request') { |             if ($x_github_event === 'pull_request') { | ||||||
|                 $action = data_get($payload, 'action'); |                 $action = data_get($payload, 'action'); | ||||||
| @ -301,9 +311,9 @@ class Github extends Controller | |||||||
|                 $pull_request_html_url = data_get($payload, 'pull_request.html_url'); |                 $pull_request_html_url = data_get($payload, 'pull_request.html_url'); | ||||||
|                 $branch = data_get($payload, 'pull_request.head.ref'); |                 $branch = data_get($payload, 'pull_request.head.ref'); | ||||||
|                 $base_branch = data_get($payload, 'pull_request.base.ref'); |                 $base_branch = data_get($payload, 'pull_request.base.ref'); | ||||||
|                 ray('Webhook GitHub Pull Request Event: ' . $id . ' with branch: ' . $branch . ' and base branch: ' . $base_branch . ' and pull request id: ' . $pull_request_id); |                 ray('Webhook GitHub Pull Request Event: '.$id.' with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id); | ||||||
|             } |             } | ||||||
|             if (!$id || !$branch) { |             if (! $id || ! $branch) { | ||||||
|                 return response('Nothing to do. No id or branch found.'); |                 return response('Nothing to do. No id or branch found.'); | ||||||
|             } |             } | ||||||
|             $applications = Application::where('repository_project_id', $id)->whereRelation('source', 'is_public', false); |             $applications = Application::where('repository_project_id', $id)->whereRelation('source', 'is_public', false); | ||||||
| @ -322,20 +332,21 @@ class Github extends Controller | |||||||
| 
 | 
 | ||||||
|             foreach ($applications as $application) { |             foreach ($applications as $application) { | ||||||
|                 $isFunctional = $application->destination->server->isFunctional(); |                 $isFunctional = $application->destination->server->isFunctional(); | ||||||
|                 if (!$isFunctional) { |                 if (! $isFunctional) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Server is not functional.', |                         'message' => 'Server is not functional.', | ||||||
|                         'application_uuid' => $application->uuid, |                         'application_uuid' => $application->uuid, | ||||||
|                         'application_name' => $application->name, |                         'application_name' => $application->name, | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if ($x_github_event === 'push') { |                 if ($x_github_event === 'push') { | ||||||
|                     if ($application->isDeployable()) { |                     if ($application->isDeployable()) { | ||||||
|                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); |                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); | ||||||
|                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { |                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { | ||||||
|                             ray('Deploying ' . $application->name . ' with branch ' . $branch); |                             ray('Deploying '.$application->name.' with branch '.$branch); | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             queue_application_deployment( |                             queue_application_deployment( | ||||||
|                                 application: $application, |                                 application: $application, | ||||||
| @ -377,7 +388,7 @@ class Github extends Controller | |||||||
|                         if ($application->isPRDeployable()) { |                         if ($application->isPRDeployable()) { | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); |                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); | ||||||
|                             if (!$found) { |                             if (! $found) { | ||||||
|                                 ApplicationPreview::create([ |                                 ApplicationPreview::create([ | ||||||
|                                     'git_type' => 'github', |                                     'git_type' => 'github', | ||||||
|                                     'application_id' => $application->id, |                                     'application_id' => $application->id, | ||||||
| @ -431,12 +442,15 @@ class Github extends Controller | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return response($return_payloads); |             return response($return_payloads); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function redirect(Request $request) |     public function redirect(Request $request) | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
| @ -464,11 +478,13 @@ class Github extends Controller | |||||||
|             $github_app->webhook_secret = $webhook_secret; |             $github_app->webhook_secret = $webhook_secret; | ||||||
|             $github_app->private_key_id = $private_key->id; |             $github_app->private_key_id = $private_key->id; | ||||||
|             $github_app->save(); |             $github_app->save(); | ||||||
|  | 
 | ||||||
|             return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]); |             return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function install(Request $request) |     public function install(Request $request) | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
| @ -478,16 +494,17 @@ class Github extends Controller | |||||||
|                 $epoch = now()->valueOf(); |                 $epoch = now()->valueOf(); | ||||||
|                 $data = [ |                 $data = [ | ||||||
|                     'attributes' => $request->attributes->all(), |                     'attributes' => $request->attributes->all(), | ||||||
|                     'request'    => $request->request->all(), |                     'request' => $request->request->all(), | ||||||
|                     'query'      => $request->query->all(), |                     'query' => $request->query->all(), | ||||||
|                     'server'     => $request->server->all(), |                     'server' => $request->server->all(), | ||||||
|                     'files'      => $request->files->all(), |                     'files' => $request->files->all(), | ||||||
|                     'cookies'    => $request->cookies->all(), |                     'cookies' => $request->cookies->all(), | ||||||
|                     'headers'    => $request->headers->all(), |                     'headers' => $request->headers->all(), | ||||||
|                     'content'    => $request->getContent(), |                     'content' => $request->getContent(), | ||||||
|                 ]; |                 ]; | ||||||
|                 $json = json_encode($data); |                 $json = json_encode($data); | ||||||
|                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::install_{$installation_id}", $json); |                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Github::install_{$installation_id}", $json); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $source = $request->get('source'); |             $source = $request->get('source'); | ||||||
| @ -497,6 +514,7 @@ class Github extends Controller | |||||||
|                 $github_app->installation_id = $installation_id; |                 $github_app->installation_id = $installation_id; | ||||||
|                 $github_app->save(); |                 $github_app->save(); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]); |             return redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|  | |||||||
| @ -21,16 +21,17 @@ class Gitlab extends Controller | |||||||
|                 $epoch = now()->valueOf(); |                 $epoch = now()->valueOf(); | ||||||
|                 $data = [ |                 $data = [ | ||||||
|                     'attributes' => $request->attributes->all(), |                     'attributes' => $request->attributes->all(), | ||||||
|                     'request'    => $request->request->all(), |                     'request' => $request->request->all(), | ||||||
|                     'query'      => $request->query->all(), |                     'query' => $request->query->all(), | ||||||
|                     'server'     => $request->server->all(), |                     'server' => $request->server->all(), | ||||||
|                     'files'      => $request->files->all(), |                     'files' => $request->files->all(), | ||||||
|                     'cookies'    => $request->cookies->all(), |                     'cookies' => $request->cookies->all(), | ||||||
|                     'headers'    => $request->headers->all(), |                     'headers' => $request->headers->all(), | ||||||
|                     'content'    => $request->getContent(), |                     'content' => $request->getContent(), | ||||||
|                 ]; |                 ]; | ||||||
|                 $json = json_encode($data); |                 $json = json_encode($data); | ||||||
|                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitlab::manual_gitlab", $json); |                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Gitlab::manual_gitlab", $json); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $return_payloads = collect([]); |             $return_payloads = collect([]); | ||||||
| @ -39,11 +40,12 @@ class Gitlab extends Controller | |||||||
|             $x_gitlab_token = data_get($headers, 'x-gitlab-token.0'); |             $x_gitlab_token = data_get($headers, 'x-gitlab-token.0'); | ||||||
|             $x_gitlab_event = data_get($payload, 'object_kind'); |             $x_gitlab_event = data_get($payload, 'object_kind'); | ||||||
|             $allowed_events = ['push', 'merge_request']; |             $allowed_events = ['push', 'merge_request']; | ||||||
|             if (!in_array($x_gitlab_event, $allowed_events)) { |             if (! in_array($x_gitlab_event, $allowed_events)) { | ||||||
|                 $return_payloads->push([ |                 $return_payloads->push([ | ||||||
|                     'status' => 'failed', |                     'status' => 'failed', | ||||||
|                     'message' => 'Event not allowed. Only push and merge_request events are allowed.', |                     'message' => 'Event not allowed. Only push and merge_request events are allowed.', | ||||||
|                 ]); |                 ]); | ||||||
|  | 
 | ||||||
|                 return response($return_payloads); |                 return response($return_payloads); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -53,18 +55,19 @@ class Gitlab extends Controller | |||||||
|                 if (Str::isMatch('/refs\/heads\/*/', $branch)) { |                 if (Str::isMatch('/refs\/heads\/*/', $branch)) { | ||||||
|                     $branch = Str::after($branch, 'refs/heads/'); |                     $branch = Str::after($branch, 'refs/heads/'); | ||||||
|                 } |                 } | ||||||
|                 if (!$branch) { |                 if (! $branch) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Nothing to do. No branch found in the request.', |                         'message' => 'Nothing to do. No branch found in the request.', | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     return response($return_payloads); |                     return response($return_payloads); | ||||||
|                 } |                 } | ||||||
|                 $added_files = data_get($payload, 'commits.*.added'); |                 $added_files = data_get($payload, 'commits.*.added'); | ||||||
|                 $removed_files = data_get($payload, 'commits.*.removed'); |                 $removed_files = data_get($payload, 'commits.*.removed'); | ||||||
|                 $modified_files = data_get($payload, 'commits.*.modified'); |                 $modified_files = data_get($payload, 'commits.*.modified'); | ||||||
|                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); |                 $changed_files = collect($added_files)->concat($removed_files)->concat($modified_files)->unique()->flatten(); | ||||||
|                 ray('Manual Webhook GitLab Push Event with branch: ' . $branch); |                 ray('Manual Webhook GitLab Push Event with branch: '.$branch); | ||||||
|             } |             } | ||||||
|             if ($x_gitlab_event === 'merge_request') { |             if ($x_gitlab_event === 'merge_request') { | ||||||
|                 $action = data_get($payload, 'object_attributes.action'); |                 $action = data_get($payload, 'object_attributes.action'); | ||||||
| @ -73,14 +76,15 @@ class Gitlab extends Controller | |||||||
|                 $full_name = data_get($payload, 'project.path_with_namespace'); |                 $full_name = data_get($payload, 'project.path_with_namespace'); | ||||||
|                 $pull_request_id = data_get($payload, 'object_attributes.iid'); |                 $pull_request_id = data_get($payload, 'object_attributes.iid'); | ||||||
|                 $pull_request_html_url = data_get($payload, 'object_attributes.url'); |                 $pull_request_html_url = data_get($payload, 'object_attributes.url'); | ||||||
|                 if (!$branch) { |                 if (! $branch) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Nothing to do. No branch found in the request.', |                         'message' => 'Nothing to do. No branch found in the request.', | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     return response($return_payloads); |                     return response($return_payloads); | ||||||
|                 } |                 } | ||||||
|                 ray('Webhook GitHub Pull Request Event with branch: ' . $branch . ' and base branch: ' . $base_branch . ' and pull request id: ' . $pull_request_id); |                 ray('Webhook GitHub Pull Request Event with branch: '.$branch.' and base branch: '.$base_branch.' and pull request id: '.$pull_request_id); | ||||||
|             } |             } | ||||||
|             $applications = Application::where('git_repository', 'like', "%$full_name%"); |             $applications = Application::where('git_repository', 'like', "%$full_name%"); | ||||||
|             if ($x_gitlab_event === 'push') { |             if ($x_gitlab_event === 'push') { | ||||||
| @ -90,6 +94,7 @@ class Gitlab extends Controller | |||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => "Nothing to do. No applications found with deploy key set, branch is '$branch' and Git Repository name has $full_name.", |                         'message' => "Nothing to do. No applications found with deploy key set, branch is '$branch' and Git Repository name has $full_name.", | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     return response($return_payloads); |                     return response($return_payloads); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -100,6 +105,7 @@ class Gitlab extends Controller | |||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => "Nothing to do. No applications found with branch '$base_branch'.", |                         'message' => "Nothing to do. No applications found with branch '$base_branch'.", | ||||||
|                     ]); |                     ]); | ||||||
|  | 
 | ||||||
|                     return response($return_payloads); |                     return response($return_payloads); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -112,23 +118,25 @@ class Gitlab extends Controller | |||||||
|                         'message' => 'Invalid signature.', |                         'message' => 'Invalid signature.', | ||||||
|                     ]); |                     ]); | ||||||
|                     ray('Invalid signature'); |                     ray('Invalid signature'); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 $isFunctional = $application->destination->server->isFunctional(); |                 $isFunctional = $application->destination->server->isFunctional(); | ||||||
|                 if (!$isFunctional) { |                 if (! $isFunctional) { | ||||||
|                     $return_payloads->push([ |                     $return_payloads->push([ | ||||||
|                         'application' => $application->name, |                         'application' => $application->name, | ||||||
|                         'status' => 'failed', |                         'status' => 'failed', | ||||||
|                         'message' => 'Server is not functional', |                         'message' => 'Server is not functional', | ||||||
|                     ]); |                     ]); | ||||||
|                     ray('Server is not functional: ' . $application->destination->server->name); |                     ray('Server is not functional: '.$application->destination->server->name); | ||||||
|  | 
 | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                 if ($x_gitlab_event === 'push') { |                 if ($x_gitlab_event === 'push') { | ||||||
|                     if ($application->isDeployable()) { |                     if ($application->isDeployable()) { | ||||||
|                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); |                         $is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files); | ||||||
|                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { |                         if ($is_watch_path_triggered || is_null($application->watch_paths)) { | ||||||
|                             ray('Deploying ' . $application->name . ' with branch ' . $branch); |                             ray('Deploying '.$application->name.' with branch '.$branch); | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             queue_application_deployment( |                             queue_application_deployment( | ||||||
|                                 application: $application, |                                 application: $application, | ||||||
| @ -163,7 +171,7 @@ class Gitlab extends Controller | |||||||
|                             'application_uuid' => $application->uuid, |                             'application_uuid' => $application->uuid, | ||||||
|                             'application_name' => $application->name, |                             'application_name' => $application->name, | ||||||
|                         ]); |                         ]); | ||||||
|                         ray('Deployments disabled for ' . $application->name); |                         ray('Deployments disabled for '.$application->name); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 if ($x_gitlab_event === 'merge_request') { |                 if ($x_gitlab_event === 'merge_request') { | ||||||
| @ -171,7 +179,7 @@ class Gitlab extends Controller | |||||||
|                         if ($application->isPRDeployable()) { |                         if ($application->isPRDeployable()) { | ||||||
|                             $deployment_uuid = new Cuid2(7); |                             $deployment_uuid = new Cuid2(7); | ||||||
|                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); |                             $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); | ||||||
|                             if (!$found) { |                             if (! $found) { | ||||||
|                                 ApplicationPreview::create([ |                                 ApplicationPreview::create([ | ||||||
|                                     'git_type' => 'gitlab', |                                     'git_type' => 'gitlab', | ||||||
|                                     'application_id' => $application->id, |                                     'application_id' => $application->id, | ||||||
| @ -188,7 +196,7 @@ class Gitlab extends Controller | |||||||
|                                 is_webhook: true, |                                 is_webhook: true, | ||||||
|                                 git_type: 'gitlab' |                                 git_type: 'gitlab' | ||||||
|                             ); |                             ); | ||||||
|                             ray('Deploying preview for ' . $application->name . ' with branch ' . $branch . ' and base branch ' . $base_branch . ' and pull request id ' . $pull_request_id); |                             ray('Deploying preview for '.$application->name.' with branch '.$branch.' and base branch '.$base_branch.' and pull request id '.$pull_request_id); | ||||||
|                             $return_payloads->push([ |                             $return_payloads->push([ | ||||||
|                                 'application' => $application->name, |                                 'application' => $application->name, | ||||||
|                                 'status' => 'success', |                                 'status' => 'success', | ||||||
| @ -200,9 +208,9 @@ class Gitlab extends Controller | |||||||
|                                 'status' => 'failed', |                                 'status' => 'failed', | ||||||
|                                 'message' => 'Preview deployments disabled', |                                 'message' => 'Preview deployments disabled', | ||||||
|                             ]); |                             ]); | ||||||
|                             ray('Preview deployments disabled for ' . $application->name); |                             ray('Preview deployments disabled for '.$application->name); | ||||||
|                         } |                         } | ||||||
|                     } else if ($action === 'closed' || $action === 'close' || $action === 'merge') { |                     } elseif ($action === 'closed' || $action === 'close' || $action === 'merge') { | ||||||
|                         $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); |                         $found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first(); | ||||||
|                         if ($found) { |                         if ($found) { | ||||||
|                             $found->delete(); |                             $found->delete(); | ||||||
| @ -214,6 +222,7 @@ class Gitlab extends Controller | |||||||
|                                 'status' => 'success', |                                 'status' => 'success', | ||||||
|                                 'message' => 'Preview Deployment closed', |                                 'message' => 'Preview Deployment closed', | ||||||
|                             ]); |                             ]); | ||||||
|  | 
 | ||||||
|                             return response($return_payloads); |                             return response($return_payloads); | ||||||
|                         } |                         } | ||||||
|                         $return_payloads->push([ |                         $return_payloads->push([ | ||||||
| @ -230,9 +239,11 @@ class Gitlab extends Controller | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return response($return_payloads); |             return response($return_payloads); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -26,16 +26,17 @@ class Stripe extends Controller | |||||||
|                 $epoch = now()->valueOf(); |                 $epoch = now()->valueOf(); | ||||||
|                 $data = [ |                 $data = [ | ||||||
|                     'attributes' => $request->attributes->all(), |                     'attributes' => $request->attributes->all(), | ||||||
|                     'request'    => $request->request->all(), |                     'request' => $request->request->all(), | ||||||
|                     'query'      => $request->query->all(), |                     'query' => $request->query->all(), | ||||||
|                     'server'     => $request->server->all(), |                     'server' => $request->server->all(), | ||||||
|                     'files'      => $request->files->all(), |                     'files' => $request->files->all(), | ||||||
|                     'cookies'    => $request->cookies->all(), |                     'cookies' => $request->cookies->all(), | ||||||
|                     'headers'    => $request->headers->all(), |                     'headers' => $request->headers->all(), | ||||||
|                     'content'    => $request->getContent(), |                     'content' => $request->getContent(), | ||||||
|                 ]; |                 ]; | ||||||
|                 $json = json_encode($data); |                 $json = json_encode($data); | ||||||
|                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Stripe::events_stripe", $json); |                 Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Stripe::events_stripe", $json); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $webhookSecret = config('subscription.stripe_webhook_secret'); |             $webhookSecret = config('subscription.stripe_webhook_secret'); | ||||||
| @ -48,7 +49,7 @@ class Stripe extends Controller | |||||||
|             ); |             ); | ||||||
|             $webhook = Webhook::create([ |             $webhook = Webhook::create([ | ||||||
|                 'type' => 'stripe', |                 'type' => 'stripe', | ||||||
|                 'payload' => $request->getContent() |                 'payload' => $request->getContent(), | ||||||
|             ]); |             ]); | ||||||
|             $type = data_get($event, 'type'); |             $type = data_get($event, 'type'); | ||||||
|             $data = data_get($event, 'data.object'); |             $data = data_get($event, 'data.object'); | ||||||
| @ -65,20 +66,20 @@ class Stripe extends Controller | |||||||
|                     $customerId = data_get($data, 'customer'); |                     $customerId = data_get($data, 'customer'); | ||||||
|                     $team = Team::find($teamId); |                     $team = Team::find($teamId); | ||||||
|                     $found = $team->members->where('id', $userId)->first(); |                     $found = $team->members->where('id', $userId)->first(); | ||||||
|                     if (!$found->isAdmin()) { |                     if (! $found->isAdmin()) { | ||||||
|                         send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); |                         send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); | ||||||
|                         throw new Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); |                         throw new Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); | ||||||
|                     } |                     } | ||||||
|                     $subscription = Subscription::where('team_id', $teamId)->first(); |                     $subscription = Subscription::where('team_id', $teamId)->first(); | ||||||
|                     if ($subscription) { |                     if ($subscription) { | ||||||
|                         send_internal_notification('Old subscription activated for team: ' . $teamId); |                         send_internal_notification('Old subscription activated for team: '.$teamId); | ||||||
|                         $subscription->update([ |                         $subscription->update([ | ||||||
|                             'stripe_subscription_id' => $subscriptionId, |                             'stripe_subscription_id' => $subscriptionId, | ||||||
|                             'stripe_customer_id' => $customerId, |                             'stripe_customer_id' => $customerId, | ||||||
|                             'stripe_invoice_paid' => true, |                             'stripe_invoice_paid' => true, | ||||||
|                         ]); |                         ]); | ||||||
|                     } else { |                     } else { | ||||||
|                         send_internal_notification('New subscription for team: ' . $teamId); |                         send_internal_notification('New subscription for team: '.$teamId); | ||||||
|                         Subscription::create([ |                         Subscription::create([ | ||||||
|                             'team_id' => $teamId, |                             'team_id' => $teamId, | ||||||
|                             'stripe_subscription_id' => $subscriptionId, |                             'stripe_subscription_id' => $subscriptionId, | ||||||
| @ -95,7 +96,7 @@ class Stripe extends Controller | |||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); |                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); | ||||||
|                     if (!$subscription) { |                     if (! $subscription) { | ||||||
|                         Sleep::for(5)->seconds(); |                         Sleep::for(5)->seconds(); | ||||||
|                         $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); |                         $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); | ||||||
|                     } |                     } | ||||||
| @ -106,34 +107,38 @@ class Stripe extends Controller | |||||||
|                 case 'invoice.payment_failed': |                 case 'invoice.payment_failed': | ||||||
|                     $customerId = data_get($data, 'customer'); |                     $customerId = data_get($data, 'customer'); | ||||||
|                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); |                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); | ||||||
|                     if (!$subscription) { |                     if (! $subscription) { | ||||||
|                         send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: ' . $customerId); |                         send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId); | ||||||
|  | 
 | ||||||
|                         return response('No subscription found in Coolify.'); |                         return response('No subscription found in Coolify.'); | ||||||
|                     } |                     } | ||||||
|                     $team = data_get($subscription, 'team'); |                     $team = data_get($subscription, 'team'); | ||||||
|                     if (!$team) { |                     if (! $team) { | ||||||
|                         send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: ' . $customerId); |                         send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId); | ||||||
|  | 
 | ||||||
|                         return response('No team found in Coolify.'); |                         return response('No team found in Coolify.'); | ||||||
|                     } |                     } | ||||||
|                     if (!$subscription->stripe_invoice_paid) { |                     if (! $subscription->stripe_invoice_paid) { | ||||||
|                         SubscriptionInvoiceFailedJob::dispatch($team); |                         SubscriptionInvoiceFailedJob::dispatch($team); | ||||||
|                         send_internal_notification('Invoice payment failed: ' . $customerId); |                         send_internal_notification('Invoice payment failed: '.$customerId); | ||||||
|                     } else { |                     } else { | ||||||
|                         send_internal_notification('Invoice payment failed but already paid: ' . $customerId); |                         send_internal_notification('Invoice payment failed but already paid: '.$customerId); | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|                 case 'payment_intent.payment_failed': |                 case 'payment_intent.payment_failed': | ||||||
|                     $customerId = data_get($data, 'customer'); |                     $customerId = data_get($data, 'customer'); | ||||||
|                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); |                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); | ||||||
|                     if (!$subscription) { |                     if (! $subscription) { | ||||||
|                         send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: ' . $customerId); |                         send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId); | ||||||
|  | 
 | ||||||
|                         return response('No subscription found in Coolify.'); |                         return response('No subscription found in Coolify.'); | ||||||
|                     } |                     } | ||||||
|                     if ($subscription->stripe_invoice_paid) { |                     if ($subscription->stripe_invoice_paid) { | ||||||
|                         send_internal_notification('payment_intent.payment_failed but invoice is active for customer: ' . $customerId); |                         send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId); | ||||||
|  | 
 | ||||||
|                         return; |                         return; | ||||||
|                     } |                     } | ||||||
|                     send_internal_notification('Subscription payment failed for customer: ' . $customerId); |                     send_internal_notification('Subscription payment failed for customer: '.$customerId); | ||||||
|                     break; |                     break; | ||||||
|                 case 'customer.subscription.updated': |                 case 'customer.subscription.updated': | ||||||
|                     $customerId = data_get($data, 'customer'); |                     $customerId = data_get($data, 'customer'); | ||||||
| @ -145,17 +150,19 @@ class Stripe extends Controller | |||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); |                     $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); | ||||||
|                     if (!$subscription) { |                     if (! $subscription) { | ||||||
|                         Sleep::for(5)->seconds(); |                         Sleep::for(5)->seconds(); | ||||||
|                         $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); |                         $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); | ||||||
|                     } |                     } | ||||||
|                     if (!$subscription) { |                     if (! $subscription) { | ||||||
|                         if ($status === 'incomplete_expired') { |                         if ($status === 'incomplete_expired') { | ||||||
|                             send_internal_notification('Subscription incomplete expired for customer: ' . $customerId); |                             send_internal_notification('Subscription incomplete expired for customer: '.$customerId); | ||||||
|                             return response("Subscription incomplete expired", 200); | 
 | ||||||
|  |                             return response('Subscription incomplete expired', 200); | ||||||
|                         } |                         } | ||||||
|                         send_internal_notification('No subscription found for: ' . $customerId); |                         send_internal_notification('No subscription found for: '.$customerId); | ||||||
|                         return response("No subscription found", 400); | 
 | ||||||
|  |                         return response('No subscription found', 400); | ||||||
|                     } |                     } | ||||||
|                     $trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended'); |                     $trialEndedAlready = data_get($subscription, 'stripe_trial_already_ended'); | ||||||
|                     $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); |                     $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); | ||||||
| @ -187,7 +194,7 @@ class Stripe extends Controller | |||||||
|                         $subscription->update([ |                         $subscription->update([ | ||||||
|                             'stripe_invoice_paid' => false, |                             'stripe_invoice_paid' => false, | ||||||
|                         ]); |                         ]); | ||||||
|                         send_internal_notification('Subscription paused or incomplete for customer: ' . $customerId); |                         send_internal_notification('Subscription paused or incomplete for customer: '.$customerId); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     // Trial ended but subscribed, reactive servers
 |                     // Trial ended but subscribed, reactive servers
 | ||||||
| @ -197,9 +204,9 @@ class Stripe extends Controller | |||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if ($feedback) { |                     if ($feedback) { | ||||||
|                         $reason = "Cancellation feedback for {$customerId}: '" . $feedback . "'"; |                         $reason = "Cancellation feedback for {$customerId}: '".$feedback."'"; | ||||||
|                         if ($comment) { |                         if ($comment) { | ||||||
|                             $reason .= ' with comment: \'' . $comment . "'"; |                             $reason .= ' with comment: \''.$comment."'"; | ||||||
|                         } |                         } | ||||||
|                         send_internal_notification($reason); |                         send_internal_notification($reason); | ||||||
|                     } |                     } | ||||||
| @ -207,7 +214,7 @@ class Stripe extends Controller | |||||||
|                         if ($cancelAtPeriodEnd) { |                         if ($cancelAtPeriodEnd) { | ||||||
|                             // send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id);
 |                             // send_internal_notification('Subscription cancelled at period end for team: ' . $subscription->team->id);
 | ||||||
|                         } else { |                         } else { | ||||||
|                             send_internal_notification('customer.subscription.updated for customer: ' . $customerId); |                             send_internal_notification('customer.subscription.updated for customer: '.$customerId); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
| @ -226,15 +233,15 @@ class Stripe extends Controller | |||||||
|                         'stripe_invoice_paid' => false, |                         'stripe_invoice_paid' => false, | ||||||
|                         'stripe_trial_already_ended' => true, |                         'stripe_trial_already_ended' => true, | ||||||
|                     ]); |                     ]); | ||||||
|                     send_internal_notification('customer.subscription.deleted for customer: ' . $customerId); |                     send_internal_notification('customer.subscription.deleted for customer: '.$customerId); | ||||||
|                     break; |                     break; | ||||||
|                 case 'customer.subscription.trial_will_end': |                 case 'customer.subscription.trial_will_end': | ||||||
|                     // Not used for now
 |                     // Not used for now
 | ||||||
|                     $customerId = data_get($data, 'customer'); |                     $customerId = data_get($data, 'customer'); | ||||||
|                     $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); |                     $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); | ||||||
|                     $team = data_get($subscription, 'team'); |                     $team = data_get($subscription, 'team'); | ||||||
|                     if (!$team) { |                     if (! $team) { | ||||||
|                         throw new Exception('No team found for subscription: ' . $subscription->id); |                         throw new Exception('No team found for subscription: '.$subscription->id); | ||||||
|                     } |                     } | ||||||
|                     SubscriptionTrialEndsSoonJob::dispatch($team); |                     SubscriptionTrialEndsSoonJob::dispatch($team); | ||||||
|                     break; |                     break; | ||||||
| @ -242,8 +249,8 @@ class Stripe extends Controller | |||||||
|                     $customerId = data_get($data, 'customer'); |                     $customerId = data_get($data, 'customer'); | ||||||
|                     $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); |                     $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); | ||||||
|                     $team = data_get($subscription, 'team'); |                     $team = data_get($subscription, 'team'); | ||||||
|                     if (!$team) { |                     if (! $team) { | ||||||
|                         throw new Exception('No team found for subscription: ' . $subscription->id); |                         throw new Exception('No team found for subscription: '.$subscription->id); | ||||||
|                     } |                     } | ||||||
|                     $team->trialEnded(); |                     $team->trialEnded(); | ||||||
|                     $subscription->update([ |                     $subscription->update([ | ||||||
| @ -251,19 +258,20 @@ class Stripe extends Controller | |||||||
|                         'stripe_invoice_paid' => false, |                         'stripe_invoice_paid' => false, | ||||||
|                     ]); |                     ]); | ||||||
|                     SubscriptionTrialEndedJob::dispatch($team); |                     SubscriptionTrialEndedJob::dispatch($team); | ||||||
|                     send_internal_notification('Subscription paused for customer: ' . $customerId); |                     send_internal_notification('Subscription paused for customer: '.$customerId); | ||||||
|                     break; |                     break; | ||||||
|                 default: |                 default: | ||||||
|                     // Unhandled event type
 |                     // Unhandled event type
 | ||||||
|             } |             } | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             if ($type !== 'payment_intent.payment_failed') { |             if ($type !== 'payment_intent.payment_failed') { | ||||||
|                 send_internal_notification("Subscription webhook ($type) failed: " . $e->getMessage()); |                 send_internal_notification("Subscription webhook ($type) failed: ".$e->getMessage()); | ||||||
|             } |             } | ||||||
|             $webhook->update([ |             $webhook->update([ | ||||||
|                 'status' => 'failed', |                 'status' => 'failed', | ||||||
|                 'failure_reason' => $e->getMessage(), |                 'failure_reason' => $e->getMessage(), | ||||||
|             ]); |             ]); | ||||||
|  | 
 | ||||||
|             return response($e->getMessage(), 400); |             return response($e->getMessage(), 400); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -17,41 +17,49 @@ class Waitlist extends Controller | |||||||
|         try { |         try { | ||||||
|             $found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first(); |             $found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first(); | ||||||
|             if ($found) { |             if ($found) { | ||||||
|                 if (!$found->verified) { |                 if (! $found->verified) { | ||||||
|                     if ($found->created_at > now()->subMinutes(config('constants.waitlist.expiration'))) { |                     if ($found->created_at > now()->subMinutes(config('constants.waitlist.expiration'))) { | ||||||
|                         $found->verified = true; |                         $found->verified = true; | ||||||
|                         $found->save(); |                         $found->save(); | ||||||
|                         send_internal_notification('Waitlist confirmed: ' . $email); |                         send_internal_notification('Waitlist confirmed: '.$email); | ||||||
|  | 
 | ||||||
|                         return 'Thank you for confirming your email address. We will notify you when you are next in line.'; |                         return 'Thank you for confirming your email address. We will notify you when you are next in line.'; | ||||||
|                     } else { |                     } else { | ||||||
|                         $found->delete(); |                         $found->delete(); | ||||||
|                         send_internal_notification('Waitlist expired: ' . $email); |                         send_internal_notification('Waitlist expired: '.$email); | ||||||
|  | 
 | ||||||
|                         return 'Your confirmation code has expired. Please sign up again.'; |                         return 'Your confirmation code has expired. Please sign up again.'; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return redirect()->route('dashboard'); |             return redirect()->route('dashboard'); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             send_internal_notification('Waitlist confirmation failed: ' . $e->getMessage()); |             send_internal_notification('Waitlist confirmation failed: '.$e->getMessage()); | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return redirect()->route('dashboard'); |             return redirect()->route('dashboard'); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function cancel(Request $request) |     public function cancel(Request $request) | ||||||
|     { |     { | ||||||
|         $email = request()->get('email'); |         $email = request()->get('email'); | ||||||
|         $confirmation_code = request()->get('confirmation_code'); |         $confirmation_code = request()->get('confirmation_code'); | ||||||
|         try { |         try { | ||||||
|             $found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first(); |             $found = ModelsWaitlist::where('uuid', $confirmation_code)->where('email', $email)->first(); | ||||||
|             if ($found && !$found->verified) { |             if ($found && ! $found->verified) { | ||||||
|                 $found->delete(); |                 $found->delete(); | ||||||
|                 send_internal_notification('Waitlist cancelled: ' . $email); |                 send_internal_notification('Waitlist cancelled: '.$email); | ||||||
|  | 
 | ||||||
|                 return 'Your email address has been removed from the waitlist.'; |                 return 'Your email address has been removed from the waitlist.'; | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return redirect()->route('dashboard'); |             return redirect()->route('dashboard'); | ||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|             send_internal_notification('Waitlist cancellation failed: ' . $e->getMessage()); |             send_internal_notification('Waitlist cancellation failed: '.$e->getMessage()); | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return redirect()->route('dashboard'); |             return redirect()->route('dashboard'); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ class Kernel extends HttpKernel | |||||||
| 
 | 
 | ||||||
|         'api' => [ |         'api' => [ | ||||||
|             // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
 |             // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
 | ||||||
|             \Illuminate\Routing\Middleware\ThrottleRequests::class . ':api', |             \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', | ||||||
|             \Illuminate\Routing\Middleware\SubstituteBindings::class, |             \Illuminate\Routing\Middleware\SubstituteBindings::class, | ||||||
|         ], |         ], | ||||||
|     ]; |     ]; | ||||||
|  | |||||||
| @ -20,16 +20,19 @@ class CheckForcePasswordReset | |||||||
|                 auth()->logout(); |                 auth()->logout(); | ||||||
|                 request()->session()->invalidate(); |                 request()->session()->invalidate(); | ||||||
|                 request()->session()->regenerateToken(); |                 request()->session()->regenerateToken(); | ||||||
|  | 
 | ||||||
|                 return $next($request); |                 return $next($request); | ||||||
|             } |             } | ||||||
|             $force_password_reset = auth()->user()->force_password_reset; |             $force_password_reset = auth()->user()->force_password_reset; | ||||||
|             if ($force_password_reset) { |             if ($force_password_reset) { | ||||||
|                 if ($request->routeIs('auth.force-password-reset') || $request->path() === 'force-password-reset' || $request->path() === 'livewire/update' ||  $request->path() === 'logout') { |                 if ($request->routeIs('auth.force-password-reset') || $request->path() === 'force-password-reset' || $request->path() === 'livewire/update' || $request->path() === 'logout') { | ||||||
|                     return $next($request); |                     return $next($request); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 return redirect()->route('auth.force-password-reset'); |                 return redirect()->route('auth.force-password-reset'); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $next($request); |         return $next($request); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,8 +5,8 @@ namespace App\Http\Middleware; | |||||||
| use App\Providers\RouteServiceProvider; | use App\Providers\RouteServiceProvider; | ||||||
| use Closure; | use Closure; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Symfony\Component\HttpFoundation\Response; |  | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
|  | use Symfony\Component\HttpFoundation\Response; | ||||||
| 
 | 
 | ||||||
| class DecideWhatToDoWithUser | class DecideWhatToDoWithUser | ||||||
| { | { | ||||||
| @ -16,33 +16,37 @@ class DecideWhatToDoWithUser | |||||||
|             $currentTeam = auth()->user()?->recreate_personal_team(); |             $currentTeam = auth()->user()?->recreate_personal_team(); | ||||||
|             refreshSession($currentTeam); |             refreshSession($currentTeam); | ||||||
|         } |         } | ||||||
|         if(auth()?->user()?->currentTeam()){ |         if (auth()?->user()?->currentTeam()) { | ||||||
|             refreshSession(auth()->user()->currentTeam()); |             refreshSession(auth()->user()->currentTeam()); | ||||||
|         } |         } | ||||||
|         if (!auth()->user() || !isCloud() || isInstanceAdmin()) { |         if (! auth()->user() || ! isCloud() || isInstanceAdmin()) { | ||||||
|             if (!isCloud() && showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) { |             if (! isCloud() && showBoarding() && ! in_array($request->path(), allowedPathsForBoardingAccounts())) { | ||||||
|                 return redirect()->route('onboarding'); |                 return redirect()->route('onboarding'); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return $next($request); |             return $next($request); | ||||||
|         } |         } | ||||||
|         if (!auth()->user()->hasVerifiedEmail()) { |         if (! auth()->user()->hasVerifiedEmail()) { | ||||||
|             if ($request->path() === 'verify' || in_array($request->path(), allowedPathsForInvalidAccounts()) || $request->routeIs('verify.verify')) { |             if ($request->path() === 'verify' || in_array($request->path(), allowedPathsForInvalidAccounts()) || $request->routeIs('verify.verify')) { | ||||||
|                 return $next($request); |                 return $next($request); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return redirect()->route('verify.email'); |             return redirect()->route('verify.email'); | ||||||
|         } |         } | ||||||
|         if (!isSubscriptionActive() && !isSubscriptionOnGracePeriod()) { |         if (! isSubscriptionActive() && ! isSubscriptionOnGracePeriod()) { | ||||||
|             if (!in_array($request->path(), allowedPathsForUnsubscribedAccounts())) { |             if (! in_array($request->path(), allowedPathsForUnsubscribedAccounts())) { | ||||||
|                 if (Str::startsWith($request->path(), 'invitations')) { |                 if (Str::startsWith($request->path(), 'invitations')) { | ||||||
|                     return $next($request); |                     return $next($request); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 return redirect()->route('subscription.index'); |                 return redirect()->route('subscription.index'); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) { |         if (showBoarding() && ! in_array($request->path(), allowedPathsForBoardingAccounts())) { | ||||||
|             if (Str::startsWith($request->path(), 'invitations')) { |             if (Str::startsWith($request->path(), 'invitations')) { | ||||||
|                 return $next($request); |                 return $next($request); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|             return redirect()->route('onboarding'); |             return redirect()->route('onboarding'); | ||||||
|         } |         } | ||||||
|         if (auth()->user()->hasVerifiedEmail() && $request->path() === 'verify') { |         if (auth()->user()->hasVerifiedEmail() && $request->path() === 'verify') { | ||||||
| @ -51,6 +55,7 @@ class DecideWhatToDoWithUser | |||||||
|         if (isSubscriptionActive() && $request->routeIs('subscription.index')) { |         if (isSubscriptionActive() && $request->routeIs('subscription.index')) { | ||||||
|             return redirect(RouteServiceProvider::HOME); |             return redirect(RouteServiceProvider::HOME); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $next($request); |         return $next($request); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,6 +13,6 @@ class PreventRequestsDuringMaintenance extends Middleware | |||||||
|      */ |      */ | ||||||
|     protected $except = [ |     protected $except = [ | ||||||
|         'webhooks/*', |         'webhooks/*', | ||||||
|         '/api/health' |         '/api/health', | ||||||
|     ]; |     ]; | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ class RedirectIfAuthenticated | |||||||
|     /** |     /** | ||||||
|      * Handle an incoming request. |      * Handle an incoming request. | ||||||
|      * |      * | ||||||
|      * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next |      * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next | ||||||
|      */ |      */ | ||||||
|     public function handle(Request $request, Closure $next, string ...$guards): Response |     public function handle(Request $request, Closure $next, string ...$guards): Response | ||||||
|     { |     { | ||||||
| @ -24,6 +24,7 @@ class RedirectIfAuthenticated | |||||||
|                 return redirect(RouteServiceProvider::HOME); |                 return redirect(RouteServiceProvider::HOME); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         return $next($request); |         return $next($request); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ class TrustProxies extends Middleware | |||||||
|      * @var int |      * @var int | ||||||
|      */ |      */ | ||||||
|     protected $headers = |     protected $headers = | ||||||
|     Request::HEADER_X_FORWARDED_FOR | |         Request::HEADER_X_FORWARDED_FOR | | ||||||
|         Request::HEADER_X_FORWARDED_HOST | |         Request::HEADER_X_FORWARDED_HOST | | ||||||
|         Request::HEADER_X_FORWARDED_PORT | |         Request::HEADER_X_FORWARDED_PORT | | ||||||
|         Request::HEADER_X_FORWARDED_PROTO | |         Request::HEADER_X_FORWARDED_PROTO | | ||||||
|  | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -12,11 +12,12 @@ use Illuminate\Foundation\Bus\Dispatchable; | |||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| 
 | 
 | ||||||
| class ApplicationPullRequestUpdateJob implements ShouldQueue, ShouldBeEncrypted | class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
|     public string $build_logs_url; |     public string $build_logs_url; | ||||||
|  | 
 | ||||||
|     public string $body; |     public string $body; | ||||||
| 
 | 
 | ||||||
|     public function __construct( |     public function __construct( | ||||||
| @ -32,25 +33,27 @@ class ApplicationPullRequestUpdateJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|         try { |         try { | ||||||
|             if ($this->application->is_public_repository()) { |             if ($this->application->is_public_repository()) { | ||||||
|                 ray('Public repository. Skipping comment update.'); |                 ray('Public repository. Skipping comment update.'); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             if ($this->status === ProcessStatus::CLOSED) { |             if ($this->status === ProcessStatus::CLOSED) { | ||||||
|                 $this->delete_comment(); |                 $this->delete_comment(); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } else if ($this->status === ProcessStatus::IN_PROGRESS) { |             } elseif ($this->status === ProcessStatus::IN_PROGRESS) { | ||||||
|                 $this->body = "The preview deployment is in progress. 🟡\n\n"; |                 $this->body = "The preview deployment is in progress. 🟡\n\n"; | ||||||
|             } else if ($this->status === ProcessStatus::FINISHED) { |             } elseif ($this->status === ProcessStatus::FINISHED) { | ||||||
|                 $this->body = "The preview deployment is ready. 🟢\n\n"; |                 $this->body = "The preview deployment is ready. 🟢\n\n"; | ||||||
|                 if ($this->preview->fqdn) { |                 if ($this->preview->fqdn) { | ||||||
|                     $this->body .= "[Open Preview]({$this->preview->fqdn}) | "; |                     $this->body .= "[Open Preview]({$this->preview->fqdn}) | "; | ||||||
|                 } |                 } | ||||||
|             } else if ($this->status === ProcessStatus::ERROR) { |             } elseif ($this->status === ProcessStatus::ERROR) { | ||||||
|                 $this->body = "The preview deployment failed. 🔴\n\n"; |                 $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->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 .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n"; | ||||||
|             $this->body .= "Last updated at: " . now()->toDateTimeString() . " CET"; |             $this->body .= 'Last updated at: '.now()->toDateTimeString().' CET'; | ||||||
| 
 | 
 | ||||||
|             ray('Updating comment', $this->body); |             ray('Updating comment', $this->body); | ||||||
|             if ($this->preview->pull_request_issue_comment_id) { |             if ($this->preview->pull_request_issue_comment_id) { | ||||||
| @ -60,6 +63,7 @@ class ApplicationPullRequestUpdateJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             } |             } | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             ray($e); |             ray($e); | ||||||
|  | 
 | ||||||
|             return $e; |             return $e; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -83,6 +87,7 @@ class ApplicationPullRequestUpdateJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|         $this->preview->pull_request_issue_comment_id = $data['id']; |         $this->preview->pull_request_issue_comment_id = $data['id']; | ||||||
|         $this->preview->save(); |         $this->preview->save(); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function delete_comment() |     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->preview->pull_request_issue_comment_id}", method: 'delete'); | ||||||
|  | |||||||
| @ -10,19 +10,23 @@ use Illuminate\Foundation\Bus\Dispatchable; | |||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| 
 | 
 | ||||||
| 
 | class ApplicationRestartJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| class ApplicationRestartJob implements ShouldQueue, ShouldBeEncrypted |  | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, ExecuteRemoteCommand; |     use Dispatchable, ExecuteRemoteCommand, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
|     public $timeout = 3600; |     public $timeout = 3600; | ||||||
|  | 
 | ||||||
|     public $tries = 1; |     public $tries = 1; | ||||||
|  | 
 | ||||||
|     public string $applicationDeploymentQueueId; |     public string $applicationDeploymentQueueId; | ||||||
|  | 
 | ||||||
|     public function __construct(string $applicationDeploymentQueueId) |     public function __construct(string $applicationDeploymentQueueId) | ||||||
|     { |     { | ||||||
|         $this->applicationDeploymentQueueId = $applicationDeploymentQueueId; |         $this->applicationDeploymentQueueId = $applicationDeploymentQueueId; | ||||||
|     } |     } | ||||||
|     public function handle() { | 
 | ||||||
|  |     public function handle() | ||||||
|  |     { | ||||||
|         ray('Restarting application'); |         ray('Restarting application'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,13 +15,14 @@ use Illuminate\Queue\Middleware\WithoutOverlapping; | |||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| use Illuminate\Support\Sleep; | use Illuminate\Support\Sleep; | ||||||
| 
 | 
 | ||||||
| class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted | class CheckLogDrainContainerJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
|     public function __construct(public Server $server) |     public function __construct(public Server $server) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function middleware(): array |     public function middleware(): array | ||||||
|     { |     { | ||||||
|         return [(new WithoutOverlapping($this->server->id))->dontRelease()]; |         return [(new WithoutOverlapping($this->server->id))->dontRelease()]; | ||||||
| @ -31,6 +32,7 @@ class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|     { |     { | ||||||
|         return $this->server->id; |         return $this->server->id; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function healthcheck() |     public function healthcheck() | ||||||
|     { |     { | ||||||
|         $status = instant_remote_process(["docker inspect --format='{{json .State.Status}}' coolify-log-drain"], $this->server, false); |         $status = instant_remote_process(["docker inspect --format='{{json .State.Status}}' coolify-log-drain"], $this->server, false); | ||||||
| @ -40,15 +42,16 @@ class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         // ray("checking log drain statuses for {$this->server->id}");
 |         // ray("checking log drain statuses for {$this->server->id}");
 | ||||||
|         try { |         try { | ||||||
|             if (!$this->server->isFunctional()) { |             if (! $this->server->isFunctional()) { | ||||||
|                 return; |                 return; | ||||||
|             }; |             } | ||||||
|             $containers = instant_remote_process(["docker container ls -q"], $this->server, false); |             $containers = instant_remote_process(['docker container ls -q'], $this->server, false); | ||||||
|             if (!$containers) { |             if (! $containers) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server); |             $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server); | ||||||
| @ -57,7 +60,7 @@ class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             $foundLogDrainContainer = $containers->filter(function ($value, $key) { |             $foundLogDrainContainer = $containers->filter(function ($value, $key) { | ||||||
|                 return data_get($value, 'Name') === '/coolify-log-drain'; |                 return data_get($value, 'Name') === '/coolify-log-drain'; | ||||||
|             })->first(); |             })->first(); | ||||||
|             if (!$foundLogDrainContainer || !$this->healthcheck()) { |             if (! $foundLogDrainContainer || ! $this->healthcheck()) { | ||||||
|                 ray('Log drain container not found or unhealthy. Restarting...'); |                 ray('Log drain container not found or unhealthy. Restarting...'); | ||||||
|                 InstallLogDrain::run($this->server); |                 InstallLogDrain::run($this->server); | ||||||
|                 Sleep::for(10)->seconds(); |                 Sleep::for(10)->seconds(); | ||||||
| @ -66,9 +69,10 @@ class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                         $this->server->team?->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); |                         $this->server->team?->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); | ||||||
|                         $this->server->update(['log_drain_notification_sent' => false]); |                         $this->server->update(['log_drain_notification_sent' => false]); | ||||||
|                     } |                     } | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 if (!$this->server->log_drain_notification_sent) { |                 if (! $this->server->log_drain_notification_sent) { | ||||||
|                     ray('Log drain container still unhealthy. Sending notification...'); |                     ray('Log drain container still unhealthy. Sending notification...'); | ||||||
|                     // $this->server->team?->notify(new ContainerStopped('Coolify Log Drainer', $this->server, null));
 |                     // $this->server->team?->notify(new ContainerStopped('Coolify Log Drainer', $this->server, null));
 | ||||||
|                     $this->server->update(['log_drain_notification_sent' => true]); |                     $this->server->update(['log_drain_notification_sent' => true]); | ||||||
| @ -80,8 +84,11 @@ class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             if (!isCloud()) send_internal_notification("CheckLogDrainContainerJob failed on ({$this->server->id}) with: " . $e->getMessage()); |             if (! isCloud()) { | ||||||
|  |                 send_internal_notification("CheckLogDrainContainerJob failed on ({$this->server->id}) with: ".$e->getMessage()); | ||||||
|  |             } | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|  | 
 | ||||||
|             return handleError($e); |             return handleError($e); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ use Illuminate\Foundation\Bus\Dispatchable; | |||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| 
 | 
 | ||||||
| class CheckResaleLicenseJob implements ShouldQueue, ShouldBeEncrypted | class CheckResaleLicenseJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
| @ -23,7 +23,7 @@ class CheckResaleLicenseJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|         try { |         try { | ||||||
|             CheckResaleLicense::run(); |             CheckResaleLicense::run(); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             send_internal_notification('CheckResaleLicenseJob failed with: ' . $e->getMessage()); |             send_internal_notification('CheckResaleLicenseJob failed with: '.$e->getMessage()); | ||||||
|             ray($e); |             ray($e); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ use Illuminate\Foundation\Bus\Dispatchable; | |||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| 
 | 
 | ||||||
| class CleanupHelperContainersJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncrypted | class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
| @ -22,18 +22,18 @@ class CleanupHelperContainersJob implements ShouldQueue, ShouldBeUnique, ShouldB | |||||||
|     public function handle(): void |     public function handle(): void | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             ray('Cleaning up helper containers on ' . $this->server->name); |             ray('Cleaning up helper containers on '.$this->server->name); | ||||||
|             $containers = instant_remote_process(['docker container ps --filter "ancestor=ghcr.io/coollabsio/coolify-helper:next" --filter "ancestor=ghcr.io/coollabsio/coolify-helper:latest" --format \'{{json .}}\''], $this->server, false); |             $containers = instant_remote_process(['docker container ps --filter "ancestor=ghcr.io/coollabsio/coolify-helper:next" --filter "ancestor=ghcr.io/coollabsio/coolify-helper:latest" --format \'{{json .}}\''], $this->server, false); | ||||||
|             $containers = format_docker_command_output_to_json($containers); |             $containers = format_docker_command_output_to_json($containers); | ||||||
|             if ($containers->count() > 0) { |             if ($containers->count() > 0) { | ||||||
|                 foreach ($containers as $container) { |                 foreach ($containers as $container) { | ||||||
|                     $containerId = data_get($container,'ID'); |                     $containerId = data_get($container, 'ID'); | ||||||
|                     ray('Removing container ' . $containerId); |                     ray('Removing container '.$containerId); | ||||||
|                     instant_remote_process(['docker container rm -f ' . $containerId], $this->server, false); |                     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()); |             send_internal_notification('CleanupHelperContainersJob failed with error: '.$e->getMessage()); | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ use Illuminate\Foundation\Bus\Dispatchable; | |||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| 
 | 
 | ||||||
| class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncrypted | class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
| @ -31,13 +31,13 @@ class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique, ShouldBeE | |||||||
|         try { |         try { | ||||||
|             // $this->cleanup_waitlist();
 |             // $this->cleanup_waitlist();
 | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage()); |             send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage()); | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|         } |         } | ||||||
|         try { |         try { | ||||||
|             $this->cleanup_invitation_link(); |             $this->cleanup_invitation_link(); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             send_internal_notification('CleanupInstanceStuffsJob failed with error: ' . $e->getMessage()); |             send_internal_notification('CleanupInstanceStuffsJob failed with error: '.$e->getMessage()); | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -49,6 +49,7 @@ class CleanupInstanceStuffsJob implements ShouldQueue, ShouldBeUnique, ShouldBeE | |||||||
|             $item->delete(); |             $item->delete(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function cleanup_invitation_link() |     private function cleanup_invitation_link() | ||||||
|     { |     { | ||||||
|         $invitation = TeamInvitation::all(); |         $invitation = TeamInvitation::all(); | ||||||
|  | |||||||
| @ -12,18 +12,21 @@ use Illuminate\Queue\InteractsWithQueue; | |||||||
| use Illuminate\Queue\Middleware\WithoutOverlapping; | use Illuminate\Queue\Middleware\WithoutOverlapping; | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| 
 | 
 | ||||||
| class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted | class ContainerStatusJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
|     public $tries = 4; |     public $tries = 4; | ||||||
|  | 
 | ||||||
|     public function backoff(): int |     public function backoff(): int | ||||||
|     { |     { | ||||||
|         return isDev() ? 1 : 3; |         return isDev() ? 1 : 3; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function __construct(public Server $server) |     public function __construct(public Server $server) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function middleware(): array |     public function middleware(): array | ||||||
|     { |     { | ||||||
|         return [(new WithoutOverlapping($this->server->uuid))]; |         return [(new WithoutOverlapping($this->server->uuid))]; | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ use Illuminate\Queue\InteractsWithQueue; | |||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| use Spatie\Activitylog\Models\Activity; | use Spatie\Activitylog\Models\Activity; | ||||||
| 
 | 
 | ||||||
| class CoolifyTask implements ShouldQueue, ShouldBeEncrypted | class CoolifyTask implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
| @ -20,7 +20,7 @@ class CoolifyTask implements ShouldQueue, ShouldBeEncrypted | |||||||
|      */ |      */ | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         public Activity $activity, |         public Activity $activity, | ||||||
|         public bool     $ignore_errors = false, |         public bool $ignore_errors = false, | ||||||
|         public $call_event_on_finish = null, |         public $call_event_on_finish = null, | ||||||
|         public $call_event_data = null |         public $call_event_data = null | ||||||
|     ) { |     ) { | ||||||
| @ -35,7 +35,7 @@ class CoolifyTask implements ShouldQueue, ShouldBeEncrypted | |||||||
|             'activity' => $this->activity, |             'activity' => $this->activity, | ||||||
|             'ignore_errors' => $this->ignore_errors, |             'ignore_errors' => $this->ignore_errors, | ||||||
|             'call_event_on_finish' => $this->call_event_on_finish, |             'call_event_on_finish' => $this->call_event_on_finish, | ||||||
|             'call_event_data' => $this->call_event_data |             'call_event_data' => $this->call_event_data, | ||||||
|         ]); |         ]); | ||||||
| 
 | 
 | ||||||
|         $remote_process(); |         $remote_process(); | ||||||
|  | |||||||
| @ -25,26 +25,37 @@ use Illuminate\Queue\InteractsWithQueue; | |||||||
| use Illuminate\Queue\Middleware\WithoutOverlapping; | use Illuminate\Queue\Middleware\WithoutOverlapping; | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Throwable; |  | ||||||
| 
 | 
 | ||||||
| class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
|     public ?Team $team = null; |     public ?Team $team = null; | ||||||
|  | 
 | ||||||
|     public Server $server; |     public Server $server; | ||||||
|  | 
 | ||||||
|     public ScheduledDatabaseBackup $backup; |     public ScheduledDatabaseBackup $backup; | ||||||
|  | 
 | ||||||
|     public StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database; |     public StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database; | ||||||
| 
 | 
 | ||||||
|     public ?string $container_name = null; |     public ?string $container_name = null; | ||||||
|  | 
 | ||||||
|     public ?string $directory_name = null; |     public ?string $directory_name = null; | ||||||
|  | 
 | ||||||
|     public ?ScheduledDatabaseBackupExecution $backup_log = null; |     public ?ScheduledDatabaseBackupExecution $backup_log = null; | ||||||
|  | 
 | ||||||
|     public string $backup_status = 'failed'; |     public string $backup_status = 'failed'; | ||||||
|  | 
 | ||||||
|     public ?string $backup_location = null; |     public ?string $backup_location = null; | ||||||
|  | 
 | ||||||
|     public string $backup_dir; |     public string $backup_dir; | ||||||
|  | 
 | ||||||
|     public string $backup_file; |     public string $backup_file; | ||||||
|  | 
 | ||||||
|     public int $size = 0; |     public int $size = 0; | ||||||
|  | 
 | ||||||
|     public ?string $backup_output = null; |     public ?string $backup_output = null; | ||||||
|  | 
 | ||||||
|     public ?S3Storage $s3 = null; |     public ?S3Storage $s3 = null; | ||||||
| 
 | 
 | ||||||
|     public function __construct($backup) |     public function __construct($backup) | ||||||
| @ -84,11 +95,13 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                 $this->backup->update(['status' => 'failed']); |                 $this->backup->update(['status' => 'failed']); | ||||||
|                 StopDatabase::run($this->database); |                 StopDatabase::run($this->database); | ||||||
|                 $this->database->delete(); |                 $this->database->delete(); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $status = Str::of(data_get($this->database, 'status')); |             $status = Str::of(data_get($this->database, 'status')); | ||||||
|             if (!$status->startsWith('running') && $this->database->id !== 0) { |             if (! $status->startsWith('running') && $this->database->id !== 0) { | ||||||
|                 ray('database not running'); |                 ray('database not running'); | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') { |             if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') { | ||||||
| @ -97,7 +110,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                 $serviceName = str($this->database->service->name)->slug(); |                 $serviceName = str($this->database->service->name)->slug(); | ||||||
|                 if (str($databaseType)->contains('postgres')) { |                 if (str($databaseType)->contains('postgres')) { | ||||||
|                     $this->container_name = "{$this->database->name}-$serviceUuid"; |                     $this->container_name = "{$this->database->name}-$serviceUuid"; | ||||||
|                     $this->directory_name = $serviceName . '-' . $this->container_name; |                     $this->directory_name = $serviceName.'-'.$this->container_name; | ||||||
|                     $commands[] = "docker exec $this->container_name env | grep POSTGRES_"; |                     $commands[] = "docker exec $this->container_name env | grep POSTGRES_"; | ||||||
|                     $envs = instant_remote_process($commands, $this->server); |                     $envs = instant_remote_process($commands, $this->server); | ||||||
|                     $envs = str($envs)->explode("\n"); |                     $envs = str($envs)->explode("\n"); | ||||||
| @ -120,9 +133,9 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                     } else { |                     } else { | ||||||
|                         $databasesToBackup = $this->database->postgres_user; |                         $databasesToBackup = $this->database->postgres_user; | ||||||
|                     } |                     } | ||||||
|                 } else if (str($databaseType)->contains('mysql')) { |                 } elseif (str($databaseType)->contains('mysql')) { | ||||||
|                     $this->container_name = "{$this->database->name}-$serviceUuid"; |                     $this->container_name = "{$this->database->name}-$serviceUuid"; | ||||||
|                     $this->directory_name = $serviceName . '-' . $this->container_name; |                     $this->directory_name = $serviceName.'-'.$this->container_name; | ||||||
|                     $commands[] = "docker exec $this->container_name env | grep MYSQL_"; |                     $commands[] = "docker exec $this->container_name env | grep MYSQL_"; | ||||||
|                     $envs = instant_remote_process($commands, $this->server); |                     $envs = instant_remote_process($commands, $this->server); | ||||||
|                     $envs = str($envs)->explode("\n"); |                     $envs = str($envs)->explode("\n"); | ||||||
| @ -143,9 +156,9 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                     } else { |                     } else { | ||||||
|                         throw new \Exception('MYSQL_DATABASE not found'); |                         throw new \Exception('MYSQL_DATABASE not found'); | ||||||
|                     } |                     } | ||||||
|                 } else if (str($databaseType)->contains('mariadb')) { |                 } elseif (str($databaseType)->contains('mariadb')) { | ||||||
|                     $this->container_name = "{$this->database->name}-$serviceUuid"; |                     $this->container_name = "{$this->database->name}-$serviceUuid"; | ||||||
|                     $this->directory_name = $serviceName . '-' . $this->container_name; |                     $this->directory_name = $serviceName.'-'.$this->container_name; | ||||||
|                     $commands[] = "docker exec $this->container_name env"; |                     $commands[] = "docker exec $this->container_name env"; | ||||||
|                     $envs = instant_remote_process($commands, $this->server); |                     $envs = instant_remote_process($commands, $this->server); | ||||||
|                     $envs = str($envs)->explode("\n"); |                     $envs = str($envs)->explode("\n"); | ||||||
| @ -184,7 +197,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             } else { |             } else { | ||||||
|                 $databaseName = str($this->database->name)->slug()->value(); |                 $databaseName = str($this->database->name)->slug()->value(); | ||||||
|                 $this->container_name = $this->database->uuid; |                 $this->container_name = $this->database->uuid; | ||||||
|                 $this->directory_name = $databaseName . '-' . $this->container_name; |                 $this->directory_name = $databaseName.'-'.$this->container_name; | ||||||
|                 $databaseType = $this->database->type(); |                 $databaseType = $this->database->type(); | ||||||
|                 $databasesToBackup = data_get($this->backup, 'databases_to_backup'); |                 $databasesToBackup = data_get($this->backup, 'databases_to_backup'); | ||||||
|             } |             } | ||||||
| @ -192,11 +205,11 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             if (is_null($databasesToBackup)) { |             if (is_null($databasesToBackup)) { | ||||||
|                 if (str($databaseType)->contains('postgres')) { |                 if (str($databaseType)->contains('postgres')) { | ||||||
|                     $databasesToBackup = [$this->database->postgres_db]; |                     $databasesToBackup = [$this->database->postgres_db]; | ||||||
|                 } else if (str($databaseType)->contains('mongodb')) { |                 } elseif (str($databaseType)->contains('mongodb')) { | ||||||
|                     $databasesToBackup = ['*']; |                     $databasesToBackup = ['*']; | ||||||
|                 } else if (str($databaseType)->contains('mysql')) { |                 } elseif (str($databaseType)->contains('mysql')) { | ||||||
|                     $databasesToBackup = [$this->database->mysql_database]; |                     $databasesToBackup = [$this->database->mysql_database]; | ||||||
|                 } else if (str($databaseType)->contains('mariadb')) { |                 } elseif (str($databaseType)->contains('mariadb')) { | ||||||
|                     $databasesToBackup = [$this->database->mariadb_database]; |                     $databasesToBackup = [$this->database->mariadb_database]; | ||||||
|                 } else { |                 } else { | ||||||
|                     return; |                     return; | ||||||
| @ -206,16 +219,16 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                     // Format: db1,db2,db3
 |                     // Format: db1,db2,db3
 | ||||||
|                     $databasesToBackup = explode(',', $databasesToBackup); |                     $databasesToBackup = explode(',', $databasesToBackup); | ||||||
|                     $databasesToBackup = array_map('trim', $databasesToBackup); |                     $databasesToBackup = array_map('trim', $databasesToBackup); | ||||||
|                 } else if (str($databaseType)->contains('mongodb')) { |                 } elseif (str($databaseType)->contains('mongodb')) { | ||||||
|                     // Format: db1:collection1,collection2|db2:collection3,collection4
 |                     // Format: db1:collection1,collection2|db2:collection3,collection4
 | ||||||
|                     $databasesToBackup = explode('|', $databasesToBackup); |                     $databasesToBackup = explode('|', $databasesToBackup); | ||||||
|                     $databasesToBackup = array_map('trim', $databasesToBackup); |                     $databasesToBackup = array_map('trim', $databasesToBackup); | ||||||
|                     ray($databasesToBackup); |                     ray($databasesToBackup); | ||||||
|                 } else if (str($databaseType)->contains('mysql')) { |                 } elseif (str($databaseType)->contains('mysql')) { | ||||||
|                     // Format: db1,db2,db3
 |                     // Format: db1,db2,db3
 | ||||||
|                     $databasesToBackup = explode(',', $databasesToBackup); |                     $databasesToBackup = explode(',', $databasesToBackup); | ||||||
|                     $databasesToBackup = array_map('trim', $databasesToBackup); |                     $databasesToBackup = array_map('trim', $databasesToBackup); | ||||||
|                 } else if (str($databaseType)->contains('mariadb')) { |                 } elseif (str($databaseType)->contains('mariadb')) { | ||||||
|                     // Format: db1,db2,db3
 |                     // Format: db1,db2,db3
 | ||||||
|                     $databasesToBackup = explode(',', $databasesToBackup); |                     $databasesToBackup = explode(',', $databasesToBackup); | ||||||
|                     $databasesToBackup = array_map('trim', $databasesToBackup); |                     $databasesToBackup = array_map('trim', $databasesToBackup); | ||||||
| @ -223,28 +236,28 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             $this->backup_dir = backup_dir() . "/databases/" . Str::of($this->team->name)->slug() . '-' . $this->team->id . '/' . $this->directory_name; |             $this->backup_dir = backup_dir().'/databases/'.Str::of($this->team->name)->slug().'-'.$this->team->id.'/'.$this->directory_name; | ||||||
| 
 | 
 | ||||||
|             if ($this->database->name === 'coolify-db') { |             if ($this->database->name === 'coolify-db') { | ||||||
|                 $databasesToBackup = ['coolify']; |                 $databasesToBackup = ['coolify']; | ||||||
|                 $this->directory_name = $this->container_name = "coolify-db"; |                 $this->directory_name = $this->container_name = 'coolify-db'; | ||||||
|                 $ip = Str::slug($this->server->ip); |                 $ip = Str::slug($this->server->ip); | ||||||
|                 $this->backup_dir = backup_dir() . "/coolify" . "/coolify-db-$ip"; |                 $this->backup_dir = backup_dir().'/coolify'."/coolify-db-$ip"; | ||||||
|             } |             } | ||||||
|             foreach ($databasesToBackup as $database) { |             foreach ($databasesToBackup as $database) { | ||||||
|                 $size = 0; |                 $size = 0; | ||||||
|                 ray('Backing up ' . $database); |                 ray('Backing up '.$database); | ||||||
|                 try { |                 try { | ||||||
|                     if (str($databaseType)->contains('postgres')) { |                     if (str($databaseType)->contains('postgres')) { | ||||||
|                         $this->backup_file = "/pg-dump-$database-" . Carbon::now()->timestamp . ".dmp"; |                         $this->backup_file = "/pg-dump-$database-".Carbon::now()->timestamp.'.dmp'; | ||||||
|                         $this->backup_location = $this->backup_dir . $this->backup_file; |                         $this->backup_location = $this->backup_dir.$this->backup_file; | ||||||
|                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ |                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ | ||||||
|                             'database_name' => $database, |                             'database_name' => $database, | ||||||
|                             'filename' => $this->backup_location, |                             'filename' => $this->backup_location, | ||||||
|                             'scheduled_database_backup_id' => $this->backup->id, |                             'scheduled_database_backup_id' => $this->backup->id, | ||||||
|                         ]); |                         ]); | ||||||
|                         $this->backup_standalone_postgresql($database); |                         $this->backup_standalone_postgresql($database); | ||||||
|                     } else if (str($databaseType)->contains('mongodb')) { |                     } elseif (str($databaseType)->contains('mongodb')) { | ||||||
|                         if ($database === '*') { |                         if ($database === '*') { | ||||||
|                             $database = 'all'; |                             $database = 'all'; | ||||||
|                             $databaseName = 'all'; |                             $databaseName = 'all'; | ||||||
| @ -255,26 +268,26 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                                 $databaseName = $database; |                                 $databaseName = $database; | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                         $this->backup_file = "/mongo-dump-$databaseName-" . Carbon::now()->timestamp . ".tar.gz"; |                         $this->backup_file = "/mongo-dump-$databaseName-".Carbon::now()->timestamp.'.tar.gz'; | ||||||
|                         $this->backup_location = $this->backup_dir . $this->backup_file; |                         $this->backup_location = $this->backup_dir.$this->backup_file; | ||||||
|                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ |                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ | ||||||
|                             'database_name' => $databaseName, |                             'database_name' => $databaseName, | ||||||
|                             'filename' => $this->backup_location, |                             'filename' => $this->backup_location, | ||||||
|                             'scheduled_database_backup_id' => $this->backup->id, |                             'scheduled_database_backup_id' => $this->backup->id, | ||||||
|                         ]); |                         ]); | ||||||
|                         $this->backup_standalone_mongodb($database); |                         $this->backup_standalone_mongodb($database); | ||||||
|                     } else if (str($databaseType)->contains('mysql')) { |                     } elseif (str($databaseType)->contains('mysql')) { | ||||||
|                         $this->backup_file = "/mysql-dump-$database-" . Carbon::now()->timestamp . ".dmp"; |                         $this->backup_file = "/mysql-dump-$database-".Carbon::now()->timestamp.'.dmp'; | ||||||
|                         $this->backup_location = $this->backup_dir . $this->backup_file; |                         $this->backup_location = $this->backup_dir.$this->backup_file; | ||||||
|                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ |                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ | ||||||
|                             'database_name' => $database, |                             'database_name' => $database, | ||||||
|                             'filename' => $this->backup_location, |                             'filename' => $this->backup_location, | ||||||
|                             'scheduled_database_backup_id' => $this->backup->id, |                             'scheduled_database_backup_id' => $this->backup->id, | ||||||
|                         ]); |                         ]); | ||||||
|                         $this->backup_standalone_mysql($database); |                         $this->backup_standalone_mysql($database); | ||||||
|                     } else if (str($databaseType)->contains('mariadb')) { |                     } elseif (str($databaseType)->contains('mariadb')) { | ||||||
|                         $this->backup_file = "/mariadb-dump-$database-" . Carbon::now()->timestamp . ".dmp"; |                         $this->backup_file = "/mariadb-dump-$database-".Carbon::now()->timestamp.'.dmp'; | ||||||
|                         $this->backup_location = $this->backup_dir . $this->backup_file; |                         $this->backup_location = $this->backup_dir.$this->backup_file; | ||||||
|                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ |                         $this->backup_log = ScheduledDatabaseBackupExecution::create([ | ||||||
|                             'database_name' => $database, |                             'database_name' => $database, | ||||||
|                             'filename' => $this->backup_location, |                             'filename' => $this->backup_location, | ||||||
| @ -301,27 +314,28 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                             'status' => 'failed', |                             'status' => 'failed', | ||||||
|                             'message' => $this->backup_output, |                             'message' => $this->backup_output, | ||||||
|                             'size' => $size, |                             'size' => $size, | ||||||
|                             'filename' => null |                             'filename' => null, | ||||||
|                         ]); |                         ]); | ||||||
|                     } |                     } | ||||||
|                     send_internal_notification('DatabaseBackupJob failed with: ' . $e->getMessage()); |                     send_internal_notification('DatabaseBackupJob failed with: '.$e->getMessage()); | ||||||
|                     $this->team?->notify(new BackupFailed($this->backup, $this->database, $this->backup_output, $database)); |                     $this->team?->notify(new BackupFailed($this->backup, $this->database, $this->backup_output, $database)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             send_internal_notification('DatabaseBackupJob failed with: ' . $e->getMessage()); |             send_internal_notification('DatabaseBackupJob failed with: '.$e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } finally { |         } finally { | ||||||
|             BackupCreated::dispatch($this->team->id); |             BackupCreated::dispatch($this->team->id); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function backup_standalone_mongodb(string $databaseWithCollections): void |     private function backup_standalone_mongodb(string $databaseWithCollections): void | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             ray($this->database->toArray()); |             ray($this->database->toArray()); | ||||||
|             $url = $this->database->get_db_url(useInternal: true); |             $url = $this->database->get_db_url(useInternal: true); | ||||||
|             if ($databaseWithCollections === 'all') { |             if ($databaseWithCollections === 'all') { | ||||||
|                 $commands[] = "mkdir -p " . $this->backup_dir; |                 $commands[] = 'mkdir -p '.$this->backup_dir; | ||||||
|                 if (str($this->database->image)->startsWith('mongo:4.0')) { |                 if (str($this->database->image)->startsWith('mongo:4.0')) { | ||||||
|                     $commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location"; |                     $commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location"; | ||||||
|                 } else { |                 } else { | ||||||
| @ -335,7 +349,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                     $databaseName = $databaseWithCollections; |                     $databaseName = $databaseWithCollections; | ||||||
|                     $collectionsToExclude = collect(); |                     $collectionsToExclude = collect(); | ||||||
|                 } |                 } | ||||||
|                 $commands[] = "mkdir -p " . $this->backup_dir; |                 $commands[] = 'mkdir -p '.$this->backup_dir; | ||||||
|                 if ($collectionsToExclude->count() === 0) { |                 if ($collectionsToExclude->count() === 0) { | ||||||
|                     if (str($this->database->image)->startsWith('mongo:4.0')) { |                     if (str($this->database->image)->startsWith('mongo:4.0')) { | ||||||
|                         $commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location"; |                         $commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location"; | ||||||
| @ -344,9 +358,9 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     if (str($this->database->image)->startsWith('mongo:4.0')) { |                     if (str($this->database->image)->startsWith('mongo:4.0')) { | ||||||
|                         $commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --excludeCollection " . $collectionsToExclude->implode(' --excludeCollection ') . " --archive > $this->backup_location"; |                         $commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location"; | ||||||
|                     } else { |                     } else { | ||||||
|                         $commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --excludeCollection " . $collectionsToExclude->implode(' --excludeCollection ') . " --archive > $this->backup_location"; |                         $commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location"; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -355,34 +369,36 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             if ($this->backup_output === '') { |             if ($this->backup_output === '') { | ||||||
|                 $this->backup_output = null; |                 $this->backup_output = null; | ||||||
|             } |             } | ||||||
|             ray('Backup done for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location); |             ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             $this->add_to_backup_output($e->getMessage()); |             $this->add_to_backup_output($e->getMessage()); | ||||||
|             ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage()); |             ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function backup_standalone_postgresql(string $database): void |     private function backup_standalone_postgresql(string $database): void | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $commands[] = "mkdir -p " . $this->backup_dir; |             $commands[] = 'mkdir -p '.$this->backup_dir; | ||||||
|             $commands[] = "docker exec $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location"; |             $commands[] = "docker exec $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location"; | ||||||
|             $this->backup_output = instant_remote_process($commands, $this->server); |             $this->backup_output = instant_remote_process($commands, $this->server); | ||||||
|             $this->backup_output = trim($this->backup_output); |             $this->backup_output = trim($this->backup_output); | ||||||
|             if ($this->backup_output === '') { |             if ($this->backup_output === '') { | ||||||
|                 $this->backup_output = null; |                 $this->backup_output = null; | ||||||
|             } |             } | ||||||
|             ray('Backup done for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location); |             ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             $this->add_to_backup_output($e->getMessage()); |             $this->add_to_backup_output($e->getMessage()); | ||||||
|             ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage()); |             ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function backup_standalone_mysql(string $database): void |     private function backup_standalone_mysql(string $database): void | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $commands[] = "mkdir -p " . $this->backup_dir; |             $commands[] = 'mkdir -p '.$this->backup_dir; | ||||||
|             $commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} $database > $this->backup_location"; |             $commands[] = "docker exec $this->container_name mysqldump -u root -p{$this->database->mysql_root_password} $database > $this->backup_location"; | ||||||
|             ray($commands); |             ray($commands); | ||||||
|             $this->backup_output = instant_remote_process($commands, $this->server); |             $this->backup_output = instant_remote_process($commands, $this->server); | ||||||
| @ -390,17 +406,18 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             if ($this->backup_output === '') { |             if ($this->backup_output === '') { | ||||||
|                 $this->backup_output = null; |                 $this->backup_output = null; | ||||||
|             } |             } | ||||||
|             ray('Backup done for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location); |             ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             $this->add_to_backup_output($e->getMessage()); |             $this->add_to_backup_output($e->getMessage()); | ||||||
|             ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage()); |             ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function backup_standalone_mariadb(string $database): void |     private function backup_standalone_mariadb(string $database): void | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
|             $commands[] = "mkdir -p " . $this->backup_dir; |             $commands[] = 'mkdir -p '.$this->backup_dir; | ||||||
|             $commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location"; |             $commands[] = "docker exec $this->container_name mariadb-dump -u root -p{$this->database->mariadb_root_password} $database > $this->backup_location"; | ||||||
|             ray($commands); |             ray($commands); | ||||||
|             $this->backup_output = instant_remote_process($commands, $this->server); |             $this->backup_output = instant_remote_process($commands, $this->server); | ||||||
| @ -408,17 +425,18 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             if ($this->backup_output === '') { |             if ($this->backup_output === '') { | ||||||
|                 $this->backup_output = null; |                 $this->backup_output = null; | ||||||
|             } |             } | ||||||
|             ray('Backup done for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location); |             ray('Backup done for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             $this->add_to_backup_output($e->getMessage()); |             $this->add_to_backup_output($e->getMessage()); | ||||||
|             ray('Backup failed for ' . $this->container_name . ' at ' . $this->server->name . ':' . $this->backup_location . '\n\nError:' . $e->getMessage()); |             ray('Backup failed for '.$this->container_name.' at '.$this->server->name.':'.$this->backup_location.'\n\nError:'.$e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     private function add_to_backup_output($output): void |     private function add_to_backup_output($output): void | ||||||
|     { |     { | ||||||
|         if ($this->backup_output) { |         if ($this->backup_output) { | ||||||
|             $this->backup_output = $this->backup_output . "\n" . $output; |             $this->backup_output = $this->backup_output."\n".$output; | ||||||
|         } else { |         } else { | ||||||
|             $this->backup_output = $output; |             $this->backup_output = $output; | ||||||
|         } |         } | ||||||
| @ -464,7 +482,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             $commands[] = "docker exec backup-of-{$this->backup->uuid} mc cp $this->backup_location temporary/$bucket{$this->backup_dir}/"; |             $commands[] = "docker exec backup-of-{$this->backup->uuid} mc cp $this->backup_location temporary/$bucket{$this->backup_dir}/"; | ||||||
|             instant_remote_process($commands, $this->server); |             instant_remote_process($commands, $this->server); | ||||||
|             $this->add_to_backup_output('Uploaded to S3.'); |             $this->add_to_backup_output('Uploaded to S3.'); | ||||||
|             ray('Uploaded to S3. ' . $this->backup_location . ' to s3://' . $bucket . $this->backup_dir); |             ray('Uploaded to S3. '.$this->backup_location.' to s3://'.$bucket.$this->backup_dir); | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             $this->add_to_backup_output($e->getMessage()); |             $this->add_to_backup_output($e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|  | |||||||
| @ -3,19 +3,16 @@ | |||||||
| namespace App\Jobs; | namespace App\Jobs; | ||||||
| 
 | 
 | ||||||
| use App\Models\ScheduledDatabaseBackup; | use App\Models\ScheduledDatabaseBackup; | ||||||
| use App\Models\Server; |  | ||||||
| use App\Models\Team; | use App\Models\Team; | ||||||
| use App\Notifications\Database\DailyBackup; | use App\Notifications\Database\DailyBackup; | ||||||
| use App\Notifications\Server\HighDiskUsage; |  | ||||||
| use Illuminate\Bus\Queueable; | use Illuminate\Bus\Queueable; | ||||||
| use Illuminate\Contracts\Queue\ShouldBeEncrypted; | use Illuminate\Contracts\Queue\ShouldBeEncrypted; | ||||||
| use Illuminate\Contracts\Queue\ShouldQueue; | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
| use Illuminate\Foundation\Bus\Dispatchable; | use Illuminate\Foundation\Bus\Dispatchable; | ||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Queue\Middleware\WithoutOverlapping; |  | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| 
 | 
 | ||||||
| class DatabaseBackupStatusJob implements ShouldQueue, ShouldBeEncrypted | class DatabaseBackupStatusJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
| @ -42,13 +39,6 @@ class DatabaseBackupStatusJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|         //     }
 |         //     }
 | ||||||
|         // }
 |         // }
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         // $scheduled_backups = ScheduledDatabaseBackup::all();
 |         // $scheduled_backups = ScheduledDatabaseBackup::all();
 | ||||||
|         // $databases = collect();
 |         // $databases = collect();
 | ||||||
|         // $teams = collect();
 |         // $teams = collect();
 | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ use Illuminate\Queue\InteractsWithQueue; | |||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| use Illuminate\Support\Facades\Artisan; | use Illuminate\Support\Facades\Artisan; | ||||||
| 
 | 
 | ||||||
| class DeleteResourceJob implements ShouldQueue, ShouldBeEncrypted | class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
| @ -60,7 +60,7 @@ class DeleteResourceJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             } |             } | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|             send_internal_notification('ContainerStoppingJob failed with: ' . $e->getMessage()); |             send_internal_notification('ContainerStoppingJob failed with: '.$e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } finally { |         } finally { | ||||||
|             Artisan::queue('cleanup:stucked-resources'); |             Artisan::queue('cleanup:stucked-resources'); | ||||||
|  | |||||||
| @ -10,21 +10,22 @@ use Illuminate\Contracts\Queue\ShouldBeEncrypted; | |||||||
| use Illuminate\Contracts\Queue\ShouldQueue; | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
| use Illuminate\Foundation\Bus\Dispatchable; | use Illuminate\Foundation\Bus\Dispatchable; | ||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Queue\Middleware\WithoutOverlapping; |  | ||||||
| use Illuminate\Queue\SerializesModels; | use Illuminate\Queue\SerializesModels; | ||||||
| use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||||
| use RuntimeException; | use RuntimeException; | ||||||
| 
 | 
 | ||||||
| class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted | class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue | ||||||
| { | { | ||||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; |     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||||
| 
 | 
 | ||||||
|     public $timeout = 300; |     public $timeout = 300; | ||||||
|  | 
 | ||||||
|     public ?int $usageBefore = null; |     public ?int $usageBefore = null; | ||||||
| 
 | 
 | ||||||
|     public function __construct(public Server $server) |     public function __construct(public Server $server) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     public function handle(): void |     public function handle(): void | ||||||
|     { |     { | ||||||
|         try { |         try { | ||||||
| @ -32,35 +33,36 @@ class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted | |||||||
|             $this->server->applications()->each(function ($application) use (&$isInprogress) { |             $this->server->applications()->each(function ($application) use (&$isInprogress) { | ||||||
|                 if ($application->isDeploymentInprogress()) { |                 if ($application->isDeploymentInprogress()) { | ||||||
|                     $isInprogress = true; |                     $isInprogress = true; | ||||||
|  | 
 | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|             if ($isInprogress) { |             if ($isInprogress) { | ||||||
|                 throw new RuntimeException('DockerCleanupJob: ApplicationDeploymentQueue is not empty, skipping...'); |                 throw new RuntimeException('DockerCleanupJob: ApplicationDeploymentQueue is not empty, skipping...'); | ||||||
|             } |             } | ||||||
|             if (!$this->server->isFunctional()) { |             if (! $this->server->isFunctional()) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             $this->usageBefore = $this->server->getDiskUsage(); |             $this->usageBefore = $this->server->getDiskUsage(); | ||||||
|             ray('Usage before: ' . $this->usageBefore); |             ray('Usage before: '.$this->usageBefore); | ||||||
|             if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) { |             if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) { | ||||||
|                 ray('Cleaning up ' . $this->server->name); |                 ray('Cleaning up '.$this->server->name); | ||||||
|                 CleanupDocker::run($this->server); |                 CleanupDocker::run($this->server); | ||||||
|                 $usageAfter = $this->server->getDiskUsage(); |                 $usageAfter = $this->server->getDiskUsage(); | ||||||
|                 if ($usageAfter <  $this->usageBefore) { |                 if ($usageAfter < $this->usageBefore) { | ||||||
|                     $this->server->team?->notify(new DockerCleanup($this->server, 'Saved ' . ($this->usageBefore - $usageAfter) . '% disk space.')); |                     $this->server->team?->notify(new DockerCleanup($this->server, 'Saved '.($this->usageBefore - $usageAfter).'% disk space.')); | ||||||
|                     // ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
 |                     // ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
 | ||||||
|                     // send_internal_notification('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
 |                     // send_internal_notification('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
 | ||||||
|                     Log::info('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name); |                     Log::info('DockerCleanupJob done: Saved '.($this->usageBefore - $usageAfter).'% disk space on '.$this->server->name); | ||||||
|                 } else { |                 } else { | ||||||
|                     Log::info('DockerCleanupJob failed to save disk space on ' . $this->server->name); |                     Log::info('DockerCleanupJob failed to save disk space on '.$this->server->name); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 ray('No need to clean up ' . $this->server->name); |                 ray('No need to clean up '.$this->server->name); | ||||||
|                 Log::info('No need to clean up ' . $this->server->name); |                 Log::info('No need to clean up '.$this->server->name); | ||||||
|             } |             } | ||||||
|         } catch (\Throwable $e) { |         } catch (\Throwable $e) { | ||||||
|             send_internal_notification('DockerCleanupJob failed with: ' . $e->getMessage()); |             send_internal_notification('DockerCleanupJob failed with: '.$e->getMessage()); | ||||||
|             ray($e->getMessage()); |             ray($e->getMessage()); | ||||||
|             throw $e; |             throw $e; | ||||||
|         } |         } | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user