mirror of
https://github.com/tiennm99/coolify.git
synced 2026-08-19 22:23:42 +00:00
feat(v5): add coolify CLI version check
This commit is contained in:
@@ -42,4 +42,6 @@ tests/Browser/Screenshots
|
||||
tests/v4/Browser/Screenshots
|
||||
|
||||
# Local generated Lima configs
|
||||
.dev/bin/
|
||||
.dev/lima/*.generated.yaml
|
||||
.dev/lima/ssh.config
|
||||
|
||||
@@ -5,7 +5,9 @@ namespace App\Http\Controllers\V5;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use App\Services\Coold\CoolifyCliVersion;
|
||||
use App\Services\Flux\FluxHealth;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
@@ -43,6 +45,11 @@ class HomeController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function coolifyCliVersion(CoolifyCliVersion $coolifyCliVersion): JsonResponse
|
||||
{
|
||||
return response()->json($coolifyCliVersion->check());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{id: string, wireguardIp: string|null, capabilities: array<int, string>, builderEnabled: bool, builderCapacity: int}>
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Coold;
|
||||
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Throwable;
|
||||
|
||||
class CoolifyCliVersion
|
||||
{
|
||||
/**
|
||||
* @return array{available: bool, label: string, version: string|null, message: string, binary: string|null}
|
||||
*/
|
||||
public function check(): array
|
||||
{
|
||||
$binary = config('coold.coolify_cli_bin', '/usr/local/bin/coolify');
|
||||
|
||||
if (! is_string($binary) || $binary === '') {
|
||||
return $this->unavailable(null, 'coolify binary is not configured.');
|
||||
}
|
||||
|
||||
try {
|
||||
$result = Process::timeout(5)->run(escapeshellarg($binary).' --version');
|
||||
} catch (Throwable $exception) {
|
||||
return $this->unavailable($binary, $exception->getMessage());
|
||||
}
|
||||
|
||||
if (! $result->successful()) {
|
||||
return $this->unavailable($binary, trim($result->errorOutput()) ?: 'coolify version check failed.');
|
||||
}
|
||||
|
||||
$version = trim($result->output());
|
||||
|
||||
return [
|
||||
'available' => true,
|
||||
'label' => 'Installed',
|
||||
'version' => $version !== '' ? $version : null,
|
||||
'message' => $version !== '' ? "Installed version: {$version}." : 'coolify is installed.',
|
||||
'binary' => $binary,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{available: false, label: string, version: null, message: string, binary: string|null}
|
||||
*/
|
||||
private function unavailable(?string $binary, string $message): array
|
||||
{
|
||||
return [
|
||||
'available' => false,
|
||||
'label' => 'Unavailable',
|
||||
'version' => null,
|
||||
'message' => $message,
|
||||
'binary' => $binary,
|
||||
];
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'coolify_cli_bin' => env('COOLIFY_CLI_BIN', '/usr/local/bin/coolify'),
|
||||
'dev_host_count' => (int) env('COOLIFY_COOLD_VM_COUNT', 2),
|
||||
'dev_host_id' => env('COOLIFY_COOLD_DEV_HOST_ID', 'coolify-coold-dev'),
|
||||
'dev_host_id_2' => env('COOLIFY_COOLD_LIMA_INSTANCE_2', env('COOLIFY_COOLD_DEV_HOST_ID', 'coolify-coold-dev').'-2'),
|
||||
'dev_wireguard_ip_1' => env('COOLIFY_COOLD_VM_WG_IP_1', '100.64.0.10'),
|
||||
'dev_wireguard_ip_2' => env('COOLIFY_COOLD_VM_WG_IP_2', '100.64.0.11'),
|
||||
'dev_host_id' => env('COOLIFY_COOLD_DEV_HOST_ID', 'coold-dev'),
|
||||
'dev_host_id_2' => env('COOLIFY_COOLD_LIMA_INSTANCE_2', env('COOLIFY_COOLD_DEV_HOST_ID', 'coold-dev').'-2'),
|
||||
'dev_wireguard_ip_1' => env('COOLIFY_COOLD_VM_WG_IP_1', '100.64.0.1'),
|
||||
'dev_wireguard_ip_2' => env('COOLIFY_COOLD_VM_WG_IP_2', '100.64.0.2'),
|
||||
'dev_builder_capacity' => (int) env('COOLIFY_COOLD_VM_BUILDER_CAPACITY', 2),
|
||||
'dev_builder_enabled' => (int) env('COOLIFY_COOLD_VM_BUILDER_CAPACITY', 2) > 0,
|
||||
];
|
||||
|
||||
+10
-10
@@ -6,7 +6,7 @@ This file documents the current local v5/coold dev setup in Coolify.
|
||||
|
||||
- `scripts/dev.sh` owns local developer convenience.
|
||||
- Lima VMs act like real deployment servers.
|
||||
- `cooldctl init bootstrap` owns host wiring:
|
||||
- `coolify init bootstrap` owns host wiring:
|
||||
- WireGuard
|
||||
- Podman mesh networks
|
||||
- Corrosion config/schema/service
|
||||
@@ -32,16 +32,16 @@ scripts/dev.sh list
|
||||
containers, WireGuard keys, Corrosion DB, installed binaries, and firewall state.
|
||||
It does not delete the Coolify repo.
|
||||
|
||||
## cooldctl helper
|
||||
## coolify helper
|
||||
|
||||
```bash
|
||||
scripts/dev.sh cooldctl install
|
||||
scripts/dev.sh cooldctl path
|
||||
scripts/dev.sh cooldctl bootstrap-command
|
||||
scripts/dev.sh cooldctl run <args>
|
||||
scripts/dev.sh coolify install
|
||||
scripts/dev.sh coolify path
|
||||
scripts/dev.sh coolify bootstrap-command
|
||||
scripts/dev.sh coolify run <args>
|
||||
```
|
||||
|
||||
On macOS, the helper builds `cooldctl` from the local coold repo because the
|
||||
On macOS, the helper builds `coolify` from the local coold repo because the
|
||||
nightly release currently publishes Linux binaries. On Linux, it downloads the
|
||||
nightly release artifact.
|
||||
|
||||
@@ -49,7 +49,7 @@ The generated bootstrap command uses Lima's forwarded SSH ports and dev
|
||||
WireGuard endpoint overrides, for example:
|
||||
|
||||
```bash
|
||||
.dev/bin/cooldctl init bootstrap \
|
||||
.dev/bin/coolify init bootstrap \
|
||||
--nodes "127.0.0.1:<ssh1>,127.0.0.1:<ssh2>" \
|
||||
--ssh-key "$HOME/.lima/_config/user" \
|
||||
--ssh-user "$USER" \
|
||||
@@ -61,12 +61,12 @@ WireGuard endpoint overrides, for example:
|
||||
```
|
||||
|
||||
Lima does not allow direct root SSH by default, so dev uses the normal Lima user
|
||||
with passwordless sudo. `cooldctl` wraps remote commands in `sudo -n bash -lc`
|
||||
with passwordless sudo. `coolify` wraps remote commands in `sudo -n bash -lc`
|
||||
when the SSH user is not `root`.
|
||||
|
||||
## Default dev topology
|
||||
|
||||
After `cooldctl init bootstrap`, defaults are:
|
||||
After `coolify init bootstrap`, defaults are:
|
||||
|
||||
| VM | WireGuard IP | WireGuard endpoint | Podman subnet | Gateway |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# Lima VM for testing Coolify v5 against cooldctl-provisioned hosts.
|
||||
# Lima VM for testing Coolify v5 against coolify-provisioned hosts.
|
||||
# Start with: scripts/coold-vm.sh up
|
||||
#
|
||||
# This file is copied into .dev/lima/coold.generated.yaml by the wrapper script,
|
||||
@@ -58,4 +58,4 @@ provision:
|
||||
mkdir -p /etc/coolify /var/lib/coolify-dev
|
||||
chmod 755 /etc/coolify
|
||||
|
||||
echo "[coold-vm] Minimal provisioning complete. cooldctl bootstrap will install WireGuard, Podman, Corrosion, coold, and builder."
|
||||
echo "[coold-vm] Minimal provisioning complete. coolify bootstrap will install WireGuard, Podman, Corrosion, coold, and builder."
|
||||
|
||||
@@ -8,10 +8,14 @@ services:
|
||||
args:
|
||||
- USER_ID=${USERID:-1000}
|
||||
- GROUP_ID=${GROUPID:-1000}
|
||||
- COOLIFY_FLUX_VERSION=${COOLIFY_FLUX_VERSION:-nightly}
|
||||
- COOLIFY_CLI_VERSION=${COOLIFY_CLI_VERSION:-nightly}
|
||||
ports:
|
||||
- "${APP_PORT:-8000}:8080"
|
||||
environment:
|
||||
AUTORUN_ENABLED: false
|
||||
COOLIFY_FLUX_VERSION: "${COOLIFY_FLUX_VERSION:-nightly}"
|
||||
COOLIFY_CLI_VERSION: "${COOLIFY_CLI_VERSION:-nightly}"
|
||||
PUSHER_HOST: "${PUSHER_HOST:-}"
|
||||
PUSHER_PORT: "${PUSHER_PORT:-}"
|
||||
PUSHER_SCHEME: "${PUSHER_SCHEME:-http}"
|
||||
|
||||
@@ -9,6 +9,7 @@ services:
|
||||
- USER_ID=${USERID:-1000}
|
||||
- GROUP_ID=${GROUPID:-1000}
|
||||
- COOLIFY_FLUX_VERSION=${COOLIFY_FLUX_VERSION:-nightly}
|
||||
- COOLIFY_CLI_VERSION=${COOLIFY_CLI_VERSION:-nightly}
|
||||
ports:
|
||||
- "${APP_PORT:-8000}:8080"
|
||||
- "${FORWARD_FLUX_PORT:-6443}:6443"
|
||||
@@ -17,6 +18,7 @@ services:
|
||||
COOLIFY_CONTAINER_ROLE: "${COOLIFY_CONTAINER_ROLE:-all}"
|
||||
COOLIFY_COOLD_VERSION: "${COOLIFY_COOLD_VERSION:-nightly}"
|
||||
COOLIFY_FLUX_VERSION: "${COOLIFY_FLUX_VERSION:-nightly}"
|
||||
COOLIFY_CLI_VERSION: "${COOLIFY_CLI_VERSION:-nightly}"
|
||||
COOLIFY_CORROSION_VERSION: "${COOLIFY_CORROSION_VERSION:-v1.0.0}"
|
||||
PUSHER_HOST: "${PUSHER_HOST:-}"
|
||||
PUSHER_PORT: "${PUSHER_PORT:-}"
|
||||
|
||||
@@ -7,6 +7,7 @@ ARG MINIO_VERSION=RELEASE.2025-05-21T01-59-54Z
|
||||
ARG CLOUDFLARED_VERSION=2025.7.0
|
||||
# https://github.com/coollabsio/coold/releases/tag/nightly
|
||||
ARG COOLIFY_FLUX_VERSION=nightly
|
||||
ARG COOLIFY_CLI_VERSION=nightly
|
||||
# https://www.postgresql.org/support/versioning/
|
||||
# Note: We are using version 18 of the postgres client (while still using postgres 15 for the postgres server) as version 15 has been removed from Alpine 3.23+ https://pkgs.alpinelinux.org/packages?name=postgresql*-client&branch=v3.23&repo=&arch=x86_64&origin=&flagged=&maintainer=
|
||||
ARG POSTGRES_VERSION=18
|
||||
@@ -30,6 +31,7 @@ ARG TARGETARCH
|
||||
ARG POSTGRES_VERSION
|
||||
ARG CLOUDFLARED_VERSION
|
||||
ARG COOLIFY_FLUX_VERSION
|
||||
ARG COOLIFY_CLI_VERSION
|
||||
ARG NGINX_VERSION
|
||||
|
||||
WORKDIR /var/www/html
|
||||
@@ -108,6 +110,27 @@ RUN set -eux; \
|
||||
install -m 0755 /tmp/flux /usr/local/bin/flux; \
|
||||
rm -f /tmp/flux /tmp/flux.tar.gz
|
||||
|
||||
# Install coolify from coold nightly release based on architecture
|
||||
RUN set -eux; \
|
||||
mkdir -p /usr/local/bin; \
|
||||
case "${TARGETARCH:-}" in \
|
||||
amd64|arm64) COOLIFY_CLI_ARCH="${TARGETARCH}" ;; \
|
||||
"") \
|
||||
case "$(uname -m)" in \
|
||||
x86_64) COOLIFY_CLI_ARCH="amd64" ;; \
|
||||
aarch64) COOLIFY_CLI_ARCH="arm64" ;; \
|
||||
*) echo "unsupported coolify arch: $(uname -m)" >&2; exit 1 ;; \
|
||||
esac ;; \
|
||||
*) echo "unsupported coolify TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
|
||||
esac; \
|
||||
curl -fsSL --retry 3 --max-time 120 \
|
||||
-o /tmp/coolify.tar.gz \
|
||||
"https://github.com/coollabsio/coold/releases/download/${COOLIFY_CLI_VERSION}/coolify-linux-musl-${COOLIFY_CLI_ARCH}.tar.gz"; \
|
||||
tar -xzf /tmp/coolify.tar.gz -C /tmp; \
|
||||
test -f /tmp/coolify; \
|
||||
install -m 0755 /tmp/coolify /usr/local/bin/coolify; \
|
||||
rm -f /tmp/coolify /tmp/coolify.tar.gz
|
||||
|
||||
# Configure PHP
|
||||
COPY docker/development/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini
|
||||
ENV PHP_OPCACHE_ENABLE=0
|
||||
|
||||
@@ -7,6 +7,7 @@ ARG MINIO_VERSION=RELEASE.2025-05-21T01-59-54Z
|
||||
ARG CLOUDFLARED_VERSION=2025.7.0
|
||||
# https://github.com/coollabsio/coold/releases/tag/nightly
|
||||
ARG COOLIFY_FLUX_VERSION=nightly
|
||||
ARG COOLIFY_CLI_VERSION=nightly
|
||||
# https://www.postgresql.org/support/versioning/
|
||||
# Note: We are using version 18 of the postgres client (while still using postgres 15 for the postgres server) as version 15 has been removed from Alpine 3.23+ https://pkgs.alpinelinux.org/packages?name=postgresql*-client&branch=v3.23&repo=&arch=x86_64&origin=&flagged=&maintainer=
|
||||
ARG POSTGRES_VERSION=18
|
||||
@@ -79,6 +80,7 @@ ARG TARGETARCH
|
||||
ARG POSTGRES_VERSION
|
||||
ARG CLOUDFLARED_VERSION
|
||||
ARG COOLIFY_FLUX_VERSION
|
||||
ARG COOLIFY_CLI_VERSION
|
||||
ARG NGINX_VERSION
|
||||
ARG CI=true
|
||||
|
||||
@@ -155,6 +157,27 @@ RUN set -eux; \
|
||||
install -m 0755 /tmp/flux /usr/local/bin/flux; \
|
||||
rm -f /tmp/flux /tmp/flux.tar.gz
|
||||
|
||||
# Install coolify from coold nightly release based on architecture
|
||||
RUN set -eux; \
|
||||
mkdir -p /usr/local/bin; \
|
||||
case "${TARGETARCH:-}" in \
|
||||
amd64|arm64) COOLIFY_CLI_ARCH="${TARGETARCH}" ;; \
|
||||
"") \
|
||||
case "$(uname -m)" in \
|
||||
x86_64) COOLIFY_CLI_ARCH="amd64" ;; \
|
||||
aarch64) COOLIFY_CLI_ARCH="arm64" ;; \
|
||||
*) echo "unsupported coolify arch: $(uname -m)" >&2; exit 1 ;; \
|
||||
esac ;; \
|
||||
*) echo "unsupported coolify TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \
|
||||
esac; \
|
||||
curl -fsSL --retry 3 --max-time 120 \
|
||||
-o /tmp/coolify.tar.gz \
|
||||
"https://github.com/coollabsio/coold/releases/download/${COOLIFY_CLI_VERSION}/coolify-linux-musl-${COOLIFY_CLI_ARCH}.tar.gz"; \
|
||||
tar -xzf /tmp/coolify.tar.gz -C /tmp; \
|
||||
test -f /tmp/coolify; \
|
||||
install -m 0755 /tmp/coolify /usr/local/bin/coolify; \
|
||||
rm -f /tmp/coolify /tmp/coolify.tar.gz
|
||||
|
||||
# Configure PHP
|
||||
COPY docker/production/etc/php/conf.d/zzz-custom-php.ini /usr/local/etc/php/conf.d/zzz-custom-php.ini
|
||||
ENV PHP_OPCACHE_ENABLE=1
|
||||
|
||||
@@ -1,6 +1,34 @@
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function Home({ status, currentTeam, teams, flux, cooldHosts }) {
|
||||
const [coolify, setCoolify] = useState(null);
|
||||
const [checkingCoolify, setCheckingCoolify] = useState(false);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title="V5" />
|
||||
@@ -45,6 +73,25 @@ export default function Home({ status, currentTeam, teams, flux, cooldHosts }) {
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="coolify-heading">
|
||||
<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}
|
||||
</section>
|
||||
|
||||
<h2>Current team</h2>
|
||||
|
||||
{currentTeam ? (
|
||||
|
||||
@@ -5,4 +5,5 @@ use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::middleware('v5.authenticated')->group(function () {
|
||||
Route::get('/', HomeController::class)->name('home');
|
||||
Route::get('/coolify/version', [HomeController::class, 'coolifyCliVersion'])->name('coolify.version');
|
||||
});
|
||||
|
||||
+7
-4
@@ -40,7 +40,7 @@ if [ "$BUILDER_CAPACITY" = "0" ]; then
|
||||
BUILDER_ENABLED="false"
|
||||
fi
|
||||
TEMPLATE="$ROOT/dev/lima/coold.yaml"
|
||||
GENERATED="$ROOT/.dev/lima/coold.generated.yaml"
|
||||
GENERATED="$ROOT/.dev/lima/${INSTANCE}.generated.yaml"
|
||||
GUEST_COOLIFY_ROOT="/workspace/coolify"
|
||||
|
||||
usage() {
|
||||
@@ -436,8 +436,11 @@ wait_for_lima_start() {
|
||||
lima_shell sudo sh -c 'test -f /var/log/cloud-init-output.log && tail -n 12 /var/log/cloud-init-output.log || true' 2>/dev/null | awk '{ print "[guest] " $0; fflush(); }' || true
|
||||
|
||||
if ! printf '%s' "$status" | grep -q running; then
|
||||
kill "$start_pid" >/dev/null 2>&1 || true
|
||||
break
|
||||
if kill -0 "$start_pid" 2>/dev/null; then
|
||||
kill "$start_pid" >/dev/null 2>&1 || true
|
||||
disown "$start_pid" >/dev/null 2>&1 || true
|
||||
fi
|
||||
return
|
||||
fi
|
||||
else
|
||||
message="$(latest_lima_message)"
|
||||
@@ -503,7 +506,7 @@ up_with_logs() {
|
||||
wait_for_lima_start
|
||||
wait_for_guest_provisioning
|
||||
|
||||
echo "==> VM is ready. Run cooldctl bootstrap via: scripts/dev.sh up"
|
||||
echo "==> VM is ready. Run coolify bootstrap via: scripts/dev.sh up"
|
||||
}
|
||||
|
||||
cmd="${1:-}"
|
||||
|
||||
+106
-93
@@ -100,30 +100,11 @@ host_os() {
|
||||
esac
|
||||
}
|
||||
|
||||
cooldctl_bin() {
|
||||
printf '%s\n' "$ROOT/.dev/bin/cooldctl"
|
||||
coolify_cli_bin() {
|
||||
printf '%s\n' "$ROOT/.dev/bin/coolify"
|
||||
}
|
||||
|
||||
build_local_cooldctl() {
|
||||
local bin
|
||||
local coold_repo
|
||||
|
||||
bin="$(cooldctl_bin)"
|
||||
coold_repo="$(read_coolify_env COOLIFY_COOLD_REPO /Users/heyandras/devel/coold)"
|
||||
|
||||
if [ ! -d "$coold_repo/cooldctl" ]; then
|
||||
echo "ERROR: macOS cooldctl release artifact is not available yet and local coold repo was not found at ${coold_repo}." >&2
|
||||
echo "Set COOLIFY_COOLD_REPO=/path/to/coold or build/copy cooldctl to ${bin}." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Building local macOS cooldctl from ${coold_repo}"
|
||||
(cd "$coold_repo" && cargo build -p cooldctl)
|
||||
mkdir -p "$(dirname "$bin")"
|
||||
install -m 0755 "$coold_repo/target/debug/cooldctl" "$bin"
|
||||
}
|
||||
|
||||
ensure_cooldctl() {
|
||||
ensure_coolify() {
|
||||
local bin
|
||||
local version
|
||||
local arch
|
||||
@@ -131,63 +112,84 @@ ensure_cooldctl() {
|
||||
local url
|
||||
local tmpdir
|
||||
|
||||
bin="$(cooldctl_bin)"
|
||||
version="$(read_coolify_env COOLIFY_COOLDCTL_VERSION "$(read_coolify_env COOLIFY_COOLD_VERSION nightly)")"
|
||||
bin="$(coolify_cli_bin)"
|
||||
version="$(read_coolify_env COOLIFY_CLI_VERSION "$(read_coolify_env COOLIFY_COOLD_VERSION nightly)")"
|
||||
arch="$(host_arch)"
|
||||
os="$(host_os)"
|
||||
|
||||
if [ "$os" = "darwin" ]; then
|
||||
build_local_cooldctl
|
||||
if [ -x "$bin" ] && "$bin" --version >/dev/null 2>&1 && [ "${COOLIFY_CLI_FORCE_DOWNLOAD:-false}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -x "$bin" ] && "$bin" --version >/dev/null 2>&1 && [ "${COOLIFY_COOLDCTL_FORCE_DOWNLOAD:-false}" != "true" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
url="https://github.com/coollabsio/coold/releases/download/${version}/cooldctl-${os}-${arch}.tar.gz"
|
||||
echo "==> Installing cooldctl from ${url}"
|
||||
url="https://github.com/coollabsio/coold/releases/download/${version}/coolify-${os}-${arch}.tar.gz"
|
||||
echo "==> Installing coolify from ${url}"
|
||||
|
||||
mkdir -p "$(dirname "$bin")"
|
||||
tmpdir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmpdir"' RETURN
|
||||
curl -fsSL --retry 3 --max-time 120 -o "$tmpdir/cooldctl.tar.gz" "$url"
|
||||
tar -xzf "$tmpdir/cooldctl.tar.gz" -C "$tmpdir"
|
||||
install -m 0755 "$tmpdir/cooldctl" "$bin"
|
||||
if ! curl -fsSL --retry 3 --max-time 120 -o "$tmpdir/coolify.tar.gz" "$url"; then
|
||||
rm -rf "$tmpdir"
|
||||
return 1
|
||||
fi
|
||||
tar -xzf "$tmpdir/coolify.tar.gz" -C "$tmpdir"
|
||||
install -m 0755 "$tmpdir/coolify" "$bin"
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
|
||||
lima_ssh_target() {
|
||||
local index="$1"
|
||||
local instance
|
||||
local ssh
|
||||
|
||||
instance="$(coold_vm_instance "$index")"
|
||||
ssh="$(limactl list 2>/dev/null | awk -v name="$instance" 'NR > 1 && $1 == name {print $3}')"
|
||||
|
||||
if [ -z "$ssh" ] || [ "$ssh" = "-" ]; then
|
||||
echo "ERROR: could not determine SSH target for Lima VM ${instance}. Start it first with scripts/dev.sh up." >&2
|
||||
if [ ! -f "$HOME/.lima/${instance}/ssh.config" ]; then
|
||||
echo "ERROR: Lima SSH config for ${instance} was not found. Start it first with scripts/dev.sh up." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '%s\n' "$ssh"
|
||||
printf 'lima-%s\n' "$instance"
|
||||
}
|
||||
|
||||
cooldctl_nodes_arg() {
|
||||
lima_ssh_config() {
|
||||
local count
|
||||
local config="$ROOT/.dev/lima/ssh.config"
|
||||
local instance
|
||||
count="$(coold_vm_count)"
|
||||
|
||||
mkdir -p "$(dirname "$config")"
|
||||
: > "$config"
|
||||
|
||||
for index in $(seq 1 "$count"); do
|
||||
instance="$(coold_vm_instance "$index")"
|
||||
if [ ! -f "$HOME/.lima/${instance}/ssh.config" ]; then
|
||||
echo "ERROR: Lima SSH config for ${instance} was not found. Start it first with scripts/dev.sh up." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat "$HOME/.lima/${instance}/ssh.config" >> "$config"
|
||||
printf '\n' >> "$config"
|
||||
done
|
||||
|
||||
printf '%s\n' "$config"
|
||||
}
|
||||
|
||||
coolify_nodes_arg() {
|
||||
local count
|
||||
local nodes=""
|
||||
local node
|
||||
count="$(coold_vm_count)"
|
||||
|
||||
for index in $(seq 1 "$count"); do
|
||||
node="$(lima_ssh_target "$index")" || return 1
|
||||
if [ -n "$nodes" ]; then
|
||||
nodes="${nodes},"
|
||||
fi
|
||||
nodes="${nodes}$(lima_ssh_target "$index")"
|
||||
nodes="${nodes}${node}"
|
||||
done
|
||||
|
||||
printf '%s\n' "$nodes"
|
||||
}
|
||||
|
||||
cooldctl_wg_listen_overrides_arg() {
|
||||
coolify_wg_listen_overrides_arg() {
|
||||
local count
|
||||
local overrides=""
|
||||
local node
|
||||
@@ -204,7 +206,7 @@ cooldctl_wg_listen_overrides_arg() {
|
||||
printf '%s\n' "$overrides"
|
||||
}
|
||||
|
||||
cooldctl_wg_endpoint_overrides_arg() {
|
||||
coolify_wg_endpoint_overrides_arg() {
|
||||
local count
|
||||
local overrides=""
|
||||
local node
|
||||
@@ -221,45 +223,63 @@ cooldctl_wg_endpoint_overrides_arg() {
|
||||
printf '%s\n' "$overrides"
|
||||
}
|
||||
|
||||
cooldctl_ssh_key() {
|
||||
read_coolify_env COOLIFY_COOLDCTL_SSH_KEY "$HOME/.lima/_config/user"
|
||||
coolify_ssh_key() {
|
||||
read_coolify_env COOLIFY_CLI_SSH_KEY "$HOME/.lima/_config/user"
|
||||
}
|
||||
|
||||
cooldctl_ssh_user() {
|
||||
read_coolify_env COOLIFY_COOLDCTL_SSH_USER "$USER"
|
||||
coolify_ssh_user() {
|
||||
read_coolify_env COOLIFY_CLI_SSH_USER "$USER"
|
||||
}
|
||||
|
||||
cooldctl_bootstrap_command() {
|
||||
ensure_cooldctl
|
||||
coolify_bootstrap_command() {
|
||||
local nodes
|
||||
local ssh_config
|
||||
local listen_overrides
|
||||
local endpoint_overrides
|
||||
ensure_coolify
|
||||
|
||||
nodes="$(coolify_nodes_arg)" || return 1
|
||||
ssh_config="$(lima_ssh_config)" || return 1
|
||||
listen_overrides="$(coolify_wg_listen_overrides_arg)" || return 1
|
||||
endpoint_overrides="$(coolify_wg_endpoint_overrides_arg)" || return 1
|
||||
|
||||
cat <<CMD
|
||||
$(cooldctl_bin) init bootstrap \\
|
||||
--nodes "$(cooldctl_nodes_arg)" \\
|
||||
--ssh-key "$(cooldctl_ssh_key)" \\
|
||||
--ssh-user "$(cooldctl_ssh_user)" \\
|
||||
--wg-listen-port-overrides "$(cooldctl_wg_listen_overrides_arg)" \\
|
||||
--wg-endpoint-overrides "$(cooldctl_wg_endpoint_overrides_arg)" \\
|
||||
$(coolify_cli_bin) init bootstrap \\
|
||||
--nodes "${nodes}" \\
|
||||
--ssh-config "${ssh_config}" \\
|
||||
--ssh-user "$(coolify_ssh_user)" \\
|
||||
--wg-listen-port-overrides "${listen_overrides}" \\
|
||||
--wg-endpoint-overrides "${endpoint_overrides}" \\
|
||||
--coold-version "$(read_coolify_env COOLIFY_COOLD_VERSION nightly)" \\
|
||||
--corrosion-version "$(read_coolify_env COOLIFY_CORROSION_VERSION v1.0.0)" \\
|
||||
--yes
|
||||
CMD
|
||||
}
|
||||
|
||||
cooldctl_bootstrap() {
|
||||
ensure_cooldctl
|
||||
coolify_bootstrap() {
|
||||
local nodes
|
||||
local ssh_config
|
||||
local listen_overrides
|
||||
local endpoint_overrides
|
||||
ensure_coolify
|
||||
|
||||
"$(cooldctl_bin)" init bootstrap \
|
||||
--nodes "$(cooldctl_nodes_arg)" \
|
||||
--ssh-key "$(cooldctl_ssh_key)" \
|
||||
--ssh-user "$(cooldctl_ssh_user)" \
|
||||
--wg-listen-port-overrides "$(cooldctl_wg_listen_overrides_arg)" \
|
||||
--wg-endpoint-overrides "$(cooldctl_wg_endpoint_overrides_arg)" \
|
||||
nodes="$(coolify_nodes_arg)" || return 1
|
||||
ssh_config="$(lima_ssh_config)" || return 1
|
||||
listen_overrides="$(coolify_wg_listen_overrides_arg)" || return 1
|
||||
endpoint_overrides="$(coolify_wg_endpoint_overrides_arg)" || return 1
|
||||
|
||||
"$(coolify_cli_bin)" init bootstrap \
|
||||
--nodes "$nodes" \
|
||||
--ssh-config "$ssh_config" \
|
||||
--ssh-user "$(coolify_ssh_user)" \
|
||||
--wg-listen-port-overrides "$listen_overrides" \
|
||||
--wg-endpoint-overrides "$endpoint_overrides" \
|
||||
--coold-version "$(read_coolify_env COOLIFY_COOLD_VERSION nightly)" \
|
||||
--corrosion-version "$(read_coolify_env COOLIFY_CORROSION_VERSION v1.0.0)" \
|
||||
--yes
|
||||
}
|
||||
|
||||
cooldctl_dev() {
|
||||
coolify_dev() {
|
||||
local command="${1:-help}"
|
||||
if [ $# -gt 0 ]; then
|
||||
shift
|
||||
@@ -267,37 +287,37 @@ cooldctl_dev() {
|
||||
|
||||
case "$command" in
|
||||
install)
|
||||
ensure_cooldctl
|
||||
"$(cooldctl_bin)" --version
|
||||
ensure_coolify
|
||||
"$(coolify_cli_bin)" --version
|
||||
;;
|
||||
path)
|
||||
ensure_cooldctl
|
||||
cooldctl_bin
|
||||
ensure_coolify
|
||||
coolify_cli_bin
|
||||
;;
|
||||
bootstrap-command)
|
||||
cooldctl_bootstrap_command
|
||||
coolify_bootstrap_command
|
||||
;;
|
||||
run)
|
||||
ensure_cooldctl
|
||||
exec "$(cooldctl_bin)" "$@"
|
||||
ensure_coolify
|
||||
exec "$(coolify_cli_bin)" "$@"
|
||||
;;
|
||||
-h|--help|help)
|
||||
cat <<'USAGE'
|
||||
Usage: scripts/dev.sh cooldctl <command>
|
||||
Usage: scripts/dev.sh coolify <command>
|
||||
|
||||
Commands:
|
||||
install Download/install the nightly cooldctl dev binary
|
||||
path Print the local cooldctl path
|
||||
install Download/install the nightly coolify dev binary
|
||||
path Print the local coolify path
|
||||
bootstrap-command Print the dev Lima bootstrap command without running it
|
||||
run <args> Run cooldctl with arbitrary args
|
||||
run <args> Run coolify with arbitrary args
|
||||
|
||||
Example:
|
||||
scripts/dev.sh cooldctl bootstrap-command
|
||||
scripts/dev.sh coolify bootstrap-command
|
||||
USAGE
|
||||
;;
|
||||
*)
|
||||
echo "unknown cooldctl command: $command" >&2
|
||||
echo "Run: scripts/dev.sh cooldctl help" >&2
|
||||
echo "unknown coolify command: $command" >&2
|
||||
echo "Run: scripts/dev.sh coolify help" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -415,15 +435,8 @@ up() {
|
||||
|
||||
if [ "$coold_vm_enabled" != "false" ]; then
|
||||
echo "==> Starting ${count} Coolify coold VM(s) before Spin..."
|
||||
vm_pids=""
|
||||
for index in $(seq 1 "$count"); do
|
||||
(
|
||||
coold_vm "$index" up
|
||||
) &
|
||||
vm_pids="${vm_pids} $!"
|
||||
done
|
||||
for pid in $vm_pids; do
|
||||
wait "$pid"
|
||||
coold_vm "$index" up
|
||||
done
|
||||
else
|
||||
echo "==> COOLIFY_COOLD_VM_ENABLED=false; skipping coold VM."
|
||||
@@ -433,8 +446,8 @@ up() {
|
||||
spin up -d "$@"
|
||||
|
||||
if [ "$coold_vm_enabled" != "false" ]; then
|
||||
echo "==> Bootstrapping coold VM mesh with cooldctl..."
|
||||
cooldctl_bootstrap
|
||||
echo "==> Bootstrapping coold VM mesh with coolify..."
|
||||
coolify_bootstrap
|
||||
|
||||
for index in $(seq 1 "$count"); do
|
||||
configure_flux_dev_for_vm "$index"
|
||||
@@ -911,7 +924,7 @@ Commands:
|
||||
corrosion <command> Inspect Corrosion state, config, logs, and registered containers
|
||||
firewall <command> Manage dev coold firewall allow rules
|
||||
example-nginx <command> Start/check example nginx containers with coold DNS
|
||||
cooldctl <command> Install/run the released cooldctl dev helper
|
||||
coolify <command> Install/run the released coolify dev helper
|
||||
USAGE
|
||||
}
|
||||
|
||||
@@ -945,8 +958,8 @@ case "$cmd" in
|
||||
example-nginx)
|
||||
example_nginx "$@"
|
||||
;;
|
||||
cooldctl)
|
||||
cooldctl_dev "$@"
|
||||
coolify)
|
||||
coolify_dev "$@"
|
||||
;;
|
||||
-h|--help|help|"")
|
||||
usage
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use App\Services\Flux\FluxHealth;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Mockery\MockInterface;
|
||||
@@ -105,10 +106,10 @@ it('serves the v5 inertia shell', function () {
|
||||
->assertSee('v5-ready', false)
|
||||
->assertSee('Running')
|
||||
->assertSee('Flux is running.')
|
||||
->assertSee('coolify-coold-dev')
|
||||
->assertSee('coolify-coold-dev-2')
|
||||
->assertSee('100.64.0.10')
|
||||
->assertSee('100.64.0.11')
|
||||
->assertSee('coold-dev')
|
||||
->assertSee('coold-dev-2')
|
||||
->assertSee('100.64.0.1')
|
||||
->assertSee('100.64.0.2')
|
||||
->assertSee('builder')
|
||||
->assertSee('builderCapacity')
|
||||
->assertSee('V5 Shared Team')
|
||||
@@ -173,6 +174,50 @@ it('shows when flux is unavailable', function () {
|
||||
->assertSee('Flux socket was not found.');
|
||||
});
|
||||
|
||||
it('checks the installed coolify version', function () {
|
||||
createSharedUserAndTeamTables();
|
||||
[$user, $team] = createV5UserWithTeam();
|
||||
|
||||
Process::fake([
|
||||
'*' => Process::result(output: 'coolify nightly-20260616', exitCode: 0),
|
||||
]);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession(['currentTeam' => $team])
|
||||
->getJson('/v5/coolify/version')
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'available' => true,
|
||||
'label' => 'Installed',
|
||||
'version' => 'coolify nightly-20260616',
|
||||
'message' => 'Installed version: coolify nightly-20260616.',
|
||||
'binary' => '/usr/local/bin/coolify',
|
||||
]);
|
||||
});
|
||||
|
||||
it('shows when coolify version check fails', function () {
|
||||
createSharedUserAndTeamTables();
|
||||
[$user, $team] = createV5UserWithTeam();
|
||||
|
||||
Process::fake([
|
||||
'*' => Process::result(errorOutput: 'not found', exitCode: 127),
|
||||
]);
|
||||
|
||||
$this
|
||||
->actingAs($user)
|
||||
->withSession(['currentTeam' => $team])
|
||||
->getJson('/v5/coolify/version')
|
||||
->assertSuccessful()
|
||||
->assertJson([
|
||||
'available' => false,
|
||||
'label' => 'Unavailable',
|
||||
'version' => null,
|
||||
'message' => 'not found',
|
||||
'binary' => '/usr/local/bin/coolify',
|
||||
]);
|
||||
});
|
||||
|
||||
function fakeFluxHealth(bool $available = true, string $message = 'Flux is running.'): void
|
||||
{
|
||||
app()->instance(FluxHealth::class, Mockery::mock(FluxHealth::class, function (MockInterface $mock) use ($available, $message) {
|
||||
@@ -218,3 +263,25 @@ function createSharedUserAndTeamTables(): void
|
||||
$table->unique(['team_id', 'user_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: User, 1: Team}
|
||||
*/
|
||||
function createV5UserWithTeam(): array
|
||||
{
|
||||
$user = User::withoutEvents(fn () => User::query()->create([
|
||||
'name' => 'Margaret Hamilton',
|
||||
'email' => 'margaret@example.com',
|
||||
'email_verified_at' => now(),
|
||||
'password' => 'password',
|
||||
]));
|
||||
$team = Team::withoutEvents(fn () => Team::query()->create([
|
||||
'name' => 'V5 Tooling Team',
|
||||
'description' => null,
|
||||
'personal_team' => false,
|
||||
'show_boarding' => false,
|
||||
]));
|
||||
$user->teams()->attach($team, ['role' => 'owner']);
|
||||
|
||||
return [$user, $team];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user