commit
17ebc650c9
30
app/Actions/Application/StopApplication.php
Normal file
30
app/Actions/Application/StopApplication.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Application;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Notifications\Application\StatusChanged;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class StopApplication
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
public function handle(Application $application)
|
||||||
|
{
|
||||||
|
$server = $application->destination->server;
|
||||||
|
$containers = getCurrentApplicationContainerStatus($server, $application->id);
|
||||||
|
if ($containers->count() > 0) {
|
||||||
|
foreach ($containers as $container) {
|
||||||
|
$containerName = data_get($container, 'Names');
|
||||||
|
if ($containerName) {
|
||||||
|
instant_remote_process(
|
||||||
|
["docker rm -f {$containerName}"],
|
||||||
|
$server
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: make notification for application
|
||||||
|
// $application->environment->project->team->notify(new StatusChanged($application));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
app/Actions/Database/StartDatabaseProxy.php
Normal file
93
app/Actions/Database/StartDatabaseProxy.php
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
class StartDatabaseProxy
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(StandaloneRedis|StandalonePostgresql $database)
|
||||||
|
{
|
||||||
|
$internalPort = null;
|
||||||
|
if ($database->getMorphClass()=== 'App\Models\StandaloneRedis') {
|
||||||
|
$internalPort = 6379;
|
||||||
|
} else if ($database->getMorphClass()=== 'App\Models\StandalonePostgresql') {
|
||||||
|
$internalPort = 5432;
|
||||||
|
}
|
||||||
|
$containerName = "{$database->uuid}-proxy";
|
||||||
|
$configuration_dir = database_proxy_dir($database->uuid);
|
||||||
|
$nginxconf = <<<EOF
|
||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
stream {
|
||||||
|
server {
|
||||||
|
listen $database->public_port;
|
||||||
|
proxy_pass $database->uuid:$internalPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF;
|
||||||
|
$dockerfile = <<< EOF
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
|
||||||
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
|
EOF;
|
||||||
|
$docker_compose = [
|
||||||
|
'version' => '3.8',
|
||||||
|
'services' => [
|
||||||
|
$containerName => [
|
||||||
|
'build' => [
|
||||||
|
'context' => $configuration_dir,
|
||||||
|
'dockerfile' => 'Dockerfile',
|
||||||
|
],
|
||||||
|
'image' => "nginx:stable-alpine",
|
||||||
|
'container_name' => $containerName,
|
||||||
|
'restart' => RESTART_MODE,
|
||||||
|
'ports' => [
|
||||||
|
"$database->public_port:$database->public_port",
|
||||||
|
],
|
||||||
|
'networks' => [
|
||||||
|
$database->destination->network,
|
||||||
|
],
|
||||||
|
'healthcheck' => [
|
||||||
|
'test' => [
|
||||||
|
'CMD-SHELL',
|
||||||
|
'stat /etc/nginx/nginx.conf || exit 1',
|
||||||
|
],
|
||||||
|
'interval' => '5s',
|
||||||
|
'timeout' => '5s',
|
||||||
|
'retries' => 3,
|
||||||
|
'start_period' => '1s'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'networks' => [
|
||||||
|
$database->destination->network => [
|
||||||
|
'external' => true,
|
||||||
|
'name' => $database->destination->network,
|
||||||
|
'attachable' => true,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2));
|
||||||
|
$nginxconf_base64 = base64_encode($nginxconf);
|
||||||
|
$dockerfile_base64 = base64_encode($dockerfile);
|
||||||
|
instant_remote_process([
|
||||||
|
"mkdir -p $configuration_dir",
|
||||||
|
"echo '{$dockerfile_base64}' | base64 -d > $configuration_dir/Dockerfile",
|
||||||
|
"echo '{$nginxconf_base64}' | base64 -d > $configuration_dir/nginx.conf",
|
||||||
|
"echo '{$dockercompose_base64}' | base64 -d > $configuration_dir/docker-compose.yaml",
|
||||||
|
"docker compose --project-directory {$configuration_dir} up --build -d >/dev/null",
|
||||||
|
], $database->destination->server);
|
||||||
|
}
|
||||||
|
}
|
@ -6,15 +6,18 @@
|
|||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class StartPostgresql
|
class StartPostgresql
|
||||||
{
|
{
|
||||||
|
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 __invoke(Server $server, StandalonePostgresql $database)
|
public function handle(Server $server, StandalonePostgresql $database)
|
||||||
{
|
{
|
||||||
$this->database = $database;
|
$this->database = $database;
|
||||||
$container_name = $this->database->uuid;
|
$container_name = $this->database->uuid;
|
||||||
|
27
app/Actions/Database/StopDatabase.php
Normal file
27
app/Actions/Database/StopDatabase.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
|
use App\Notifications\Application\StatusChanged;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class StopDatabase
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(StandaloneRedis|StandalonePostgresql $database)
|
||||||
|
{
|
||||||
|
$server = $database->destination->server;
|
||||||
|
instant_remote_process(
|
||||||
|
["docker rm -f {$database->uuid}"],
|
||||||
|
$server
|
||||||
|
);
|
||||||
|
if ($database->is_public) {
|
||||||
|
StopDatabaseProxy::run($database);
|
||||||
|
}
|
||||||
|
// TODO: make notification for services
|
||||||
|
// $database->environment->project->team->notify(new StatusChanged($database));
|
||||||
|
}
|
||||||
|
}
|
19
app/Actions/Database/StopDatabaseProxy.php
Normal file
19
app/Actions/Database/StopDatabaseProxy.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Database;
|
||||||
|
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class StopDatabaseProxy
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(StandaloneRedis|StandalonePostgresql $database)
|
||||||
|
{
|
||||||
|
instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server);
|
||||||
|
$database->is_public = false;
|
||||||
|
$database->save();
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use App\Notifications\Application\StatusChanged;
|
||||||
|
|
||||||
class StopService
|
class StopService
|
||||||
{
|
{
|
||||||
@ -22,5 +23,7 @@ public function handle(Service $service)
|
|||||||
}
|
}
|
||||||
instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy 2>/dev/null"], $service->server, false);
|
instant_remote_process(["docker network disconnect {$service->uuid} coolify-proxy 2>/dev/null"], $service->server, false);
|
||||||
instant_remote_process(["docker network rm {$service->uuid} 2>/dev/null"], $service->server, false);
|
instant_remote_process(["docker network rm {$service->uuid} 2>/dev/null"], $service->server, false);
|
||||||
|
// TODO: make notification for databases
|
||||||
|
// $service->environment->project->team->notify(new StatusChanged($service));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Application;
|
namespace App\Http\Livewire\Project\Application;
|
||||||
|
|
||||||
|
use App\Actions\Application\StopApplication;
|
||||||
use App\Jobs\ContainerStatusJob;
|
use App\Jobs\ContainerStatusJob;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@ -59,22 +60,9 @@ protected function setDeploymentUuid()
|
|||||||
|
|
||||||
public function stop()
|
public function stop()
|
||||||
{
|
{
|
||||||
$containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id);
|
StopApplication::run($this->application);
|
||||||
if ($containers->count() === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
foreach ($containers as $container) {
|
|
||||||
$containerName = data_get($container, 'Names');
|
|
||||||
if ($containerName) {
|
|
||||||
instant_remote_process(
|
|
||||||
["docker rm -f {$containerName}"],
|
|
||||||
$this->application->destination->server
|
|
||||||
);
|
|
||||||
$this->application->status = 'exited';
|
$this->application->status = 'exited';
|
||||||
$this->application->save();
|
$this->application->save();
|
||||||
// $this->application->environment->project->team->notify(new StatusChanged($this->application));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->application->refresh();
|
$this->application->refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
use App\Actions\Database\StartPostgresql;
|
use App\Actions\Database\StartPostgresql;
|
||||||
use App\Actions\Database\StartRedis;
|
use App\Actions\Database\StartRedis;
|
||||||
|
use App\Actions\Database\StopDatabase;
|
||||||
use App\Jobs\ContainerStatusJob;
|
use App\Jobs\ContainerStatusJob;
|
||||||
|
use App\Notifications\Application\StatusChanged;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Heading extends Component
|
class Heading extends Component
|
||||||
@ -37,24 +39,16 @@ public function mount()
|
|||||||
|
|
||||||
public function stop()
|
public function stop()
|
||||||
{
|
{
|
||||||
instant_remote_process(
|
StopDatabase::run($this->database);
|
||||||
["docker rm -f {$this->database->uuid}"],
|
|
||||||
$this->database->destination->server
|
|
||||||
);
|
|
||||||
if ($this->database->is_public) {
|
|
||||||
stopDatabaseProxy($this->database);
|
|
||||||
$this->database->is_public = false;
|
|
||||||
}
|
|
||||||
$this->database->status = 'exited';
|
$this->database->status = 'exited';
|
||||||
$this->database->save();
|
$this->database->save();
|
||||||
$this->check_status();
|
$this->check_status();
|
||||||
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start()
|
public function start()
|
||||||
{
|
{
|
||||||
if ($this->database->type() === 'standalone-postgresql') {
|
if ($this->database->type() === 'standalone-postgresql') {
|
||||||
$activity = resolve(StartPostgresql::class)($this->database->destination->server, $this->database);
|
$activity = StartPostgresql::run($this->database->destination->server, $this->database);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
}
|
}
|
||||||
if ($this->database->type() === 'standalone-redis') {
|
if ($this->database->type() === 'standalone-redis') {
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Database\Postgresql;
|
namespace App\Http\Livewire\Project\Database\Postgresql;
|
||||||
|
|
||||||
|
use App\Actions\Database\StartDatabaseProxy;
|
||||||
|
use App\Actions\Database\StopDatabaseProxy;
|
||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@ -67,10 +69,10 @@ public function instantSave()
|
|||||||
}
|
}
|
||||||
if ($this->database->is_public) {
|
if ($this->database->is_public) {
|
||||||
$this->emit('success', 'Starting TCP proxy...');
|
$this->emit('success', 'Starting TCP proxy...');
|
||||||
startDatabaseProxy($this->database);
|
StartDatabaseProxy::run($this->database);
|
||||||
$this->emit('success', 'Database is now publicly accessible.');
|
$this->emit('success', 'Database is now publicly accessible.');
|
||||||
} else {
|
} else {
|
||||||
stopDatabaseProxy($this->database);
|
StopDatabaseProxy::run($this->database);
|
||||||
$this->emit('success', 'Database is no longer publicly accessible.');
|
$this->emit('success', 'Database is no longer publicly accessible.');
|
||||||
}
|
}
|
||||||
$this->getDbUrl();
|
$this->getDbUrl();
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Database\Redis;
|
namespace App\Http\Livewire\Project\Database\Redis;
|
||||||
|
|
||||||
|
use App\Actions\Database\StartDatabaseProxy;
|
||||||
|
use App\Actions\Database\StopDatabaseProxy;
|
||||||
use App\Models\StandaloneRedis;
|
use App\Models\StandaloneRedis;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
@ -55,10 +57,10 @@ public function instantSave()
|
|||||||
}
|
}
|
||||||
if ($this->database->is_public) {
|
if ($this->database->is_public) {
|
||||||
$this->emit('success', 'Starting TCP proxy...');
|
$this->emit('success', 'Starting TCP proxy...');
|
||||||
startDatabaseProxy($this->database);
|
StartDatabaseProxy::run($this->database);
|
||||||
$this->emit('success', 'Database is now publicly accessible.');
|
$this->emit('success', 'Database is now publicly accessible.');
|
||||||
} else {
|
} else {
|
||||||
stopDatabaseProxy($this->database);
|
StopDatabaseProxy::run($this->database);
|
||||||
$this->emit('success', 'Database is no longer publicly accessible.');
|
$this->emit('success', 'Database is no longer publicly accessible.');
|
||||||
}
|
}
|
||||||
$this->getDbUrl();
|
$this->getDbUrl();
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Livewire\Project\Shared;
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
use App\Actions\Service\StopService;
|
use App\Jobs\StopResourceJob;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ class Danger extends Component
|
|||||||
{
|
{
|
||||||
public $resource;
|
public $resource;
|
||||||
public array $parameters;
|
public array $parameters;
|
||||||
public string|null $modalId = null;
|
public ?string $modalId = null;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
@ -20,22 +20,8 @@ public function mount()
|
|||||||
|
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
// Should be queued
|
|
||||||
try {
|
try {
|
||||||
if ($this->resource->type() === 'service') {
|
StopResourceJob::dispatchSync($this->resource);
|
||||||
$server = $this->resource->server;
|
|
||||||
StopService::run($this->resource);
|
|
||||||
} else {
|
|
||||||
$destination = data_get($this->resource, 'destination');
|
|
||||||
if ($destination) {
|
|
||||||
$destination = $this->resource->destination->getMorphClass()::where('id', $this->resource->destination->id)->first();
|
|
||||||
$server = $destination->server;
|
|
||||||
}
|
|
||||||
if ($this->resource->destination->server->isFunctional()) {
|
|
||||||
instant_remote_process(["docker rm -f {$this->resource->uuid}"], $server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->resource->delete();
|
|
||||||
return redirect()->route('project.resources', [
|
return redirect()->route('project.resources', [
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
'project_uuid' => $this->parameters['project_uuid'],
|
||||||
'environment_name' => $this->parameters['environment_name']
|
'environment_name' => $this->parameters['environment_name']
|
||||||
|
54
app/Jobs/StopResourceJob.php
Normal file
54
app/Jobs/StopResourceJob.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Actions\Application\StopApplication;
|
||||||
|
use App\Actions\Database\StopDatabase;
|
||||||
|
use App\Actions\Service\StopService;
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use App\Models\StandaloneRedis;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class StopResourceJob implements ShouldQueue, ShouldBeEncrypted
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public function __construct(public Application|Service|StandalonePostgresql|StandaloneRedis $resource)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$server = $this->resource->destination->server;
|
||||||
|
if (!$server->isFunctional()) {
|
||||||
|
return 'Server is not functional';
|
||||||
|
}
|
||||||
|
switch ($this->resource->type()) {
|
||||||
|
case 'application':
|
||||||
|
StopApplication::run($this->resource);
|
||||||
|
break;
|
||||||
|
case 'standalone-postgresql':
|
||||||
|
StopDatabase::run($this->resource);
|
||||||
|
break;
|
||||||
|
case 'standalone-redis':
|
||||||
|
StopDatabase::run($this->resource);
|
||||||
|
break;
|
||||||
|
case 'service':
|
||||||
|
StopService::run($this->resource);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$this->resource->delete();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
send_internal_notification('ContainerStoppingJob failed with: ' . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,14 +32,6 @@ protected static function booted()
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleting(function ($application) {
|
static::deleting(function ($application) {
|
||||||
// Stop Container
|
|
||||||
if ($application->destination->server->isFunctional()) {
|
|
||||||
instant_remote_process(
|
|
||||||
["docker rm -f {$application->uuid}"],
|
|
||||||
$application->destination->server,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$application->settings()->delete();
|
$application->settings()->delete();
|
||||||
$storages = $application->persistentStorages()->get();
|
$storages = $application->persistentStorages()->get();
|
||||||
foreach ($storages as $storage) {
|
foreach ($storages as $storage) {
|
||||||
|
@ -19,7 +19,6 @@ protected static function booted()
|
|||||||
static::deleting(function ($service) {
|
static::deleting(function ($service) {
|
||||||
$storagesToDelete = collect([]);
|
$storagesToDelete = collect([]);
|
||||||
foreach ($service->applications()->get() as $application) {
|
foreach ($service->applications()->get() as $application) {
|
||||||
instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server, false);
|
|
||||||
$storages = $application->persistentStorages()->get();
|
$storages = $application->persistentStorages()->get();
|
||||||
foreach ($storages as $storage) {
|
foreach ($storages as $storage) {
|
||||||
$storagesToDelete->push($storage);
|
$storagesToDelete->push($storage);
|
||||||
@ -27,7 +26,6 @@ protected static function booted()
|
|||||||
$application->persistentStorages()->delete();
|
$application->persistentStorages()->delete();
|
||||||
}
|
}
|
||||||
foreach ($service->databases()->get() as $database) {
|
foreach ($service->databases()->get() as $database) {
|
||||||
instant_remote_process(["docker rm -f {$database->name}-{$service->uuid}"], $service->server, false);
|
|
||||||
$storages = $database->persistentStorages()->get();
|
$storages = $database->persistentStorages()->get();
|
||||||
foreach ($storages as $storage) {
|
foreach ($storages as $storage) {
|
||||||
$storagesToDelete->push($storage);
|
$storagesToDelete->push($storage);
|
||||||
|
@ -29,21 +29,13 @@ protected static function booted()
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleting(function ($database) {
|
static::deleting(function ($database) {
|
||||||
// Stop Container
|
$storages = $database->persistentStorages()->get();
|
||||||
instant_remote_process(
|
foreach ($storages as $storage) {
|
||||||
["docker rm -f {$database->uuid}"],
|
instant_remote_process(["docker volume rm -f $storage->name"], $database->destination->server, false);
|
||||||
$database->destination->server,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
// Stop TCP Proxy
|
|
||||||
if ($database->is_public) {
|
|
||||||
instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server, false);
|
|
||||||
}
|
}
|
||||||
$database->scheduledBackups()->delete();
|
$database->scheduledBackups()->delete();
|
||||||
$database->persistentStorages()->delete();
|
$database->persistentStorages()->delete();
|
||||||
$database->environment_variables()->delete();
|
$database->environment_variables()->delete();
|
||||||
// Remove Volume
|
|
||||||
instant_remote_process(['docker volume rm postgres-data-' . $database->uuid], $database->destination->server, false);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,21 +24,13 @@ protected static function booted()
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleting(function ($database) {
|
static::deleting(function ($database) {
|
||||||
// Stop Container
|
|
||||||
instant_remote_process(
|
|
||||||
["docker rm -f {$database->uuid}"],
|
|
||||||
$database->destination->server,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
// Stop TCP Proxy
|
|
||||||
if ($database->is_public) {
|
|
||||||
instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server, false);
|
|
||||||
}
|
|
||||||
$database->scheduledBackups()->delete();
|
$database->scheduledBackups()->delete();
|
||||||
|
$storages = $database->persistentStorages()->get();
|
||||||
|
foreach ($storages as $storage) {
|
||||||
|
instant_remote_process(["docker volume rm -f $storage->name"], $database->destination->server, false);
|
||||||
|
}
|
||||||
$database->persistentStorages()->delete();
|
$database->persistentStorages()->delete();
|
||||||
$database->environment_variables()->delete();
|
$database->environment_variables()->delete();
|
||||||
// Remove Volume
|
|
||||||
instant_remote_process(['docker volume rm postgres-data-' . $database->uuid], $database->destination->server, false);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,25 +15,23 @@ class StatusChanged extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public $tries = 1;
|
public $tries = 1;
|
||||||
|
|
||||||
public Application $application;
|
public string $resource_name;
|
||||||
public string $application_name;
|
|
||||||
public string $project_uuid;
|
public string $project_uuid;
|
||||||
public string $environment_name;
|
public string $environment_name;
|
||||||
|
|
||||||
public ?string $application_url = null;
|
public ?string $resource_url = null;
|
||||||
public ?string $fqdn;
|
public ?string $fqdn;
|
||||||
|
|
||||||
public function __construct($application)
|
public function __construct(public Application $resource)
|
||||||
{
|
{
|
||||||
$this->application = $application;
|
$this->resource_name = data_get($resource, 'name');
|
||||||
$this->application_name = data_get($application, 'name');
|
$this->project_uuid = data_get($resource, 'environment.project.uuid');
|
||||||
$this->project_uuid = data_get($application, 'environment.project.uuid');
|
$this->environment_name = data_get($resource, 'environment.name');
|
||||||
$this->environment_name = data_get($application, 'environment.name');
|
$this->fqdn = data_get($resource, 'fqdn', null);
|
||||||
$this->fqdn = data_get($application, 'fqdn', null);
|
|
||||||
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
if (Str::of($this->fqdn)->explode(',')->count() > 1) {
|
||||||
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
$this->fqdn = Str::of($this->fqdn)->explode(',')->first();
|
||||||
}
|
}
|
||||||
$this->application_url = base_url() . "/project/{$this->project_uuid}/{$this->environment_name}/application/{$this->application->uuid}";
|
$this->resource_url = base_url() . "/project/{$this->project_uuid}/{$this->environment_name}/application/{$this->resource->uuid}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
@ -45,32 +43,32 @@ public function toMail(): MailMessage
|
|||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage();
|
||||||
$fqdn = $this->fqdn;
|
$fqdn = $this->fqdn;
|
||||||
$mail->subject("Coolify: {$this->application_name} has been stopped");
|
$mail->subject("Coolify: {$this->resource_name} has been stopped");
|
||||||
$mail->view('emails.application-status-changes', [
|
$mail->view('emails.application-status-changes', [
|
||||||
'name' => $this->application_name,
|
'name' => $this->resource_name,
|
||||||
'fqdn' => $fqdn,
|
'fqdn' => $fqdn,
|
||||||
'application_url' => $this->application_url,
|
'resource_url' => $this->resource_url,
|
||||||
]);
|
]);
|
||||||
return $mail;
|
return $mail;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toDiscord(): string
|
public function toDiscord(): string
|
||||||
{
|
{
|
||||||
$message = 'Coolify: ' . $this->application_name . ' has been stopped.
|
$message = 'Coolify: ' . $this->resource_name . ' has been stopped.
|
||||||
|
|
||||||
';
|
';
|
||||||
$message .= '[Open Application in Coolify](' . $this->application_url . ')';
|
$message .= '[Open Application in Coolify](' . $this->resource_url . ')';
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
public function toTelegram(): array
|
public function toTelegram(): array
|
||||||
{
|
{
|
||||||
$message = 'Coolify: ' . $this->application_name . ' has been stopped.';
|
$message = 'Coolify: ' . $this->resource_name . ' has been stopped.';
|
||||||
return [
|
return [
|
||||||
"message" => $message,
|
"message" => $message,
|
||||||
"buttons" => [
|
"buttons" => [
|
||||||
[
|
[
|
||||||
"text" => "Open Application in Coolify",
|
"text" => "Open Application in Coolify",
|
||||||
"url" => $this->application_url
|
"url" => $this->resource_url
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
use App\Actions\Proxy\SaveConfiguration;
|
use App\Actions\Proxy\SaveConfiguration;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandalonePostgresql;
|
|
||||||
use App\Models\StandaloneRedis;
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
function get_proxy_path()
|
function get_proxy_path()
|
||||||
@ -187,87 +185,3 @@ function setup_default_redirect_404(string|null $redirect_url, Server $server)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startDatabaseProxy(StandalonePostgresql|StandaloneRedis $database)
|
|
||||||
{
|
|
||||||
$internalPort = null;
|
|
||||||
if ($database->getMorphClass()=== 'App\Models\StandaloneRedis') {
|
|
||||||
$internalPort = 6379;
|
|
||||||
} else if ($database->getMorphClass()=== 'App\Models\StandalonePostgresql') {
|
|
||||||
$internalPort = 5432;
|
|
||||||
}
|
|
||||||
$containerName = "{$database->uuid}-proxy";
|
|
||||||
$configuration_dir = database_proxy_dir($database->uuid);
|
|
||||||
$nginxconf = <<<EOF
|
|
||||||
user nginx;
|
|
||||||
worker_processes auto;
|
|
||||||
|
|
||||||
error_log /var/log/nginx/error.log;
|
|
||||||
|
|
||||||
events {
|
|
||||||
worker_connections 1024;
|
|
||||||
}
|
|
||||||
stream {
|
|
||||||
server {
|
|
||||||
listen $database->public_port;
|
|
||||||
proxy_pass $database->uuid:$internalPort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EOF;
|
|
||||||
$dockerfile = <<< EOF
|
|
||||||
FROM nginx:stable-alpine
|
|
||||||
|
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
|
||||||
EOF;
|
|
||||||
$docker_compose = [
|
|
||||||
'version' => '3.8',
|
|
||||||
'services' => [
|
|
||||||
$containerName => [
|
|
||||||
'build' => [
|
|
||||||
'context' => $configuration_dir,
|
|
||||||
'dockerfile' => 'Dockerfile',
|
|
||||||
],
|
|
||||||
'image' => "nginx:stable-alpine",
|
|
||||||
'container_name' => $containerName,
|
|
||||||
'restart' => RESTART_MODE,
|
|
||||||
'ports' => [
|
|
||||||
"$database->public_port:$database->public_port",
|
|
||||||
],
|
|
||||||
'networks' => [
|
|
||||||
$database->destination->network,
|
|
||||||
],
|
|
||||||
'healthcheck' => [
|
|
||||||
'test' => [
|
|
||||||
'CMD-SHELL',
|
|
||||||
'stat /etc/nginx/nginx.conf || exit 1',
|
|
||||||
],
|
|
||||||
'interval' => '5s',
|
|
||||||
'timeout' => '5s',
|
|
||||||
'retries' => 3,
|
|
||||||
'start_period' => '1s'
|
|
||||||
],
|
|
||||||
]
|
|
||||||
],
|
|
||||||
'networks' => [
|
|
||||||
$database->destination->network => [
|
|
||||||
'external' => true,
|
|
||||||
'name' => $database->destination->network,
|
|
||||||
'attachable' => true,
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
$dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2));
|
|
||||||
$nginxconf_base64 = base64_encode($nginxconf);
|
|
||||||
$dockerfile_base64 = base64_encode($dockerfile);
|
|
||||||
instant_remote_process([
|
|
||||||
"mkdir -p $configuration_dir",
|
|
||||||
"echo '{$dockerfile_base64}' | base64 -d > $configuration_dir/Dockerfile",
|
|
||||||
"echo '{$nginxconf_base64}' | base64 -d > $configuration_dir/nginx.conf",
|
|
||||||
"echo '{$dockercompose_base64}' | base64 -d > $configuration_dir/docker-compose.yaml",
|
|
||||||
"docker compose --project-directory {$configuration_dir} up --build -d >/dev/null",
|
|
||||||
], $database->destination->server);
|
|
||||||
}
|
|
||||||
function stopDatabaseProxy(StandalonePostgresql|StandaloneRedis $database)
|
|
||||||
{
|
|
||||||
instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server);
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.83',
|
'release' => '4.0.0-beta.84',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.83';
|
return '4.0.0-beta.84';
|
||||||
|
@ -38,30 +38,48 @@ class="items-center justify-center box">+ Add New Resource</a>
|
|||||||
@endif
|
@endif
|
||||||
<div class="grid gap-2 lg:grid-cols-2">
|
<div class="grid gap-2 lg:grid-cols-2">
|
||||||
@foreach ($environment->applications->sortBy('name') as $application)
|
@foreach ($environment->applications->sortBy('name') as $application)
|
||||||
<a class="box group"
|
<a class="relative box group"
|
||||||
href="{{ route('project.application.configuration', [$project->uuid, $environment->name, $application->uuid]) }}">
|
href="{{ route('project.application.configuration', [$project->uuid, $environment->name, $application->uuid]) }}">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white">{{ $application->name }}</div>
|
<div class="font-bold text-white">{{ $application->name }}</div>
|
||||||
<div class="text-xs text-gray-400 group-hover:text-white">{{ $application->description }}</div>
|
<div class="text-xs text-gray-400 group-hover:text-white">{{ $application->description }}</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@if (Str::of(data_get($application, 'status'))->startsWith('running'))
|
||||||
|
<div class="absolute bg-green-400 -top-1 -left-1 badge badge-xs"></div>
|
||||||
|
@elseif (Str::of(data_get($application, 'status'))->startsWith('exited'))
|
||||||
|
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||||
|
@endif
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
@foreach ($environment->databases()->sortBy('name') as $databases)
|
@foreach ($environment->databases()->sortBy('name') as $database)
|
||||||
<a class="box group"
|
<a class="relative box group"
|
||||||
href="{{ route('project.database.configuration', [$project->uuid, $environment->name, $databases->uuid]) }}">
|
href="{{ route('project.database.configuration', [$project->uuid, $environment->name, $database->uuid]) }}">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white">{{ $databases->name }}</div>
|
<div class="font-bold text-white">{{ $database->name }}</div>
|
||||||
<div class="text-xs text-gray-400 group-hover:text-white">{{ $databases->description }}</div>
|
<div class="text-xs text-gray-400 group-hover:text-white">{{ $database->description }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (Str::of(data_get($database, 'status'))->startsWith('running'))
|
||||||
|
<div class="absolute bg-green-400 -top-1 -left-1 badge badge-xs"></div>
|
||||||
|
@elseif (Str::of(data_get($database, 'status'))->startsWith('exited'))
|
||||||
|
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||||
|
@endif
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
@foreach ($environment->services->sortBy('name') as $service)
|
@foreach ($environment->services->sortBy('name') as $service)
|
||||||
<a class="box group"
|
<a class="relative box group"
|
||||||
href="{{ route('project.service', [$project->uuid, $environment->name, $service->uuid]) }}">
|
href="{{ route('project.service', [$project->uuid, $environment->name, $service->uuid]) }}">
|
||||||
<div class="flex flex-col mx-6">
|
<div class="flex flex-col mx-6">
|
||||||
<div class="font-bold text-white">{{ $service->name }}</div>
|
<div class="font-bold text-white">{{ $service->name }}</div>
|
||||||
<div class="text-xs text-gray-400 group-hover:text-white">{{ $service->description }}</div>
|
<div class="text-xs text-gray-400 group-hover:text-white">{{ $service->description }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (Str::of(serviceStatus($service))->startsWith('running'))
|
||||||
|
<div class="absolute bg-green-400 -top-1 -left-1 badge badge-xs"></div>
|
||||||
|
@elseif (Str::of(serviceStatus($service))->startsWith('degraded'))
|
||||||
|
<div class="absolute bg-yellow-400 -top-1 -left-1 badge badge-xs"></div>
|
||||||
|
@elseif (Str::of(serviceStatus($service))->startsWith('exited'))
|
||||||
|
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||||
|
@endif
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.83"
|
"version": "4.0.0-beta.84"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user