wip
This commit is contained in:
parent
706e4b13ee
commit
c505a6ce9c
@ -13,6 +13,9 @@ class StartProxy
|
||||
public function handle(Server $server, bool $async = true): string|Activity
|
||||
{
|
||||
try {
|
||||
if ($server->isSwarm()) {
|
||||
throw new \Exception("Server is part of swarm, not implemented yet.");
|
||||
}
|
||||
$proxyType = $server->proxyType();
|
||||
$commands = collect([]);
|
||||
$proxy_path = get_proxy_path();
|
||||
@ -46,11 +49,9 @@ public function handle(Server $server, bool $async = true): string|Activity
|
||||
$server->save();
|
||||
return 'OK';
|
||||
}
|
||||
} catch(\Throwable $e) {
|
||||
} catch (\Throwable $e) {
|
||||
ray($e);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ class Index extends Component
|
||||
public ?string $remoteServerHost = null;
|
||||
public ?int $remoteServerPort = 22;
|
||||
public ?string $remoteServerUser = 'root';
|
||||
public bool $isPartOfSwarm = false;
|
||||
public ?Server $createdServer = null;
|
||||
|
||||
public Collection $projects;
|
||||
@ -182,7 +183,9 @@ public function saveServer()
|
||||
'private_key_id' => $this->createdPrivateKey->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
$this->createdServer->save();
|
||||
$this->createdServer->settings->is_part_of_swarm = $this->isPartOfSwarm;
|
||||
$this->createdServer->settings->save();
|
||||
$this->createdServer->addInitialNetwork();
|
||||
$this->validateServer();
|
||||
}
|
||||
public function validateServer()
|
||||
|
@ -14,6 +14,8 @@ class Dashboard extends Component
|
||||
public function mount()
|
||||
{
|
||||
$this->servers = Server::ownedByCurrentTeam()->get();
|
||||
ray($this->servers[1]);
|
||||
ray($this->servers[1]->standaloneDockers);
|
||||
$this->projects = Project::ownedByCurrentTeam()->get();
|
||||
}
|
||||
// public function getIptables()
|
||||
|
@ -126,6 +126,7 @@ public function setServer(Server $server)
|
||||
{
|
||||
$this->server_id = $server->id;
|
||||
$this->standaloneDockers = $server->standaloneDockers;
|
||||
ray($server);
|
||||
$this->swarmDockers = $server->swarmDockers;
|
||||
$this->current_step = 'destinations';
|
||||
}
|
||||
|
@ -17,14 +17,14 @@ class Form extends Component
|
||||
protected $listeners = ['serverRefresh'];
|
||||
|
||||
protected $rules = [
|
||||
'server.name' => 'required|min:6',
|
||||
'server.name' => 'required',
|
||||
'server.description' => 'nullable',
|
||||
'server.ip' => 'required',
|
||||
'server.user' => 'required',
|
||||
'server.port' => 'required',
|
||||
'server.settings.is_cloudflare_tunnel' => 'required',
|
||||
'server.settings.is_cloudflare_tunnel' => 'required|boolean',
|
||||
'server.settings.is_reachable' => 'required',
|
||||
'server.settings.is_part_of_swarm' => 'required',
|
||||
'server.settings.is_part_of_swarm' => 'required|boolean',
|
||||
'wildcard_domain' => 'nullable|url',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
@ -49,9 +49,14 @@ public function serverRefresh($install = true)
|
||||
}
|
||||
public function instantSave()
|
||||
{
|
||||
refresh_server_connection($this->server->privateKey);
|
||||
$this->validateServer();
|
||||
$this->server->settings->save();
|
||||
try {
|
||||
refresh_server_connection($this->server->privateKey);
|
||||
$this->validateServer(false);
|
||||
$this->server->settings->save();
|
||||
$this->emit('success', 'Server updated successfully.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
}
|
||||
public function installDocker()
|
||||
{
|
||||
@ -100,6 +105,12 @@ public function validateServer($install = true)
|
||||
$install && $this->installDocker();
|
||||
return;
|
||||
}
|
||||
if ($this->server->isSwarm()) {
|
||||
$swarmInstalled = $this->server->validateDockerSwarm();
|
||||
if ($swarmInstalled) {
|
||||
$install && $this->emit('success', 'Docker Swarm is initiated.');
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
} finally {
|
||||
|
@ -29,6 +29,7 @@ class ByIp extends Component
|
||||
'ip' => 'required',
|
||||
'user' => 'required|string',
|
||||
'port' => 'required|integer',
|
||||
'is_part_of_swarm' => 'required|boolean',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'name' => 'Name',
|
||||
@ -36,6 +37,7 @@ class ByIp extends Component
|
||||
'ip' => 'IP Address/Domain',
|
||||
'user' => 'User',
|
||||
'port' => 'Port',
|
||||
'is_part_of_swarm' => 'Is part of swarm',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@ -72,11 +74,11 @@ public function submit()
|
||||
'proxy' => [
|
||||
"type" => ProxyTypes::TRAEFIK_V2->value,
|
||||
"status" => ProxyStatus::EXITED->value,
|
||||
]
|
||||
|
||||
],
|
||||
]);
|
||||
$server->settings->is_part_of_swarm = $this->is_part_of_swarm;
|
||||
$server->settings->save();
|
||||
$server->addInitialNetwork();
|
||||
return redirect()->route('server.show', $server->uuid);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
@ -35,25 +35,10 @@ protected static function booted()
|
||||
}
|
||||
$server->forceFill($payload);
|
||||
});
|
||||
|
||||
static::created(function ($server) {
|
||||
ServerSetting::create([
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
if ($server->id === 0) {
|
||||
StandaloneDocker::create([
|
||||
'id' => 0,
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
} else {
|
||||
StandaloneDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
}
|
||||
});
|
||||
static::deleting(function ($server) {
|
||||
$server->destinations()->each(function ($destination) {
|
||||
@ -101,7 +86,39 @@ public function settings()
|
||||
{
|
||||
return $this->hasOne(ServerSetting::class);
|
||||
}
|
||||
|
||||
public function addInitialNetwork() {
|
||||
if ($this->id === 0) {
|
||||
if ($this->isSwarm()) {
|
||||
SwarmDocker::create([
|
||||
'id' => 0,
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify-overlay',
|
||||
'server_id' => $this->id,
|
||||
]);
|
||||
} else {
|
||||
StandaloneDocker::create([
|
||||
'id' => 0,
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $this->id,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if ($this->isSwarm()) {
|
||||
SwarmDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify-overlay',
|
||||
'server_id' => $this->id,
|
||||
]);
|
||||
} else {
|
||||
StandaloneDocker::create([
|
||||
'name' => 'coolify',
|
||||
'network' => 'coolify',
|
||||
'server_id' => $this->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function proxyType()
|
||||
{
|
||||
$proxyType = $this->proxy->get('type');
|
||||
@ -357,12 +374,16 @@ public function validateOS(): bool | Stringable
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public function isSwarm()
|
||||
{
|
||||
return data_get($this, 'settings.is_part_of_swarm');
|
||||
}
|
||||
public function validateConnection()
|
||||
{
|
||||
$server = Server::find($this->id);
|
||||
if ($this->skipServer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$uptime = instant_remote_process(['uptime'], $this, false);
|
||||
if (!$uptime) {
|
||||
$this->settings()->update([
|
||||
@ -373,14 +394,14 @@ public function validateConnection()
|
||||
$this->settings()->update([
|
||||
'is_reachable' => true,
|
||||
]);
|
||||
$this->update([
|
||||
$server->update([
|
||||
'unreachable_count' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
if (data_get($this, 'unreachable_notification_sent') === true) {
|
||||
$this->team->notify(new Revived($this));
|
||||
$this->update(['unreachable_notification_sent' => false]);
|
||||
$server->update(['unreachable_notification_sent' => false]);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -398,7 +419,20 @@ public function validateDockerEngine($throwError = false)
|
||||
}
|
||||
$this->settings->is_usable = true;
|
||||
$this->settings->save();
|
||||
$this->validateCoolifyNetwork();
|
||||
$this->validateCoolifyNetwork(isSwarm: false);
|
||||
return true;
|
||||
}
|
||||
public function validateDockerSwarm()
|
||||
{
|
||||
$swarmStatus = instant_remote_process(["docker info|grep -i swarm"], $this, false);
|
||||
$swarmStatus = str($swarmStatus)->trim()->after(':')->trim();
|
||||
if ($swarmStatus === 'inactive') {
|
||||
throw new \Exception('Docker Swarm is not initiated. Please join the server to a swarm before continuing.');
|
||||
return false;
|
||||
}
|
||||
$this->settings->is_usable = true;
|
||||
$this->settings->save();
|
||||
$this->validateCoolifyNetwork(isSwarm: true);
|
||||
return true;
|
||||
}
|
||||
public function validateDockerEngineVersion()
|
||||
@ -415,9 +449,13 @@ public function validateDockerEngineVersion()
|
||||
$this->settings->save();
|
||||
return true;
|
||||
}
|
||||
public function validateCoolifyNetwork()
|
||||
public function validateCoolifyNetwork($isSwarm = false)
|
||||
{
|
||||
return instant_remote_process(["docker network create coolify --attachable >/dev/null 2>&1 || true"], $this, false);
|
||||
if ($isSwarm) {
|
||||
return instant_remote_process(["docker network create --driver overlay coolify-overlay >/dev/null 2>&1 || true"], $this, false);
|
||||
} else {
|
||||
return instant_remote_process(["docker network create coolify --attachable >/dev/null 2>&1 || true"], $this, false);
|
||||
}
|
||||
}
|
||||
public function executeRemoteCommand(Collection $commands, ?ApplicationDeploymentQueue $loggingModel = null)
|
||||
{
|
||||
|
@ -4,13 +4,57 @@
|
||||
|
||||
class SwarmDocker extends BaseModel
|
||||
{
|
||||
protected $guarded = [];
|
||||
|
||||
public function applications()
|
||||
{
|
||||
return $this->morphMany(Application::class, 'destination');
|
||||
}
|
||||
|
||||
public function postgresqls()
|
||||
{
|
||||
return $this->morphMany(StandalonePostgresql::class, 'destination');
|
||||
}
|
||||
|
||||
public function redis()
|
||||
{
|
||||
return $this->morphMany(StandaloneRedis::class, 'destination');
|
||||
}
|
||||
public function mongodbs()
|
||||
{
|
||||
return $this->morphMany(StandaloneMongodb::class, 'destination');
|
||||
}
|
||||
public function mysqls()
|
||||
{
|
||||
return $this->morphMany(StandaloneMysql::class, 'destination');
|
||||
}
|
||||
public function mariadbs()
|
||||
{
|
||||
return $this->morphMany(StandaloneMariadb::class, 'destination');
|
||||
}
|
||||
|
||||
public function server()
|
||||
{
|
||||
return $this->belongsTo(Server::class);
|
||||
}
|
||||
|
||||
public function services()
|
||||
{
|
||||
return $this->morphMany(Service::class, 'destination');
|
||||
}
|
||||
|
||||
public function databases()
|
||||
{
|
||||
$postgresqls = $this->postgresqls;
|
||||
$redis = $this->redis;
|
||||
$mongodbs = $this->mongodbs;
|
||||
$mysqls = $this->mysqls;
|
||||
$mariadbs = $this->mariadbs;
|
||||
return $postgresqls->concat($redis)->concat($mongodbs)->concat($mysqls)->concat($mariadbs);
|
||||
}
|
||||
|
||||
public function attachedTo()
|
||||
{
|
||||
return $this->applications?->count() > 0 || $this->databases()->count() > 0;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('swarm_dockers', function (Blueprint $table) {
|
||||
$table->string('network');
|
||||
|
||||
$table->unique(['server_id', 'network']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('swarm_dockers', function (Blueprint $table) {
|
||||
$table->dropColumn('network');
|
||||
});
|
||||
}
|
||||
};
|
@ -131,16 +131,16 @@
|
||||
</form>
|
||||
</div>
|
||||
@if (!$serverReachable)
|
||||
This server is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the boarding process and add a new private key manually to Coolify and to the
|
||||
server.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="box" wire:target="validateServer"
|
||||
wire:click="validateServer">Check again
|
||||
</x-forms.button>
|
||||
@endif
|
||||
This server is not reachable with the following public key.
|
||||
<br /> <br />
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the boarding process and add a new private key manually to Coolify and to the
|
||||
server.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="box" wire:target="validateServer" wire:click="validateServer">Check
|
||||
again
|
||||
</x-forms.button>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>Private Keys are used to connect to a remote server through a secure shell, called SSH.</p>
|
||||
@ -200,14 +200,17 @@
|
||||
label="Description" id="remoteServerDescription" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input required placeholder="127.0.0.1" label="IP Address"
|
||||
id="remoteServerHost" />
|
||||
<x-forms.input required placeholder="127.0.0.1" label="IP Address" id="remoteServerHost" />
|
||||
<x-forms.input required placeholder="Port number of your server. Default is 22."
|
||||
label="Port" id="remoteServerPort" />
|
||||
<x-forms.input required readonly
|
||||
placeholder="Username to connect to your server. Default is root." label="Username"
|
||||
id="remoteServerUser" />
|
||||
</div>
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox type="checkbox" id="isPartOfSwarm"
|
||||
label="Is it part of a Swarm cluster?" />
|
||||
</div>
|
||||
<x-forms.button type="submit">Check Connection</x-forms.button>
|
||||
</form>
|
||||
</x-slot:actions>
|
||||
@ -226,7 +229,7 @@
|
||||
</x-slot:question>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center box" wire:click="installDocker">
|
||||
Let's do it!</x-forms.button>
|
||||
Let's do it!</x-forms.button>
|
||||
@if ($dockerInstallationStarted)
|
||||
<x-forms.button class="justify-center box" wire:click="dockerInstalledOrSkipped">
|
||||
Validate Server & Continue</x-forms.button>
|
||||
@ -234,7 +237,10 @@
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>This will install the latest Docker Engine on your server, configure a few things to be able
|
||||
to run optimal.<br><br>Minimum Docker Engine version is: 22<br><br>To manually install Docker Engine, check <a target="_blank" class="underline text-warning" href="https://coolify.io/docs/servers#install-docker-engine-manually">this documentation</a>.</p>
|
||||
to run optimal.<br><br>Minimum Docker Engine version is: 22<br><br>To manually install Docker
|
||||
Engine, check <a target="_blank" class="underline text-warning"
|
||||
href="https://coolify.io/docs/servers#install-docker-engine-manually">this
|
||||
documentation</a>.</p>
|
||||
</x-slot:explanation>
|
||||
</x-boarding-step>
|
||||
|
||||
|
@ -38,8 +38,7 @@
|
||||
<x-forms.input id="server.description" label="Description" />
|
||||
<x-forms.input placeholder="https://example.com" id="wildcard_domain" label="Wildcard Domain"
|
||||
helper="Wildcard domain for your applications. If you set this, you will get a random generated domain for your new applications.<br><span class='font-bold text-white'>Example:</span><br>In case you set:<span class='text-helper'>https://example.com</span> your applications will get:<br> <span class='text-helper'>https://randomId.example.com</span>" />
|
||||
{{-- <x-forms.checkbox disabled type="checkbox" id="server.settings.is_part_of_swarm"
|
||||
label="Is it part of a Swarm cluster?" /> --}}
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-2 lg:flex-row">
|
||||
<x-forms.input id="server.ip" label="IP Address/Domain"
|
||||
@ -49,13 +48,15 @@
|
||||
<x-forms.input type="number" id="server.port" label="Port" required />
|
||||
</div>
|
||||
</div>
|
||||
@if (!$server->isLocalhost())
|
||||
<div class="w-64">
|
||||
<div class="w-64">
|
||||
@if (!$server->isLocalhost())
|
||||
<x-forms.checkbox instantSave
|
||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||
id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" />
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
<x-forms.checkbox instantSave type="checkbox" id="server.settings.is_part_of_swarm"
|
||||
label="Is it part of a Swarm cluster?" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($server->isFunctional())
|
||||
|
@ -3,7 +3,7 @@
|
||||
<x-limit-reached name="servers" />
|
||||
@else
|
||||
<h1>Create a new Server</h1>
|
||||
<div class="subtitle ">Servers are the main blocks of your infrastructure.</div>
|
||||
<div class="subtitle">Servers are the main blocks of your infrastructure.</div>
|
||||
<form class="flex flex-col gap-2" wire:submit.prevent='submit'>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input id="name" label="Name" required />
|
||||
@ -25,6 +25,10 @@
|
||||
@endif
|
||||
@endforeach
|
||||
</x-forms.select>
|
||||
<div class="w-64">
|
||||
<x-forms.checkbox type="checkbox" id="is_part_of_swarm"
|
||||
label="Is it part of a Swarm cluster?" />
|
||||
</div>
|
||||
<x-forms.button type="submit">
|
||||
Save New Server
|
||||
</x-forms.button>
|
||||
|
Loading…
Reference in New Issue
Block a user