feat: public database
This commit is contained in:
parent
db5ecf07bd
commit
77e3208f00
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,3 +31,4 @@ _ide_helper.php
|
|||||||
_ide_helper_models.php
|
_ide_helper_models.php
|
||||||
.rnd
|
.rnd
|
||||||
/.ssh
|
/.ssh
|
||||||
|
scripts/load-test/*
|
||||||
|
@ -42,8 +42,13 @@ public function stop()
|
|||||||
["docker rm -f {$this->database->uuid}"],
|
["docker rm -f {$this->database->uuid}"],
|
||||||
$this->database->destination->server
|
$this->database->destination->server
|
||||||
);
|
);
|
||||||
|
if ($this->database->is_public) {
|
||||||
|
stopPostgresProxy($this->database);
|
||||||
|
$this->database->is_public = false;
|
||||||
|
}
|
||||||
$this->database->status = 'stopped';
|
$this->database->status = 'stopped';
|
||||||
$this->database->save();
|
$this->database->save();
|
||||||
|
$this->emit('refresh');
|
||||||
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
// $this->database->environment->project->team->notify(new StatusChanged($this->database));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ class General extends Component
|
|||||||
public StandalonePostgresql $database;
|
public StandalonePostgresql $database;
|
||||||
public string $new_filename;
|
public string $new_filename;
|
||||||
public string $new_content;
|
public string $new_content;
|
||||||
|
public string $db_url;
|
||||||
|
|
||||||
protected $listeners = ['refresh', 'save_init_script', 'delete_init_script'];
|
protected $listeners = ['refresh', 'save_init_script', 'delete_init_script'];
|
||||||
|
|
||||||
@ -26,6 +27,8 @@ class General extends Component
|
|||||||
'database.init_scripts' => 'nullable',
|
'database.init_scripts' => 'nullable',
|
||||||
'database.image' => 'required',
|
'database.image' => 'required',
|
||||||
'database.ports_mappings' => 'nullable',
|
'database.ports_mappings' => 'nullable',
|
||||||
|
'database.is_public' => 'nullable|boolean',
|
||||||
|
'database.public_port' => 'nullable|integer',
|
||||||
];
|
];
|
||||||
protected $validationAttributes = [
|
protected $validationAttributes = [
|
||||||
'database.name' => 'Name',
|
'database.name' => 'Name',
|
||||||
@ -38,8 +41,43 @@ class General extends Component
|
|||||||
'database.init_scripts' => 'Init Scripts',
|
'database.init_scripts' => 'Init Scripts',
|
||||||
'database.image' => 'Image',
|
'database.image' => 'Image',
|
||||||
'database.ports_mappings' => 'Port Mapping',
|
'database.ports_mappings' => 'Port Mapping',
|
||||||
|
'database.is_public' => 'Is Public',
|
||||||
|
'database.public_port' => 'Public Port',
|
||||||
];
|
];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->getDbUrl();
|
||||||
|
}
|
||||||
|
public function getDbUrl() {
|
||||||
|
if ($this->database->is_public) {
|
||||||
|
$this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->destination->server->ip}:{$this->database->public_port}/{$this->database->postgres_db}";
|
||||||
|
} else {
|
||||||
|
$this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->uuid}:5432/{$this->database->postgres_db}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if ($this->database->is_public && !$this->database->public_port) {
|
||||||
|
$this->emit('error', 'Public port is required.');
|
||||||
|
$this->database->is_public = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($this->database->is_public) {
|
||||||
|
startPostgresProxy($this->database);
|
||||||
|
$this->emit('success', 'Database is now publicly accessible.');
|
||||||
|
} else {
|
||||||
|
stopPostgresProxy($this->database);
|
||||||
|
$this->emit('success', 'Database is no longer publicly accessible.');
|
||||||
|
}
|
||||||
|
$this->getDbUrl();
|
||||||
|
$this->database->save();
|
||||||
|
} catch(Exception $e) {
|
||||||
|
$this->database->is_public = !$this->database->is_public;
|
||||||
|
return general_error_handler(err: $e, that: $this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
public function save_init_script($script)
|
public function save_init_script($script)
|
||||||
{
|
{
|
||||||
$this->database->init_scripts = filter($this->database->init_scripts, fn ($s) => $s['filename'] !== $script['filename']);
|
$this->database->init_scripts = filter($this->database->init_scripts, fn ($s) => $s['filename'] !== $script['filename']);
|
||||||
|
@ -20,7 +20,7 @@ function create_standalone_postgresql($environment_id, $destination_uuid): Stand
|
|||||||
}
|
}
|
||||||
return StandalonePostgresql::create([
|
return StandalonePostgresql::create([
|
||||||
'name' => generate_database_name('postgresql'),
|
'name' => generate_database_name('postgresql'),
|
||||||
'postgres_password' => \Illuminate\Support\Str::password(),
|
'postgres_password' => \Illuminate\Support\Str::password(symbols: false),
|
||||||
'environment_id' => $environment_id,
|
'environment_id' => $environment_id,
|
||||||
'destination_id' => $destination->id,
|
'destination_id' => $destination->id,
|
||||||
'destination_type' => $destination->getMorphClass(),
|
'destination_type' => $destination->getMorphClass(),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
function get_proxy_path()
|
function get_proxy_path()
|
||||||
@ -166,3 +167,75 @@ function setup_default_redirect_404(string|null $redirect_url, Server $server)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startPostgresProxy(StandalonePostgresql $database)
|
||||||
|
{
|
||||||
|
$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:5432;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF;
|
||||||
|
$docker_compose = [
|
||||||
|
'version' => '3.8',
|
||||||
|
'services' => [
|
||||||
|
$containerName => [
|
||||||
|
'image' => "nginx:stable-alpine",
|
||||||
|
'container_name' => $containerName,
|
||||||
|
'restart' => RESTART_MODE,
|
||||||
|
'volumes' => [
|
||||||
|
"$configuration_dir/nginx.conf:/etc/nginx/nginx.conf:ro",
|
||||||
|
],
|
||||||
|
'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);
|
||||||
|
instant_remote_process([
|
||||||
|
"mkdir -p $configuration_dir",
|
||||||
|
"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 -d >/dev/null",
|
||||||
|
|
||||||
|
|
||||||
|
], $database->destination->server);
|
||||||
|
}
|
||||||
|
function stopPostgresProxy(StandalonePostgresql $database)
|
||||||
|
{
|
||||||
|
instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server);
|
||||||
|
}
|
||||||
|
@ -28,6 +28,10 @@ function database_configuration_dir(): string
|
|||||||
{
|
{
|
||||||
return '/data/coolify/databases';
|
return '/data/coolify/databases';
|
||||||
}
|
}
|
||||||
|
function database_proxy_dir($uuid): string
|
||||||
|
{
|
||||||
|
return "/data/coolify/databases/$uuid/proxy";
|
||||||
|
}
|
||||||
|
|
||||||
function backup_dir(): string
|
function backup_dir(): string
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ class="w-4 h-4 stroke-current">
|
|||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
<input @disabled($disabled) type="checkbox" {{ $attributes->merge(['class' => $defaultClass]) }}
|
<input @disabled($disabled) type="checkbox" {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||||
@if ($instantSave) wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}'
|
@if ($instantSave) wire:loading.attr="disabled" wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}'
|
||||||
wire:model.defer={{ $id }} @else wire:model.defer={{ $value ?? $id }} @endif />
|
wire:model.defer={{ $id }} @else wire:model.defer={{ $value ?? $id }} @endif />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,10 +51,15 @@
|
|||||||
<x-forms.input label="Host Auth Method" id="database.postgres_host_auth_method"
|
<x-forms.input label="Host Auth Method" id="database.postgres_host_auth_method"
|
||||||
placeholder="If empty, use default. See in docker docs." />
|
placeholder="If empty, use default. See in docker docs." />
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="flex flex-col gap-2">
|
||||||
<h3 class="py-2">Network</h3>
|
<h3 class="py-2">Network</h3>
|
||||||
|
<div class="flex items-end gap-2">
|
||||||
<x-forms.input placeholder="3000:5432" id="database.ports_mappings" label="Ports Mappings"
|
<x-forms.input placeholder="3000:5432" id="database.ports_mappings" label="Ports Mappings"
|
||||||
helper="A comma separated list of ports you would like to map to the host system.<br><span class='inline-block font-bold text-warning'>Example</span>3000:5432,3002:5433" />
|
helper="A comma separated list of ports you would like to map to the host system.<br><span class='inline-block font-bold text-warning'>Example</span>3000:5432,3002:5433" />
|
||||||
|
<x-forms.input placeholder="5432" disabled="{{$database->is_public}}" id="database.public_port" label="Public Port" />
|
||||||
|
<x-forms.checkbox instantSave id="database.is_public" label="Accessible over the internet" />
|
||||||
|
</div>
|
||||||
|
<x-forms.input label="Postgres URL" readonly wire:model="db_url" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="pb-16">
|
<div class="pb-16">
|
||||||
|
2
resources/views/vendor/toaster/hub.blade.php
vendored
2
resources/views/vendor/toaster/hub.blade.php
vendored
@ -71,7 +71,7 @@ class="relative flex duration-300 transform transition ease-in-out max-w-md w-fu
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span x-html="toast.message" />
|
<span x-html="toast.message" class="w-full pr-10 break-words" />
|
||||||
</i>
|
</i>
|
||||||
|
|
||||||
@if ($closeable)
|
@if ($closeable)
|
||||||
|
Loading…
Reference in New Issue
Block a user