Merge pull request #1002 from coollabsio/ijpatricio-wip-1
First SSH command on remote host.
This commit is contained in:
commit
1bb3117b05
27
.env.example
27
.env.example
@ -1,39 +1,24 @@
|
|||||||
############################################################################################################
|
############################################################################################################
|
||||||
# Development Environment
|
# Development Environment
|
||||||
|
|
||||||
# Userid for the user that will run the application inside the container
|
# User and group id for the user that will run the application inside the container
|
||||||
|
# Run in your terminal: `id -u` and `id -g` and that's the results
|
||||||
USERID=
|
USERID=
|
||||||
|
GROUPID=
|
||||||
############################################################################################################
|
############################################################################################################
|
||||||
|
|
||||||
APP_NAME=Laravel
|
APP_NAME=Laravel
|
||||||
|
APP_SERVICE=php
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_URL=http://localhost
|
APP_URL=http://localhost
|
||||||
|
|
||||||
LOG_CHANNEL=stack
|
|
||||||
LOG_DEPRECATIONS_CHANNEL=null
|
|
||||||
LOG_LEVEL=debug
|
|
||||||
|
|
||||||
DB_CONNECTION=pgsql
|
DB_CONNECTION=pgsql
|
||||||
DB_HOST=postgres
|
DB_HOST=postgres
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_DATABASE=coolify
|
DB_DATABASE=coolify
|
||||||
DB_USERNAME=sail
|
DB_USERNAME=coolify
|
||||||
DB_PASSWORD=password
|
DB_PASSWORD=password
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
QUEUE_CONNECTION=database
|
||||||
CACHE_DRIVER=file
|
|
||||||
FILESYSTEM_DISK=local
|
|
||||||
QUEUE_CONNECTION=sync
|
|
||||||
SESSION_DRIVER=file
|
|
||||||
SESSION_LIFETIME=120
|
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
|
||||||
MAIL_HOST=mailpit
|
|
||||||
MAIL_PORT=1025
|
|
||||||
MAIL_USERNAME=null
|
|
||||||
MAIL_PASSWORD=null
|
|
||||||
MAIL_ENCRYPTION=null
|
|
||||||
MAIL_FROM_ADDRESS="hello@example.com"
|
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
|
||||||
|
29
.github/workflows/docker-image.yml
vendored
Normal file
29
.github/workflows/docker-image.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
name: Docker Image CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "*" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Build the Docker image
|
||||||
|
run: |
|
||||||
|
docker run --rm -u "$(id -u):$(id -g)" \
|
||||||
|
-v "$(pwd):/app" \
|
||||||
|
-w /app composer:2 \
|
||||||
|
composer install --ignore-platform-reqs
|
||||||
|
TAG=$(date +%s) ./vendor/bin/sail build
|
||||||
|
TAG=$(date +%s) ./vendor/bin/sail up -d
|
||||||
|
sleep 1
|
||||||
|
./vendor/bin/sail ps
|
||||||
|
# Now to create .env
|
||||||
|
# Await database is created
|
||||||
|
# pest
|
26
Dockerfile
26
Dockerfile
@ -1,26 +0,0 @@
|
|||||||
FROM serversideup/php:8.2-fpm-nginx
|
|
||||||
|
|
||||||
ARG NODE_VERSION=18
|
|
||||||
ARG POSTGRES_VERSION=15
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
|
|
||||||
&& apt-get install -y nodejs \
|
|
||||||
&& npm install -g npm
|
|
||||||
|
|
||||||
RUN apt-get install -y php-pgsql
|
|
||||||
|
|
||||||
RUN apt-get -y autoremove \
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
|
|
||||||
|
|
||||||
# Adding test ssh key
|
|
||||||
RUN mkdir -p ~/.ssh
|
|
||||||
RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\
|
|
||||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\
|
|
||||||
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\
|
|
||||||
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\
|
|
||||||
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\
|
|
||||||
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\
|
|
||||||
-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519
|
|
||||||
RUN chmod 0600 ~/.ssh/id_ed25519
|
|
54
app/Http/Livewire/RunCommand.php
Executable file
54
app/Http/Livewire/RunCommand.php
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class RunCommand extends Component
|
||||||
|
{
|
||||||
|
public $activity;
|
||||||
|
|
||||||
|
public $isKeepAliveOn = false;
|
||||||
|
|
||||||
|
public $manualKeepAlive = false;
|
||||||
|
|
||||||
|
public $command = 'ls';
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.run-command');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runCommand()
|
||||||
|
{
|
||||||
|
$this->isKeepAliveOn = true;
|
||||||
|
|
||||||
|
$this->activity = coolifyProcess($this->command, 'testing-host');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runSleepingBeauty()
|
||||||
|
{
|
||||||
|
$this->isKeepAliveOn = true;
|
||||||
|
|
||||||
|
$this->activity = coolifyProcess('x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done', 'testing-host');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function runDummyProjectBuild()
|
||||||
|
{
|
||||||
|
$this->isKeepAliveOn = true;
|
||||||
|
|
||||||
|
$this->activity = coolifyProcess(<<<EOT
|
||||||
|
cd projects/dummy-project
|
||||||
|
~/.docker/cli-plugins/docker-compose build --no-cache
|
||||||
|
EOT, 'testing-host');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function polling()
|
||||||
|
{
|
||||||
|
$this->activity?->refresh();
|
||||||
|
|
||||||
|
if (data_get($this->activity, 'properties.exitCode') !== null) {
|
||||||
|
$this->isKeepAliveOn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
132
app/Jobs/ExecuteCoolifyProcess.php
Executable file
132
app/Jobs/ExecuteCoolifyProcess.php
Executable file
@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Services\ProcessStatus;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Process\InvokedProcess;
|
||||||
|
use Illuminate\Process\ProcessResult;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Process;
|
||||||
|
use Spatie\Activitylog\Contracts\Activity;
|
||||||
|
|
||||||
|
class ExecuteCoolifyProcess implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $throttleIntervalMS = 500;
|
||||||
|
|
||||||
|
protected $timeStart;
|
||||||
|
|
||||||
|
protected $currentTime;
|
||||||
|
|
||||||
|
protected $lastWriteAt = 0;
|
||||||
|
|
||||||
|
protected string $stdOutIncremental = '';
|
||||||
|
|
||||||
|
protected string $stdErrIncremental = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
public Activity $activity,
|
||||||
|
){}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*/
|
||||||
|
public function handle(): ProcessResult
|
||||||
|
{
|
||||||
|
$this->timeStart = hrtime(true);
|
||||||
|
|
||||||
|
$user = $this->activity->getExtraProperty('user');
|
||||||
|
$destination = $this->activity->getExtraProperty('destination');
|
||||||
|
$port = $this->activity->getExtraProperty('port');
|
||||||
|
$command = $this->activity->getExtraProperty('command');
|
||||||
|
|
||||||
|
$delimiter = 'EOF-COOLIFY-SSH';
|
||||||
|
|
||||||
|
$sshCommand = 'ssh '
|
||||||
|
. '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
|
||||||
|
. '-o PasswordAuthentication=no '
|
||||||
|
. '-o RequestTTY=no '
|
||||||
|
// Quiet mode. Causes most warning and diagnostic messages to be suppressed.
|
||||||
|
// Errors are still out put. This is to silence for example, that warning
|
||||||
|
// Permanently added <host and key type> to the list of known hosts.
|
||||||
|
. '-q '
|
||||||
|
. "-p {$port} "
|
||||||
|
. "{$user}@{$destination} "
|
||||||
|
. " 'bash -se' << \\$delimiter" . PHP_EOL
|
||||||
|
. $command . PHP_EOL
|
||||||
|
. $delimiter;
|
||||||
|
|
||||||
|
$process = Process::start($sshCommand, $this->handleOutput(...));
|
||||||
|
|
||||||
|
$processResult = $process->wait();
|
||||||
|
|
||||||
|
$status = match ($processResult->exitCode()) {
|
||||||
|
0 => ProcessStatus::FINISHED,
|
||||||
|
default => ProcessStatus::ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->activity->properties = $this->activity->properties->merge([
|
||||||
|
'exitCode' => $processResult->exitCode(),
|
||||||
|
'stdout' => $processResult->output(),
|
||||||
|
'stderr' => $processResult->errorOutput(),
|
||||||
|
'status' => $status,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->activity->save();
|
||||||
|
|
||||||
|
return $processResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleOutput(string $type, string $output)
|
||||||
|
{
|
||||||
|
$this->currentTime = $this->elapsedTime();
|
||||||
|
|
||||||
|
if ($type === 'out') {
|
||||||
|
$this->stdOutIncremental .= $output;
|
||||||
|
} else {
|
||||||
|
$this->stdErrIncremental .= $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->activity->description .= $output;
|
||||||
|
|
||||||
|
if ($this->isAfterLastThrottle()) {
|
||||||
|
// Let's write to database.
|
||||||
|
DB::transaction(function () {
|
||||||
|
$this->activity->save();
|
||||||
|
$this->lastWriteAt = $this->currentTime;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decides if it's time to write again to database.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isAfterLastThrottle()
|
||||||
|
{
|
||||||
|
// If DB was never written, then we immediately decide we have to write.
|
||||||
|
if ($this->lastWriteAt === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($this->currentTime - $this->throttleIntervalMS) > $this->lastWriteAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function elapsedTime(): int
|
||||||
|
{
|
||||||
|
$timeMs = (hrtime(true) - $this->timeStart) / 1_000_000;
|
||||||
|
|
||||||
|
return intval($timeMs);
|
||||||
|
}
|
||||||
|
}
|
47
app/Services/CoolifyProcess.php
Normal file
47
app/Services/CoolifyProcess.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Jobs\ExecuteCoolifyProcess;
|
||||||
|
use Illuminate\Process\ProcessResult;
|
||||||
|
use Spatie\Activitylog\Contracts\Activity;
|
||||||
|
|
||||||
|
class CoolifyProcess
|
||||||
|
{
|
||||||
|
protected Activity $activity;
|
||||||
|
|
||||||
|
// TODO Left 'root' as default user instead of 'coolify' because
|
||||||
|
// there's a task at TODO.md to run docker without sudo
|
||||||
|
public function __construct(
|
||||||
|
protected string $destination,
|
||||||
|
protected string $command,
|
||||||
|
protected ?int $port = 22,
|
||||||
|
protected ?string $user = 'root',
|
||||||
|
){
|
||||||
|
$this->activity = activity()
|
||||||
|
->withProperties([
|
||||||
|
'type' => 'COOLIFY_PROCESS',
|
||||||
|
'user' => $this->user,
|
||||||
|
'destination' => $this->destination,
|
||||||
|
'port' => $this->port,
|
||||||
|
'command' => $this->command,
|
||||||
|
'status' => ProcessStatus::HOLDING,
|
||||||
|
])
|
||||||
|
->log("Awaiting to start command...\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(): Activity|ProcessResult
|
||||||
|
{
|
||||||
|
$job = new ExecuteCoolifyProcess($this->activity);
|
||||||
|
|
||||||
|
if (app()->environment('testing')) {
|
||||||
|
return $job->handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch($job);
|
||||||
|
|
||||||
|
return $this->activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
11
app/Services/ProcessStatus.php
Normal file
11
app/Services/ProcessStatus.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
enum ProcessStatus: string
|
||||||
|
{
|
||||||
|
case HOLDING = 'holding';
|
||||||
|
case IN_PROGRESS = 'in_progress';
|
||||||
|
case FINISHED = 'finished';
|
||||||
|
case ERROR = 'error';
|
||||||
|
}
|
24
bootstrap/helpers.php
Normal file
24
bootstrap/helpers.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Services\CoolifyProcess;
|
||||||
|
use Illuminate\Process\ProcessResult;
|
||||||
|
use Spatie\Activitylog\Contracts\Activity;
|
||||||
|
|
||||||
|
if (! function_exists('coolifyProcess')) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a Coolify Process, which SSH's into a machine to run the command(s).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function coolifyProcess($command, $destination): Activity|ProcessResult
|
||||||
|
{
|
||||||
|
$process = resolve(CoolifyProcess::class, [
|
||||||
|
'destination' => $destination,
|
||||||
|
'command' => $command,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$activityLog = $process();
|
||||||
|
|
||||||
|
return $activityLog;
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,10 @@
|
|||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
"laravel/framework": "^10.0",
|
"laravel/framework": "^10.0",
|
||||||
"laravel/sanctum": "^3.2",
|
"laravel/sanctum": "^3.2",
|
||||||
"laravel/tinker": "^2.8"
|
"laravel/tinker": "^2.8",
|
||||||
|
"livewire/livewire": "^2.12",
|
||||||
|
"spatie/laravel-activitylog": "^4.7",
|
||||||
|
"spatie/laravel-ray": "^1.32"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
@ -17,10 +20,14 @@
|
|||||||
"laravel/sail": "^1.18",
|
"laravel/sail": "^1.18",
|
||||||
"mockery/mockery": "^1.4.4",
|
"mockery/mockery": "^1.4.4",
|
||||||
"nunomaduro/collision": "^7.0",
|
"nunomaduro/collision": "^7.0",
|
||||||
|
"pestphp/pest": "^2.0",
|
||||||
"phpunit/phpunit": "^10.0",
|
"phpunit/phpunit": "^10.0",
|
||||||
"spatie/laravel-ignition": "^2.0"
|
"spatie/laravel-ignition": "^2.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap/helpers.php"
|
||||||
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"App\\": "app/",
|
"App\\": "app/",
|
||||||
"Database\\Factories\\": "database/factories/",
|
"Database\\Factories\\": "database/factories/",
|
||||||
|
1821
composer.lock
generated
1821
composer.lock
generated
File diff suppressed because it is too large
Load Diff
108
config/ray.php
Normal file
108
config/ray.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
/*
|
||||||
|
* This setting controls whether data should be sent to Ray.
|
||||||
|
*
|
||||||
|
* By default, `ray()` will only transmit data in non-production environments.
|
||||||
|
*/
|
||||||
|
'enable' => env('RAY_ENABLED', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all cache events will automatically be sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_cache_to_ray' => env('SEND_CACHE_TO_RAY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all things passed to `dump` or `dd`
|
||||||
|
* will be sent to Ray as well.
|
||||||
|
*/
|
||||||
|
'send_dumps_to_ray' => env('SEND_DUMPS_TO_RAY', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled all job events will automatically be sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_jobs_to_ray' => env('SEND_JOBS_TO_RAY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all things logged to the application log
|
||||||
|
* will be sent to Ray as well.
|
||||||
|
*/
|
||||||
|
'send_log_calls_to_ray' => env('SEND_LOG_CALLS_TO_RAY', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all queries will automatically be sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_queries_to_ray' => env('SEND_QUERIES_TO_RAY', false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When enabled, all duplicate queries will automatically be sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_duplicate_queries_to_ray' => env('SEND_DUPLICATE_QUERIES_TO_RAY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, slow queries will automatically be sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_slow_queries_to_ray' => env('SEND_SLOW_QUERIES_TO_RAY', false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries that are longer than this number of milliseconds will be regarded as slow.
|
||||||
|
*/
|
||||||
|
'slow_query_threshold_in_ms' => env('RAY_SLOW_QUERY_THRESHOLD_IN_MS', 500),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all requests made to this app will automatically be sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_requests_to_ray' => env('SEND_REQUESTS_TO_RAY', false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When enabled, all Http Client requests made by this app will be automatically sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_http_client_requests_to_ray' => env('SEND_HTTP_CLIENT_REQUESTS_TO_RAY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all views that are rendered automatically be sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_views_to_ray' => env('SEND_VIEWS_TO_RAY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all exceptions will be automatically sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_exceptions_to_ray' => env('SEND_EXCEPTIONS_TO_RAY', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, all deprecation notices will be automatically sent to Ray.
|
||||||
|
*/
|
||||||
|
'send_deprecated_notices_to_ray' => env('SEND_DEPRECATED_NOTICES_TO_RAY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The host used to communicate with the Ray app.
|
||||||
|
* When using Docker on Mac or Windows, you can replace localhost with 'host.docker.internal'
|
||||||
|
* When using Docker on Linux, you can replace localhost with '172.17.0.1'
|
||||||
|
* When using Homestead with the VirtualBox provider, you can replace localhost with '10.0.2.2'
|
||||||
|
* When using Homestead with the Parallels provider, you can replace localhost with '10.211.55.2'
|
||||||
|
*/
|
||||||
|
'host' => env('RAY_HOST', 'host.docker.internal'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The port number used to communicate with the Ray app.
|
||||||
|
*/
|
||||||
|
'port' => env('RAY_PORT', 23517),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Absolute base path for your sites or projects in Homestead,
|
||||||
|
* Vagrant, Docker, or another remote development server.
|
||||||
|
*/
|
||||||
|
'remote_path' => env('RAY_REMOTE_PATH', null),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Absolute base path for your sites or projects on your local
|
||||||
|
* computer where your IDE or code editor is running on.
|
||||||
|
*/
|
||||||
|
'local_path' => env('RAY_LOCAL_PATH', null),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When this setting is enabled, the package will not try to format values sent to Ray.
|
||||||
|
*/
|
||||||
|
'always_send_raw_values' => false,
|
||||||
|
];
|
27
database/migrations/2023_03_20_112410_create_activity_log_table.php
Executable file
27
database/migrations/2023_03_20_112410_create_activity_log_table.php
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateActivityLogTable extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::connection(config('activitylog.database_connection'))->create(config('activitylog.table_name'), function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->string('log_name')->nullable();
|
||||||
|
$table->text('description');
|
||||||
|
$table->nullableMorphs('subject', 'subject');
|
||||||
|
$table->nullableMorphs('causer', 'causer');
|
||||||
|
$table->json('properties')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->index('log_name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name'));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddEventColumnToActivityLogTable extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||||
|
$table->string('event')->nullable()->after('subject_type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||||
|
$table->dropColumn('event');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddBatchUuidColumnToActivityLogTable extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||||
|
$table->uuid('batch_uuid')->nullable()->after('properties');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::connection(config('activitylog.database_connection'))->table(config('activitylog.table_name'), function (Blueprint $table) {
|
||||||
|
$table->dropColumn('batch_uuid');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
32
database/migrations/2023_03_20_112810_create_jobs_table.php
Executable file
32
database/migrations/2023_03_20_112810_create_jobs_table.php
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
<?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::create('jobs', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->string('queue')->index();
|
||||||
|
$table->longText('payload');
|
||||||
|
$table->unsignedTinyInteger('attempts');
|
||||||
|
$table->unsignedInteger('reserved_at')->nullable();
|
||||||
|
$table->unsignedInteger('available_at');
|
||||||
|
$table->unsignedInteger('created_at');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('jobs');
|
||||||
|
}
|
||||||
|
};
|
@ -1,24 +1,32 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
services:
|
services:
|
||||||
php:
|
php:
|
||||||
|
image: "coolify:${TAG:-4}"
|
||||||
build:
|
build:
|
||||||
context: .
|
context: ./docker/dev
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
WWWGROUP: '${WWWGROUP}'
|
||||||
ports:
|
ports:
|
||||||
- "${APP_PORT:-8000}:80"
|
- "${APP_PORT:-8000}:80"
|
||||||
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
|
- "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
|
||||||
environment:
|
environment:
|
||||||
PGID: "${USERID:-9999}"
|
WWWUSER: "${WWWUSER}"
|
||||||
PUID: "${USERID:-9999}"
|
LARAVEL_SAIL: 1
|
||||||
SSL_MODE: 'off'
|
XDEBUG_MODE: "${SAIL_XDEBUG_MODE:-off}"
|
||||||
|
XDEBUG_CONFIG: "${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}"
|
||||||
volumes:
|
volumes:
|
||||||
- .:/var/www/html:cached
|
- .:/var/www/html
|
||||||
|
networks:
|
||||||
|
- coolify
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:15-alpine
|
image: postgres:15-alpine
|
||||||
ports:
|
ports:
|
||||||
- "${FORWARD_DB_PORT:-5432}:5432"
|
- "${FORWARD_DB_PORT:-5432}:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- db-coolify:/var/lib/postgresql/data
|
- db-coolify:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- coolify
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: "${DB_USERNAME}"
|
POSTGRES_USER: "${DB_USERNAME}"
|
||||||
POSTGRES_PASSWORD: "${DB_PASSWORD}"
|
POSTGRES_PASSWORD: "${DB_PASSWORD}"
|
||||||
@ -34,11 +42,22 @@ services:
|
|||||||
]
|
]
|
||||||
retries: 3
|
retries: 3
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
mailpit:
|
testing-host:
|
||||||
image: "axllent/mailpit:latest"
|
container_name: coolify-testing-host
|
||||||
ports:
|
image: coolify-testing-host
|
||||||
- "${FORWARD_MAILPIT_PORT:-1025}:1025"
|
build:
|
||||||
- "${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025"
|
dockerfile: Dockerfile
|
||||||
|
context: ./docker/testing-host
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./docker/testing-host/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf
|
||||||
|
networks:
|
||||||
|
- coolify
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
db-coolify:
|
db-coolify:
|
||||||
driver: local
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
coolify:
|
||||||
|
driver: bridge
|
||||||
|
93
docker/dev/Dockerfile
Normal file
93
docker/dev/Dockerfile
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
ARG WWWGROUP
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
|
ARG NODE_VERSION=18
|
||||||
|
ARG POSTGRES_VERSION=14
|
||||||
|
|
||||||
|
# https://download.docker.com/linux/static/stable/
|
||||||
|
ARG DOCKER_VERSION=20.10.18
|
||||||
|
# https://github.com/docker/compose/releases
|
||||||
|
# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug.
|
||||||
|
ARG DOCKER_COMPOSE_VERSION=2.6.1
|
||||||
|
# https://github.com/buildpacks/pack/releases
|
||||||
|
ARG PACK_VERSION=v0.27.0
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV TZ=UTC
|
||||||
|
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \
|
||||||
|
&& curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \
|
||||||
|
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y php8.2-cli php8.2-dev \
|
||||||
|
php8.2-pgsql php8.2-sqlite3 php8.2-gd \
|
||||||
|
php8.2-curl \
|
||||||
|
php8.2-imap php8.2-mysql php8.2-mbstring \
|
||||||
|
php8.2-xml php8.2-zip php8.2-bcmath php8.2-soap \
|
||||||
|
php8.2-intl php8.2-readline \
|
||||||
|
php8.2-ldap \
|
||||||
|
php8.2-msgpack php8.2-igbinary php8.2-redis php8.2-swoole \
|
||||||
|
php8.2-memcached php8.2-pcov php8.2-xdebug \
|
||||||
|
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
|
||||||
|
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
|
||||||
|
&& apt-get install -y nodejs \
|
||||||
|
&& npm install -g npm \
|
||||||
|
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarn.gpg >/dev/null \
|
||||||
|
&& echo "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
|
||||||
|
&& curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /usr/share/keyrings/pgdg.gpg >/dev/null \
|
||||||
|
&& echo "deb [signed-by=/usr/share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt jammy-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y yarn \
|
||||||
|
&& apt-get install -y mysql-client \
|
||||||
|
&& apt-get install -y postgresql-client-$POSTGRES_VERSION \
|
||||||
|
&& apt-get -y autoremove \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2
|
||||||
|
|
||||||
|
RUN groupadd --force -g $WWWGROUP sail
|
||||||
|
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
|
||||||
|
|
||||||
|
USER sail
|
||||||
|
RUN mkdir -p ~/.ssh
|
||||||
|
RUN echo "-----BEGIN OPENSSH PRIVATE KEY-----\n\
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n\
|
||||||
|
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk\n\
|
||||||
|
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA\n\
|
||||||
|
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV\n\
|
||||||
|
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==\n\
|
||||||
|
-----END OPENSSH PRIVATE KEY-----" >> ~/.ssh/id_ed25519
|
||||||
|
RUN chmod 0600 ~/.ssh/id_ed25519
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
COPY start-container /usr/local/bin/start-container
|
||||||
|
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
COPY php.ini /etc/php/8.2/cli/conf.d/99-sail.ini
|
||||||
|
RUN chmod +x /usr/local/bin/start-container
|
||||||
|
|
||||||
|
# Install Docker CLI, Docker Compose, and Pack
|
||||||
|
RUN mkdir -p ~/.docker/cli-plugins
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose -o /home/sail/.docker/cli-plugins/docker-compose
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack
|
||||||
|
RUN curl -sSL https://nixpacks.com/install.sh | bash
|
||||||
|
|
||||||
|
RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack
|
||||||
|
RUN chmod +x /usr/local/bin/pack
|
||||||
|
|
||||||
|
RUN mkdir -p /home/sail/.docker/cli-plugins
|
||||||
|
RUN cp ~/.docker/cli-plugins/docker-compose /home/sail/.docker/cli-plugins/docker-compose
|
||||||
|
RUN chown -R sail:sail /home/sail
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
ENTRYPOINT ["start-container"]
|
4
docker/dev/php.ini
Normal file
4
docker/dev/php.ini
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[PHP]
|
||||||
|
post_max_size = 100M
|
||||||
|
upload_max_filesize = 100M
|
||||||
|
variables_order = EGPCS
|
17
docker/dev/start-container
Normal file
17
docker/dev/start-container
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ ! -z "$WWWUSER" ]; then
|
||||||
|
usermod -u $WWWUSER sail
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d /.composer ]; then
|
||||||
|
mkdir /.composer
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod -R ugo+rw /.composer
|
||||||
|
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
exec gosu $WWWUSER "$@"
|
||||||
|
else
|
||||||
|
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
fi
|
27
docker/dev/supervisord.conf
Normal file
27
docker/dev/supervisord.conf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/var/log/supervisor/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:php]
|
||||||
|
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan serve --host=0.0.0.0 --port=80
|
||||||
|
user=sail
|
||||||
|
environment=LARAVEL_SAIL="1"
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:laravel-worker]
|
||||||
|
process_name=%(program_name)s_%(process_num)02d
|
||||||
|
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan queue:listen
|
||||||
|
user=sail
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stopasgroup=true
|
||||||
|
killasgroup=true
|
||||||
|
numprocs=8
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/var/www/html/storage/logs/worker.log
|
||||||
|
stopwaitsecs=3600
|
20
docker/staging/Dockerfile
Normal file
20
docker/staging/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
FROM serversideup/php:8.2-fpm-nginx
|
||||||
|
|
||||||
|
ARG NODE_VERSION=18
|
||||||
|
ARG POSTGRES_VERSION=15
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& curl -sLS https://deb.nodesource.com/setup_$NODE_VERSION.x | bash - \
|
||||||
|
&& apt-get install -y nodejs \
|
||||||
|
&& npm install -g npm
|
||||||
|
|
||||||
|
RUN apt-get install -y php-pgsql openssh-client
|
||||||
|
|
||||||
|
RUN apt-get -y autoremove \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
# S6 Overlay config
|
||||||
|
COPY --chmod=755 etc/s6-overlay/ /etc/s6-overlay/
|
2
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/run
Normal file
2
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/run
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/command/execlineb -P
|
||||||
|
su webuser -c "php /var/www/html/artisan queue:listen --tries=3"
|
1
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/type
Normal file
1
docker/staging/etc/s6-overlay/s6-rc.d/queue-worker/type
Normal file
@ -0,0 +1 @@
|
|||||||
|
longrun
|
67
docker/testing-host/Dockerfile
Normal file
67
docker/testing-host/Dockerfile
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
|
# https://download.docker.com/linux/static/stable/
|
||||||
|
ARG DOCKER_VERSION=20.10.18
|
||||||
|
# https://github.com/docker/compose/releases
|
||||||
|
# Reverted to 2.6.1 because of this https://github.com/docker/compose/issues/9704. 2.9.0 still has a bug.
|
||||||
|
ARG DOCKER_COMPOSE_VERSION=2.6.1
|
||||||
|
# https://github.com/buildpacks/pack/releases
|
||||||
|
ARG PACK_VERSION=v0.27.0
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV TZ=UTC
|
||||||
|
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor \
|
||||||
|
sqlite3 libcap2-bin libpng-dev python2 dnsutils openssh-server sudo \
|
||||||
|
&& apt-get -y autoremove \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
# Setup sshd
|
||||||
|
RUN ssh-keygen -A
|
||||||
|
RUN mkdir -p /run/sshd
|
||||||
|
|
||||||
|
# Install Docker CLI, Docker Compose, and Pack
|
||||||
|
RUN mkdir -p ~/.docker/cli-plugins
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-$DOCKER_VERSION -o /usr/bin/docker
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/docker-compose-linux-$DOCKER_COMPOSE_VERSION -o ~/.docker/cli-plugins/docker-compose
|
||||||
|
RUN curl -SL https://cdn.coollabs.io/bin/$TARGETPLATFORM/pack-$PACK_VERSION -o /usr/local/bin/pack
|
||||||
|
RUN curl -sSL https://nixpacks.com/install.sh | bash
|
||||||
|
RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack
|
||||||
|
RUN groupadd docker
|
||||||
|
|
||||||
|
# Setup coolify user
|
||||||
|
RUN useradd -ms /bin/bash coolify
|
||||||
|
RUN usermod -aG sudo coolify
|
||||||
|
RUN usermod -aG docker coolify
|
||||||
|
RUN echo 'coolify ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||||
|
|
||||||
|
# Setup ssh'ing into the destination as Coolify User
|
||||||
|
USER coolify
|
||||||
|
RUN mkdir -p ~/.ssh
|
||||||
|
RUN echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68 coolify@coolify-instance" >> ~/.ssh/authorized_keys
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
# Setup ssh'ing into the destination as Root
|
||||||
|
RUN mkdir -p ~/.ssh
|
||||||
|
RUN echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68 coolify@coolify-instance" >> ~/.ssh/authorized_keys
|
||||||
|
|
||||||
|
EXPOSE 22
|
||||||
|
|
||||||
|
COPY start-container /usr/local/bin/start-container
|
||||||
|
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
RUN chmod +x /usr/local/bin/start-container
|
||||||
|
|
||||||
|
WORKDIR /root
|
||||||
|
|
||||||
|
# Prepare projects
|
||||||
|
RUN mkdir -p projects
|
||||||
|
COPY dummy-project projects/dummy-project
|
||||||
|
|
||||||
|
ENTRYPOINT ["start-container"]
|
31
docker/testing-host/dummy-project/Dockerfile
Normal file
31
docker/testing-host/dummy-project/Dockerfile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
|
ARG WWWGROUP
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV TZ=UTC
|
||||||
|
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y gnupg gosu curl ca-certificates zip unzip git git-lfs supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils \
|
||||||
|
&& curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /usr/share/keyrings/ppa_ondrej_php.gpg > /dev/null \
|
||||||
|
&& echo "deb [signed-by=/usr/share/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y php8.2-cli php8.2-dev \
|
||||||
|
php8.2-curl php8.2-mbstring php8.2-xml php8.2-zip php8.2-bcmath \
|
||||||
|
php8.2-intl php8.2-readline php8.2-msgpack php8.2-igbinary \
|
||||||
|
&& php -r "readfile('https://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
|
||||||
|
&& apt-get -y autoremove \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.2
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENTRYPOINT ["php", "-S", "0.0.0.0:8000"]
|
10
docker/testing-host/dummy-project/docker-compose.yml
Normal file
10
docker/testing-host/dummy-project/docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
dummy-project:
|
||||||
|
image: dummy-project
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
3
docker/testing-host/dummy-project/index.php
Normal file
3
docker/testing-host/dummy-project/index.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
echo "Hello World! " . date('Y-m-d H:i:s');
|
3
docker/testing-host/start-container
Normal file
3
docker/testing-host/start-container
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
13
docker/testing-host/supervisord.conf
Normal file
13
docker/testing-host/supervisord.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/var/log/supervisor/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:sshd]
|
||||||
|
command=/usr/sbin/sshd -D
|
||||||
|
user=root
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
@ -1,3 +1,3 @@
|
|||||||
@tailwind base;
|
/* @tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities; */
|
||||||
|
3
resources/views/components/button.blade.php
Normal file
3
resources/views/components/button.blade.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<button wire:loading.remove {{ $attributes }} class="btn btn-primary rounded-none btn-xs no-animation"> {{ $slot }} </button>
|
||||||
|
|
||||||
|
<button wire:loading class="btn btn-disabled rounded-none btn-xs no-animation"> {{ $slot }}</button>
|
24
resources/views/components/layout.blade.php
Normal file
24
resources/views/components/layout.blade.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" data-theme="light" class="h-full">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{{ $title ?? 'Coolify' }}</title>
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
@vite(['resources/js/app.js', 'resources/css/app.css'])
|
||||||
|
@livewireStyles
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="h-full">
|
||||||
|
@auth
|
||||||
|
<x-navbar />
|
||||||
|
@endauth
|
||||||
|
<main class="h-full pt-10 p-4">
|
||||||
|
{{ $slot }}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
@livewireScripts
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
15
resources/views/components/navbar.blade.php
Normal file
15
resources/views/components/navbar.blade.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<nav class="flex space-x-4 p-2 fixed right-0">
|
||||||
|
@env('local')
|
||||||
|
<a href="/run-command">Run command</a>
|
||||||
|
{{-- <livewire:create-token /> --}}
|
||||||
|
<a href="/debug">Debug</a>
|
||||||
|
<a href="/debug/logs" target="_blank">Debug Logs</a>
|
||||||
|
{{-- <a href="/debug/inertia">Debug(inertia)</a> --}}
|
||||||
|
@endenv
|
||||||
|
<a href="/">Dashboard</a>
|
||||||
|
<a href="/profile">Profile</a>
|
||||||
|
<form action="/logout" method="POST">
|
||||||
|
@csrf
|
||||||
|
<button type="submit">Logout</button>
|
||||||
|
</form>
|
||||||
|
</nav>
|
5
resources/views/demo.blade.php
Normal file
5
resources/views/demo.blade.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<x-layout>
|
||||||
|
|
||||||
|
<livewire:run-command />
|
||||||
|
|
||||||
|
</x-layout>
|
29
resources/views/livewire/run-command.blade.php
Executable file
29
resources/views/livewire/run-command.blade.php
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<label for="command">
|
||||||
|
<input class="py-2 rounded ring-1" id="command" wire:model="command" type="text" />
|
||||||
|
</label>
|
||||||
|
<button wire:click="runCommand">Run command</button>
|
||||||
|
|
||||||
|
<button wire:click="runSleepingBeauty">Run sleeping beauty</button>
|
||||||
|
<button wire:click="runDummyProjectBuild">Build DummyProject</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="manualKeepAlive" name="manualKeepAlive" type="checkbox" wire:model="manualKeepAlive">
|
||||||
|
<label for="manualKeepAlive">Real-time logs</label>
|
||||||
|
@if ($isKeepAliveOn || $manualKeepAlive)
|
||||||
|
Polling...
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@isset($activity?->id)
|
||||||
|
<div>
|
||||||
|
Activity: <span>{{ $activity?->id ?? 'waiting' }}</span>
|
||||||
|
</div>
|
||||||
|
<pre style="width: 100%;overflow-y: scroll;"
|
||||||
|
@if ($isKeepAliveOn || $manualKeepAlive) wire:poll.750ms="polling" @endif> {{ data_get($activity, 'description') }}</pre>
|
||||||
|
<div>
|
||||||
|
<div>Details:</div>
|
||||||
|
<pre style="width: 100%;overflow-y: scroll;">{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}</pre>
|
||||||
|
</div>
|
||||||
|
@endisset
|
||||||
|
</div>
|
@ -11,8 +11,12 @@
|
|||||||
|
|
||||||
<body class="antialiased">
|
<body class="antialiased">
|
||||||
<h1 class="text-3xl font-bold">
|
<h1 class="text-3xl font-bold">
|
||||||
Hello from Coolify!
|
Coolify v4
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<p class="mt-4">
|
||||||
|
<a href="/demo"> See demo </a>
|
||||||
|
</p>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -16,3 +16,5 @@
|
|||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return view('welcome');
|
return view('welcome');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::view('/demo', 'demo');
|
||||||
|
39
run
Executable file
39
run
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Inspired on https://github.com/adriancooney/Taskfile
|
||||||
|
# Install an alias, to be able to simply execute `run` => echo 'alias run=./run' >> ~/.aliases
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function help {
|
||||||
|
echo "$0 <task> <args>"
|
||||||
|
echo "Tasks:"
|
||||||
|
compgen -A function | cat -n
|
||||||
|
}
|
||||||
|
|
||||||
|
function default {
|
||||||
|
help
|
||||||
|
}
|
||||||
|
|
||||||
|
function bash {
|
||||||
|
docker-compose exec -u $(id -u) php bash
|
||||||
|
}
|
||||||
|
|
||||||
|
# The user with native SSH capability
|
||||||
|
function coolify-bash {
|
||||||
|
docker-compose exec -u coolify php bash
|
||||||
|
}
|
||||||
|
|
||||||
|
function root-bash {
|
||||||
|
docker-compose exec php bash
|
||||||
|
}
|
||||||
|
|
||||||
|
# Usage: ./Taskfile envFile:set FOOBAR abc
|
||||||
|
# This will set the FOOBAR variable to "abc" in the .env file
|
||||||
|
function envFile:set {
|
||||||
|
sed -i "s#^$1=.*#$1=$2#g" .env
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMEFORMAT="Task completed in %3lR"
|
||||||
|
time "${@:-default}"
|
32
tests/Feature/DockerCommandsTest.php
Normal file
32
tests/Feature/DockerCommandsTest.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Tests\Support\Output;
|
||||||
|
|
||||||
|
it('starts a docker container correctly', function () {
|
||||||
|
|
||||||
|
$coolifyNamePrefix = 'coolify_test_';
|
||||||
|
$format = '{"ID":"{{ .ID }}", "Image": "{{ .Image }}", "Names":"{{ .Names }}"}';
|
||||||
|
$areThereCoolifyTestContainers = "docker ps --filter=\"name={$coolifyNamePrefix}*\" --format '{$format}' ";
|
||||||
|
|
||||||
|
// Generate a known name
|
||||||
|
$containerName = 'coolify_test_' . now()->format('Ymd_his');
|
||||||
|
$host = 'testing-host';
|
||||||
|
|
||||||
|
// Assert there's no containers start with coolify_test_*
|
||||||
|
$processResult = coolifyProcess($areThereCoolifyTestContainers, $host);
|
||||||
|
$containers = Output::containerList($processResult->output());
|
||||||
|
expect($containers)->toBeEmpty();
|
||||||
|
|
||||||
|
// start a container nginx -d --name = $containerName
|
||||||
|
$processResult = coolifyProcess("docker run -d --name {$containerName} nginx", $host);
|
||||||
|
expect($processResult->successful())->toBeTrue();
|
||||||
|
|
||||||
|
// docker ps name = $container
|
||||||
|
$processResult = coolifyProcess($areThereCoolifyTestContainers, $host);
|
||||||
|
$containers = Output::containerList($processResult->output());
|
||||||
|
expect($containers->where('Names', $containerName)->count())->toBe(1);
|
||||||
|
|
||||||
|
// Stop testing containers
|
||||||
|
$processResult = coolifyProcess("docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)", $host);
|
||||||
|
expect($processResult->successful())->toBeTrue();
|
||||||
|
});
|
@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Feature;
|
|
||||||
|
|
||||||
// use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
||||||
use Tests\TestCase;
|
|
||||||
|
|
||||||
class ExampleTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A basic test example.
|
|
||||||
*/
|
|
||||||
public function test_the_application_returns_a_successful_response(): void
|
|
||||||
{
|
|
||||||
$response = $this->get('/');
|
|
||||||
|
|
||||||
$response->assertStatus(200);
|
|
||||||
}
|
|
||||||
}
|
|
48
tests/Pest.php
Normal file
48
tests/Pest.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Test Case
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
|
||||||
|
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
|
||||||
|
| need to change it using the "uses()" function to bind a different classes or traits.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
uses(
|
||||||
|
Tests\TestCase::class,
|
||||||
|
// Illuminate\Foundation\Testing\RefreshDatabase::class,
|
||||||
|
)->in('Feature');
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Expectations
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When you're writing tests, you often need to check that values meet certain conditions. The
|
||||||
|
| "expect()" function gives you access to a set of "expectations" methods that you can use
|
||||||
|
| to assert different things. Of course, you may extend the Expectation API at any time.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
expect()->extend('toBeOne', function () {
|
||||||
|
return $this->toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Functions
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
|
||||||
|
| project that you don't want to repeat in every file. Here you can also expose helpers as
|
||||||
|
| global functions to help you to reduce the number of lines of code in your test files.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
function something()
|
||||||
|
{
|
||||||
|
// ..
|
||||||
|
}
|
17
tests/Support/Output.php
Normal file
17
tests/Support/Output.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Support;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class Output
|
||||||
|
{
|
||||||
|
public static function containerList($rawOutput): Collection
|
||||||
|
{
|
||||||
|
$outputLines = explode(PHP_EOL, $rawOutput);
|
||||||
|
|
||||||
|
return collect($outputLines)
|
||||||
|
->reject(fn($line) => empty($line))
|
||||||
|
->map(fn($outputLine) => json_decode($outputLine, flags: JSON_THROW_ON_ERROR));
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Tests\Unit;
|
test('that true is true', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
use PHPUnit\Framework\TestCase;
|
});
|
||||||
|
|
||||||
class ExampleTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A basic test example.
|
|
||||||
*/
|
|
||||||
public function test_that_true_is_true(): void
|
|
||||||
{
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user