server list, logs removed, driver/plan wip
This commit is contained in:
15
app/Data/Deployments/Plan.php
Normal file
15
app/Data/Deployments/Plan.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Deployments;
|
||||||
|
|
||||||
|
class Plan
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Step[] $steps
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
public array $steps = [],
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
11
app/Data/Deployments/Step.php
Normal file
11
app/Data/Deployments/Step.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Data\Deployments;
|
||||||
|
|
||||||
|
class Step
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
8
app/Drivers/DatabaseDriver.php
Normal file
8
app/Drivers/DatabaseDriver.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Drivers;
|
||||||
|
|
||||||
|
interface DatabaseDriver extends Driver
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
8
app/Drivers/Driver.php
Normal file
8
app/Drivers/Driver.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Drivers;
|
||||||
|
|
||||||
|
interface Driver
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
10
app/Drivers/Postgres/Postgres17Driver.php
Normal file
10
app/Drivers/Postgres/Postgres17Driver.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Drivers\Postgres;
|
||||||
|
|
||||||
|
use App\Drivers\DatabaseDriver;
|
||||||
|
|
||||||
|
class Postgres17Driver implements DatabaseDriver
|
||||||
|
{
|
||||||
|
// @todo
|
||||||
|
}
|
||||||
11
app/Enums/ServiceStatus.php
Normal file
11
app/Enums/ServiceStatus.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum ServiceStatus: string
|
||||||
|
{
|
||||||
|
case RUNNING = 'running';
|
||||||
|
case STOPPED = 'stopped';
|
||||||
|
case ERROR = 'error';
|
||||||
|
case UNKNOWN = 'unknown';
|
||||||
|
}
|
||||||
@@ -92,13 +92,6 @@ class ServerController extends Controller
|
|||||||
sudoPassword: $sudoPassword,
|
sudoPassword: $sudoPassword,
|
||||||
))->delay(now()->addSeconds(5));
|
))->delay(now()->addSeconds(5));
|
||||||
|
|
||||||
logger('server created');
|
|
||||||
logger($createdServer->id);
|
|
||||||
logger($createdServer->ipv4);
|
|
||||||
logger($createdServer->ipv6);
|
|
||||||
logger($createdServer->rootPassword);
|
|
||||||
logger($sudoPassword);
|
|
||||||
|
|
||||||
session()->flash('sudo_password', $sudoPassword);
|
session()->flash('sudo_password', $sudoPassword);
|
||||||
|
|
||||||
return redirect()->route('servers.show', ['organisation' => $organisation->id, 'server' => $server->id]);
|
return redirect()->route('servers.show', ['organisation' => $organisation->id, 'server' => $server->id]);
|
||||||
|
|||||||
@@ -43,21 +43,12 @@ class ProvisionServer implements ShouldQueue, ShouldBeEncrypted
|
|||||||
]);
|
]);
|
||||||
logger('executing script on server');
|
logger('executing script on server');
|
||||||
if (! $result->isSuccessful()) {
|
if (! $result->isSuccessful()) {
|
||||||
logger('failed to execute script on server');
|
|
||||||
logger($result->getOutput());
|
|
||||||
logger($result->getErrorOutput());
|
|
||||||
logger($result->getExitCode());
|
|
||||||
$this->server->update([
|
$this->server->update([
|
||||||
'status' => ServerStatus::PROVISIONING_FAILED,
|
'status' => ServerStatus::PROVISIONING_FAILED,
|
||||||
]);
|
]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger('script executed on server');
|
|
||||||
logger($result->getOutput());
|
|
||||||
logger($result->getErrorOutput());
|
|
||||||
logger($result->getExitCode());
|
|
||||||
|
|
||||||
$this->server->update([
|
$this->server->update([
|
||||||
'status' => ServerStatus::PROVISIONING,
|
'status' => ServerStatus::PROVISIONING,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -34,12 +34,6 @@ class WaitForServerToConnect implements ShouldQueue, ShouldBeEncrypted
|
|||||||
->execute('echo "Connected"');
|
->execute('echo "Connected"');
|
||||||
|
|
||||||
if (! $process->isSuccessful()) {
|
if (! $process->isSuccessful()) {
|
||||||
logger('root pw: ' . $this->rootPassword);
|
|
||||||
logger('server not reachable');
|
|
||||||
logger('exit code' . $process->getExitCode());
|
|
||||||
logger('output');
|
|
||||||
logger($process->getOutput());
|
|
||||||
logger($process->getErrorOutput());
|
|
||||||
$this->release(15);
|
$this->release(15);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Drivers\Driver;
|
||||||
|
use App\Enums\ServiceStatus;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
@@ -10,6 +12,13 @@ class Service extends Model
|
|||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => ServiceStatus::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function server(): BelongsTo
|
public function server(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Server::class);
|
return $this->belongsTo(Server::class);
|
||||||
@@ -19,4 +28,9 @@ class Service extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Slice::class);
|
return $this->hasMany(Slice::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function driver()//: Driver
|
||||||
|
{
|
||||||
|
// @todo. This is the class that controls the service
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,14 @@ return new class extends Migration
|
|||||||
Schema::create('services', function (Blueprint $table) {
|
Schema::create('services', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->foreignIdFor(Server::class);
|
$table->foreignIdFor(Server::class);
|
||||||
$table->string('category');
|
|
||||||
$table->string('type');
|
|
||||||
$table->string('name');
|
$table->string('name');
|
||||||
|
$table->string('status');
|
||||||
|
$table->string('category'); // database / cache / webserver
|
||||||
|
$table->string('type'); // postgres / redis / caddy
|
||||||
|
$table->string('version'); // 17 / 7 / 2
|
||||||
|
$table->string('driver_name');
|
||||||
|
$table->string('container_name')->nullable();
|
||||||
|
$table->string('container_id')->nullable();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,18 @@ const environment = usePage().props.environment ?? null;
|
|||||||
<header
|
<header
|
||||||
class="flex h-16 shrink-0 items-center gap-2 border-b border-sidebar-border/70 px-6 transition-[width,height] ease-in-out group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12 md:px-4"
|
class="flex h-16 shrink-0 items-center gap-2 border-b border-sidebar-border/70 px-6 transition-[width,height] ease-in-out group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12 md:px-4"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex w-full items-center gap-4">
|
||||||
<SidebarTrigger class="-ml-1" />
|
<SidebarTrigger class="-ml-1" />
|
||||||
<div class="gap-0.25 flex items-center">
|
<template v-if="breadcrumbs.length > 0">
|
||||||
<Button :as="organisation ? Link : 'button'" :href="organisation ? route('organisations.show', { organisation: organisation?.id }) : null" variant="ghost" size="xs">
|
<Breadcrumbs :breadcrumbs="breadcrumbs" />
|
||||||
|
</template>
|
||||||
|
<div class="gap-0.25 ml-auto flex items-center">
|
||||||
|
<Button
|
||||||
|
:as="organisation ? Link : 'button'"
|
||||||
|
:href="organisation ? route('organisations.show', { organisation: organisation?.id }) : null"
|
||||||
|
variant="ghost"
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
{{ organisation?.name ?? 'Select Organisation' }}
|
{{ organisation?.name ?? 'Select Organisation' }}
|
||||||
</Button>
|
</Button>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
@@ -42,15 +50,18 @@ const environment = usePage().props.environment ?? null;
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="organisation" class="gap-0.25 flex items-center">
|
<div v-if="organisation" class="gap-0.25 flex items-center">
|
||||||
<Button
|
<Button
|
||||||
|
:disabled="!organisation?.applications?.length"
|
||||||
:as="application ? Link : 'button'"
|
:as="application ? Link : 'button'"
|
||||||
:href="application ? route('applications.show', { organisation: application.organisation_id, application: application.id }) : null"
|
:href="
|
||||||
|
application ? route('applications.show', { organisation: application.organisation_id, application: application.id }) : null
|
||||||
|
"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
{{ application?.name ?? 'Select Application' }}
|
{{ application?.name ?? 'Application' }}
|
||||||
</Button>
|
</Button>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger :as="Button" size="iconxs" variant="ghost">
|
<DropdownMenuTrigger :as="Button" size="iconxs" variant="ghost" :disabled="!organisation?.applications?.length">
|
||||||
<ChevronsUpDown class="size-3" />
|
<ChevronsUpDown class="size-3" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
@@ -63,32 +74,44 @@ const environment = usePage().props.environment ?? null;
|
|||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="application" class="gap-0.25 flex items-center">
|
<div class="gap-0.25 flex items-center">
|
||||||
<Button
|
<Button
|
||||||
|
:disabled="!application?.environments?.length"
|
||||||
:as="environment ? Link : 'button'"
|
:as="environment ? Link : 'button'"
|
||||||
:href="environment ? route('environments.show', { organisation: application.organisation_id, application: application.id, environment: environment.id }) : null"
|
:href="
|
||||||
|
environment
|
||||||
|
? route('environments.show', {
|
||||||
|
organisation: application.organisation_id,
|
||||||
|
application: application.id,
|
||||||
|
environment: environment.id,
|
||||||
|
})
|
||||||
|
: null
|
||||||
|
"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
{{ environment?.name ?? 'Select Environment' }}
|
{{ environment?.name ?? 'Environment' }}
|
||||||
</Button>
|
</Button>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger :as="Button" size="iconxs" variant="ghost">
|
<DropdownMenuTrigger :as="Button" size="iconxs" variant="ghost" :disabled="!application?.environments?.length">
|
||||||
<ChevronsUpDown class="size-3" />
|
<ChevronsUpDown class="size-3" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
v-for="env in application?.environments"
|
v-for="env in application?.environments"
|
||||||
:as="Link"
|
:as="Link"
|
||||||
:href="route('environments.show', { organisation: application.organisation_id, application: application.id, environment: env.id })"
|
:href="
|
||||||
|
route('environments.show', {
|
||||||
|
organisation: application.organisation_id,
|
||||||
|
application: application.id,
|
||||||
|
environment: env.id,
|
||||||
|
})
|
||||||
|
"
|
||||||
>{{ env.name }}</DropdownMenuItem
|
>{{ env.name }}</DropdownMenuItem
|
||||||
>
|
>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="breadcrumbs.length > 0">
|
|
||||||
<Breadcrumbs :breadcrumbs="breadcrumbs" />
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup>
|
||||||
|
import { Card, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
import AppLayout from '@/layouts/AppLayout.vue';
|
||||||
import { Head } from '@inertiajs/vue3';
|
import { Head, Link } from '@inertiajs/vue3';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
servers: {
|
servers: {
|
||||||
@@ -13,9 +14,28 @@ const props = defineProps({
|
|||||||
<template>
|
<template>
|
||||||
<Head title="Dashboard" />
|
<Head title="Dashboard" />
|
||||||
|
|
||||||
<AppLayout>
|
<AppLayout :breadcrumbs="[
|
||||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
|
{
|
||||||
{{ servers.data }}
|
title: 'Servers',
|
||||||
|
href: route('servers.index', {
|
||||||
|
organisation: $page.props.organisation.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]">
|
||||||
|
<div class="grid gap-4 rounded-xl p-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
<Card v-for="server in servers.data" :key="`server{$servers.id}`" class="w-full relative">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>{{ server.name }}</CardTitle>
|
||||||
|
<CardDescription
|
||||||
|
><span class="inline-block rounded-md bg-green-200 px-2 text-xs uppercase text-green-800">{{ server.status }}</span> •
|
||||||
|
{{ server.ipv4 || server.ipv6 }}</CardDescription
|
||||||
|
>
|
||||||
|
</CardHeader>
|
||||||
|
<Link :href="route('servers.show', {
|
||||||
|
organisation: $page.props.organisation.id,
|
||||||
|
server: server.id,
|
||||||
|
})" class="absolute inset-0"></Link>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<div>@todo pagination</div>
|
<div>@todo pagination</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
import AppLayout from '@/layouts/AppLayout.vue';
|
||||||
import { type BreadcrumbItem } from '@/types';
|
|
||||||
import { Head } from '@inertiajs/vue3';
|
import { Head } from '@inertiajs/vue3';
|
||||||
import PlaceholderPattern from '../components/PlaceholderPattern.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
server: {
|
server: {
|
||||||
@@ -15,13 +13,29 @@ const props = defineProps({
|
|||||||
<template>
|
<template>
|
||||||
<Head :title="server.name" />
|
<Head :title="server.name" />
|
||||||
|
|
||||||
<AppLayout>
|
<AppLayout
|
||||||
|
:breadcrumbs="[
|
||||||
|
{
|
||||||
|
title: 'Servers',
|
||||||
|
href: route('servers.index', {
|
||||||
|
organisation: $page.props.organisation.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: server.name,
|
||||||
|
href: route('servers.show', {
|
||||||
|
organisation: $page.props.organisation.id,
|
||||||
|
server: server.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
|
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
|
||||||
{{ server }}
|
{{ server }}
|
||||||
|
|
||||||
<div v-if="$page.props.flash?.server_credentials" class="p-5">
|
<div v-if="$page.props.flash?.server_credentials" class="p-5">
|
||||||
<div class="mb-4 text-sm font-medium text-gray-900 dark:text-white">
|
<div class="mb-4 text-sm font-medium text-gray-900 dark:text-white">
|
||||||
WILL NOT BE SHOWN AGAIN:
|
WILL NOT BE SHOWN AGAIN:
|
||||||
{{ $page.props.flash.server_credentials }}
|
{{ $page.props.flash.server_credentials }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user