feat(dev): add example nginx connectivity commands

Add ping and firewall up/down helpers for example nginx dev VMs.
Remove the v5 home ready banner and coolify version controls, and render Flux status as a compact summary.
This commit is contained in:
Andras Bacsai 2026-06-16 16:47:10 +02:00
parent 1e038fecae
commit 5c23b9aaa5
5 changed files with 123 additions and 62 deletions

View file

@ -25,7 +25,6 @@ public function __invoke(Request $request, FluxHealth $fluxHealth): Response
$currentTeam = $request->attributes->get('v5.currentTeam'); $currentTeam = $request->attributes->get('v5.currentTeam');
return Inertia::render('Home', [ return Inertia::render('Home', [
'status' => 'v5-ready',
'flux' => $fluxHealth->check(), 'flux' => $fluxHealth->check(),
'clusters' => $this->clusters($currentTeam), 'clusters' => $this->clusters($currentTeam),
'cooldServers' => $this->cooldServers($currentTeam), 'cooldServers' => $this->cooldServers($currentTeam),

View file

@ -1,10 +1,8 @@
import { Head } from '@inertiajs/react'; import { Head } from '@inertiajs/react';
import { useState } from 'react'; import { useState } from 'react';
export default function Home({ status, currentTeam, teams, flux, clusters, cooldServers, privateKeys }) { export default function Home({ currentTeam, teams, flux, clusters, cooldServers, privateKeys }) {
const firstPrivateKey = privateKeys[0]?.uuid || ''; const firstPrivateKey = privateKeys[0]?.uuid || '';
const [coolify, setCoolify] = useState(null);
const [checkingCoolify, setCheckingCoolify] = useState(false);
const [bootstrapResult, setBootstrapResult] = useState(null); const [bootstrapResult, setBootstrapResult] = useState(null);
const [bootstrapping, setBootstrapping] = useState(false); const [bootstrapping, setBootstrapping] = useState(false);
const [bootstrapForm, setBootstrapForm] = useState({ const [bootstrapForm, setBootstrapForm] = useState({
@ -29,30 +27,6 @@ export default function Home({ status, currentTeam, teams, flux, clusters, coold
})); }));
} }
async function checkCoolifyCliVersion() {
setCheckingCoolify(true);
try {
const response = await fetch('/v5/coolify/version', {
headers: {
Accept: 'application/json',
},
});
setCoolify(await response.json());
} catch (error) {
setCoolify({
available: false,
label: 'Unavailable',
version: null,
message: 'Could not check the installed coolify version.',
binary: null,
});
} finally {
setCheckingCoolify(false);
}
}
async function bootstrapCoolifyMesh(event) { async function bootstrapCoolifyMesh(event) {
event.preventDefault(); event.preventDefault();
setBootstrapping(true); setBootstrapping(true);
@ -101,25 +75,12 @@ export default function Home({ status, currentTeam, teams, flux, clusters, coold
<Head title="V5" /> <Head title="V5" />
<main> <main>
<p>{status}</p>
<h1>Coolify v5</h1> <h1>Coolify v5</h1>
<p> <section aria-label="Flux status">
This page is served from Laravel through Inertia and React, with routes,
assets, and future v5 tables isolated from the current v4 Livewire app.
</p>
<section aria-labelledby="flux-status-heading">
<h2 id="flux-status-heading">Flux status</h2>
<p> <p>
<strong>{flux.label}</strong> <strong>Flux:</strong> {flux.label} {flux.socket ? flux.socket : flux.message}
</p> </p>
<p>{flux.message}</p>
{flux.socket ? <p>Socket: {flux.socket}</p> : null}
</section> </section>
<section aria-labelledby="clusters-heading"> <section aria-labelledby="clusters-heading">
@ -173,21 +134,6 @@ export default function Home({ status, currentTeam, teams, flux, clusters, coold
<section aria-labelledby="coolify-heading"> <section aria-labelledby="coolify-heading">
<h2 id="coolify-heading">coolify</h2> <h2 id="coolify-heading">coolify</h2>
<button type="button" onClick={checkCoolifyCliVersion} disabled={checkingCoolify}>
{checkingCoolify ? 'Checking coolify...' : 'Check coolify version'}
</button>
{coolify ? (
<div>
<p>
<strong>{coolify.label}</strong>
</p>
{coolify.version ? <p>Version: {coolify.version}</p> : null}
<p>{coolify.message}</p>
{coolify.binary ? <p>Binary: {coolify.binary}</p> : null}
</div>
) : null}
<form onSubmit={bootstrapCoolifyMesh}> <form onSubmit={bootstrapCoolifyMesh}>
<h3>Bootstrap server</h3> <h3>Bootstrap server</h3>

View file

@ -816,14 +816,67 @@ sudo podman exec coolify-example-nginx nslookup coolify-example-nginx-2.default.
SH SH
} }
example_nginx_require_pair() {
if [ "$(coold_vm_count)" = "1" ]; then
echo "ERROR: example-nginx ping/firewall commands require COOLIFY_COOLD_VM_COUNT=2." >&2
exit 1
fi
}
example_nginx_container_ip() {
local index="$1"
local name
name="$(example_nginx_name "$index")"
COOLIFY_COOLD_LIMA_INSTANCE="$(coold_vm_instance "$index")" scripts/coold-vm.sh shell <<SH
set -e
sudo podman inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${name}
SH
}
example_nginx_ping() {
example_nginx_require_pair
COOLIFY_COOLD_LIMA_INSTANCE="$(coold_vm_instance 1)" scripts/coold-vm.sh shell <<'SH'
set -e
sudo podman exec coolify-example-nginx wget -qO- --timeout=3 http://coolify-example-nginx-2.default.coolify.internal/ >/dev/null
echo 'ok: coolify-example-nginx can reach coolify-example-nginx-2 on tcp/80'
SH
}
example_nginx_firewall_up() {
local src
local dst
example_nginx_require_pair
src="$(example_nginx_container_ip 1)"
dst="$(example_nginx_container_ip 2)"
scripts/dev.sh firewall allow "$src" "$dst" tcp 80
}
example_nginx_firewall_down() {
local src
local dst
example_nginx_require_pair
src="$(example_nginx_container_ip 1)"
dst="$(example_nginx_container_ip 2)"
scripts/dev.sh firewall revoke "$src" "$dst" tcp 80
}
example_nginx_help() { example_nginx_help() {
cat <<'USAGE' cat <<'USAGE'
Usage: scripts/dev.sh example-nginx <command> Usage: scripts/dev.sh example-nginx <command>
Commands: Commands:
up Start one nginx container on each coold VM with coold DNS configured up Start one nginx container on each coold VM with coold DNS configured
down Remove the example nginx containers down Remove the example nginx containers
check-dns Verify host 1 nginx can resolve host 2 nginx through coold DNS check-dns Verify host 1 nginx can resolve host 2 nginx through coold DNS
ping Verify host 1 nginx can reach host 2 nginx on tcp/80
firewall up Allow host 1 nginx to reach host 2 nginx through the coolify CLI
firewall down Revoke the example nginx tcp/80 allow rule through the coolify CLI
USAGE USAGE
} }
@ -843,6 +896,24 @@ example_nginx() {
check-dns) check-dns)
example_nginx_check_dns example_nginx_check_dns
;; ;;
ping)
example_nginx_ping
;;
firewall)
case "${1:-help}" in
up)
example_nginx_firewall_up
;;
down)
example_nginx_firewall_down
;;
*)
echo "unknown example-nginx firewall command: ${1:-help}" >&2
echo "Run: scripts/dev.sh example-nginx help" >&2
exit 1
;;
esac
;;
-h|--help|help) -h|--help|help)
example_nginx_help example_nginx_help
;; ;;

