fixes for terminal

This commit is contained in:
Andras Bacsai
2024-09-11 12:19:27 +02:00
parent 33e9c9b0f9
commit 117fbeb07c
12 changed files with 279 additions and 226 deletions

View File

@@ -11,17 +11,19 @@ class Terminal extends Component
#[On('send-terminal-command')]
public function sendTerminalCommand($isContainer, $identifier, $serverUuid)
{
$server = Server::whereUuid($serverUuid)->firstOrFail();
$server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->firstOrFail();
if (auth()->user()) {
$teams = auth()->user()->teams->pluck('id');
if (! $teams->contains($server->team_id) && ! $teams->contains(0)) {
throw new \Exception('User is not part of the team that owns this server');
}
}
// if (auth()->user()) {
// $teams = auth()->user()->teams->pluck('id');
// if (! $teams->contains($server->team_id) && ! $teams->contains(0)) {
// throw new \Exception('User is not part of the team that owns this server');
// }
// }
if ($isContainer) {
ray($identifier);
$status = getContainerStatus($server, $identifier);
ray($status);
if ($status !== 'running') {
return handleError(new \Exception('Container is not running'), $this);
}

View File

@@ -2,7 +2,6 @@
namespace App\Livewire;
use App\Models\Server;
use Livewire\Attributes\On;
use Livewire\Component;
@@ -23,7 +22,7 @@ class RunCommand extends Component
private function getAllActiveContainers()
{
return Server::all()->flatMap(function ($server) {
return collect($this->servers)->flatMap(function ($server) {
if (! $server->isFunctional()) {
return [];
}
@@ -31,25 +30,52 @@ class RunCommand extends Component
return $server->definedResources()
->filter(function ($resource) {
$status = method_exists($resource, 'realStatus') ? $resource->realStatus() : (method_exists($resource, 'status') ? $resource->status() : 'exited');
return str_starts_with($status, 'running:');
})
->map(function ($resource) use ($server) {
$container_name = $resource->uuid;
if (isDev()) {
if (data_get($resource, 'name') === 'coolify-db') {
$container_name = 'coolify-db';
if (class_basename($resource) === 'Application' || class_basename($resource) === 'Service') {
return [
'name' => $resource->name,
'connection_name' => $container_name,
'uuid' => $resource->uuid,
'status' => 'running',
'server' => $server,
'server_uuid' => $server->uuid,
];
}
}
if (class_basename($resource) === 'Application') {
if (! $server->isSwarm()) {
$current_containers = getCurrentApplicationContainerStatus($server, $resource->id, includePullrequests: true);
}
$status = $resource->status;
} elseif (class_basename($resource) === 'Service') {
$current_containers = getCurrentServiceContainerStatus($server, $resource->id);
$status = $resource->status();
} else {
$status = getContainerStatus($server, $resource->uuid);
if ($status === 'running') {
$current_containers = collect([
'Names' => $resource->name,
]);
}
}
if ($server->isSwarm()) {
$container_name = $resource->uuid.'_'.$resource->uuid;
} else {
$current_containers = getCurrentApplicationContainerStatus($server, $resource->id, includePullrequests: true);
$container_name = data_get($current_containers->first(), 'Names');
}
}
return [
'name' => $resource->name,
'connection_name' => $container_name,
'uuid' => $resource->uuid,
'status' => $resource->status,
'status' => $status,
'server' => $server,
'server_uuid' => $server->uuid,
];

View File

@@ -40,6 +40,20 @@ function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pul
return $containers;
}
function getCurrentServiceContainerStatus(Server $server, int $id): Collection
{
$containers = collect([]);
if (! $server->isSwarm()) {
$containers = instant_remote_process(["docker ps -a --filter='label=coolify.serviceId={$id}' --format '{{json .}}' "], $server);
$containers = format_docker_command_output_to_json($containers);
$containers = $containers->filter();
return $containers;
}
return $containers;
}
function format_docker_command_output_to_json($rawOutput): Collection
{
$outputLines = explode(PHP_EOL, $rawOutput);

View File

@@ -43,25 +43,23 @@ services:
- /data/coolify/_volumes/redis/:/data
# - coolify-redis-data-dev:/data
soketi:
build:
context: .
dockerfile: ./docker/coolify-realtime/Dockerfile
env_file:
- .env
ports:
- "${FORWARD_SOKETI_PORT:-6001}:6001"
- "6002:6002"
volumes:
- ./docker/soketi-entrypoint/soketi-entrypoint.sh:/soketi-entrypoint.sh
- ./package.json:/terminal/package.json
- ./package-lock.json:/terminal/package-lock.json
- ./terminal-server.js:/terminal/terminal-server.js
- ./storage:/var/www/html/storage
entrypoint: ["/bin/sh", "/soketi-entrypoint.sh"]
environment:
SOKETI_DEBUG: "false"
SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}"
SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}"
SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}"
vite:
image: node:alpine
image: node:20
pull_policy: always
working_dir: /var/www/html
# environment:

View File

@@ -109,6 +109,7 @@ services:
retries: 10
timeout: 2s
soketi:
image: 'ghcr.io/coollabsio/coolify-realtime:latest'
ports:
- "${SOKETI_PORT:-6001}:6001"
- "6002:6002"

View File

@@ -102,8 +102,8 @@ services:
interval: 5s
retries: 10
timeout: 2s
soketi:
image: 'quay.io/soketi/soketi:1.6-16-alpine'
soketi:
image: 'ghcr.io/coollabsio/coolify-realtime:latest'
pull_policy: always
container_name: coolify-realtime
restart: always

View File

@@ -24,7 +24,6 @@ services:
networks:
- coolify
soketi:
image: 'quay.io/soketi/soketi:1.6-16-alpine'
container_name: coolify-realtime
restart: always
networks:

View File

@@ -0,0 +1,9 @@
FROM quay.io/soketi/soketi:1.6-16-alpine
WORKDIR /terminal
RUN apk add --no-cache openssh-client make g++ python3
COPY docker/coolify-realtime/package.json ./
RUN npm i
RUN npm rebuild node-pty --update-binary
COPY docker/coolify-realtime/soketi-entrypoint.sh /soketi-entrypoint.sh
COPY docker/coolify-realtime/terminal-server.js /terminal/terminal-server.js
ENTRYPOINT ["/bin/sh", "/soketi-entrypoint.sh"]

View File

@@ -0,0 +1,13 @@
{
"private": true,
"type": "module",
"dependencies": {
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"cookie": "^0.6.0",
"axios": "1.7.5",
"dotenv": "^16.4.5",
"node-pty": "^1.0.0",
"ws": "^8.17.0"
}
}

View File

@@ -1,16 +1,4 @@
#!/bin/sh
# Install openssh-client
apk add --no-cache openssh-client make g++ python3
cd /terminal
# Install npm dependencies
npm ci
# Rebuild node-pty
npm rebuild node-pty --update-binary
# Function to timestamp logs
timestamp() {
date "+%Y-%m-%d %H:%M:%S"

View File

@@ -1,7 +1,8 @@
<div x-data="data()">
<div x-show="!terminalActive" class="flex items-center justify-center w-full py-4 mx-auto h-[510px]">
<div class="w-full h-full border rounded dark:bg-coolgray-100 dark:border-coolgray-300">
<span class="font-mono text-sm text-gray-500">(connection closed)</span>
<div
class="w-full h-full bg-white border border-solid rounded dark:text-white dark:bg-coolgray-100 scrollbar border-neutral-300 dark:border-coolgray-300 p-1">
<span class="font-mono text-sm text-gray-500 ">(connection closed)</span>
</div>
</div>
<div x-ref="terminalWrapper"
@@ -34,7 +35,9 @@
function initializeWebSocket() {
if (!socket || socket.readyState === WebSocket.CLOSED) {
const url = "{{ str_replace(['http://', 'https://'], '', config('app.url')) }}" || window.location.hostname;
let url = "{{ str_replace(['http://', 'https://'], '', config('app.url')) }}" || window.location.hostname;
// make sure the port is not included
url = url.split(':')[0];
socket = new WebSocket((window.location.protocol === 'https:' ? 'wss://' : 'ws://') +
url +
':6002/terminal');