View file

@ -0,0 +1,23 @@
<?php
use Symfony\Component\Process\Process;
it('documents example nginx connectivity and firewall commands', function () {
$process = new Process(['bash', base_path('scripts/dev.sh'), 'example-nginx', 'help'], base_path());
$process->run();
expect($process->isSuccessful())->toBeTrue()
->and($process->getOutput())->toContain('ping')
->and($process->getOutput())->toContain('firewall up')
->and($process->getOutput())->toContain('firewall down')
->and($process->getOutput())->not->toContain('firewall-up')
->and($process->getOutput())->not->toContain('firewall-down');
});
it('uses the coolify firewall wrapper for example nginx firewall changes', function () {
$script = file_get_contents(base_path('scripts/dev.sh'));
expect($script)->toContain('scripts/dev.sh firewall allow "$src" "$dst" tcp 80')
->and($script)->toContain('scripts/dev.sh firewall revoke "$src" "$dst" tcp 80');
});

View file

@ -184,7 +184,8 @@
->assertSuccessful() ->assertSuccessful()
->assertSee('v5-app', false) ->assertSee('v5-app', false)
->assertSee('Home', false) ->assertSee('Home', false)
->assertSee('v5-ready', false) ->assertDontSee('v5-ready', false)
->assertDontSee('This page is served from Laravel through Inertia and React')
->assertSee('Running') ->assertSee('Running')
->assertSee('Flux is running.') ->assertSee('Flux is running.')
->assertSee('"clusters":[]', false) ->assertSee('"clusters":[]', false)
@ -294,6 +295,27 @@
->assertSee('Flux socket was not found.'); ->assertSee('Flux socket was not found.');
}); });
it('does not include coolify version controls on the v5 home page', function () {
$homePage = file_get_contents(resource_path('js/v5/Pages/Home.jsx'));
expect($homePage)
->not->toContain('Check coolify version')
->not->toContain('/v5/coolify/version')
->not->toContain('Installed version:');
});
it('renders flux status as a compact summary', function () {
$homePage = file_get_contents(resource_path('js/v5/Pages/Home.jsx'));
expect($homePage)
->toContain('<strong>Flux:</strong>')
->toContain('{flux.label}')
->toContain('{flux.socket ? flux.socket : flux.message}')
->not->toContain('<h2 id="flux-status-heading">Flux status</h2>')
->not->toContain('<p>{flux.message}</p>')
->not->toContain('Socket: {flux.socket}');
});
it('checks the installed coolify version', function () { it('checks the installed coolify version', function () {
createSharedUserAndTeamTables(); createSharedUserAndTeamTables();
[$user, $team] = createV5UserWithTeam(); [$user, $team] = createV5UserWithTeam();