2023-05-24 12:26:50 +00:00
< ? php
2024-06-11 10:37:39 +00:00
use App\Enums\ApplicationDeploymentStatus ;
2024-08-23 18:54:38 +00:00
use App\Enums\ProxyTypes ;
2024-03-13 17:26:30 +00:00
use App\Jobs\ServerFilesFromServerJob ;
2023-10-20 12:51:01 +00:00
use App\Models\Application ;
2024-06-12 09:31:14 +00:00
use App\Models\ApplicationDeploymentQueue ;
2024-08-23 18:54:38 +00:00
use App\Models\ApplicationPreview ;
use App\Models\EnvironmentVariable ;
2024-11-12 10:32:18 +00:00
use App\Models\GithubApp ;
2023-06-12 10:00:01 +00:00
use App\Models\InstanceSettings ;
2023-11-24 14:48:23 +00:00
use App\Models\LocalFileVolume ;
use App\Models\LocalPersistentVolume ;
2023-09-28 08:53:00 +00:00
use App\Models\Server ;
2023-10-20 12:51:01 +00:00
use App\Models\Service ;
2023-11-24 14:48:23 +00:00
use App\Models\ServiceApplication ;
2024-08-23 18:54:38 +00:00
use App\Models\ServiceDatabase ;
2024-04-10 13:00:46 +00:00
use App\Models\StandaloneClickhouse ;
use App\Models\StandaloneDragonfly ;
use App\Models\StandaloneKeydb ;
2023-10-25 08:43:07 +00:00
use App\Models\StandaloneMariadb ;
2023-10-20 12:51:01 +00:00
use App\Models\StandaloneMongodb ;
2023-10-25 08:43:07 +00:00
use App\Models\StandaloneMysql ;
2023-10-20 12:51:01 +00:00
use App\Models\StandalonePostgresql ;
use App\Models\StandaloneRedis ;
2023-08-16 14:03:30 +00:00
use App\Models\Team ;
2023-09-14 16:22:08 +00:00
use App\Models\User ;
2024-10-31 15:47:08 +00:00
use Carbon\CarbonImmutable ;
2023-08-16 14:03:30 +00:00
use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException ;
2024-01-30 08:48:51 +00:00
use Illuminate\Database\UniqueConstraintViolationException ;
2024-04-25 11:52:52 +00:00
use Illuminate\Process\Pool ;
2024-04-16 18:57:54 +00:00
use Illuminate\Support\Collection ;
2024-11-04 13:18:16 +00:00
use Illuminate\Support\Facades\Auth ;
2023-09-15 09:19:36 +00:00
use Illuminate\Support\Facades\Cache ;
2023-10-04 12:40:26 +00:00
use Illuminate\Support\Facades\File ;
2023-05-24 12:26:50 +00:00
use Illuminate\Support\Facades\Http ;
2024-04-25 11:52:52 +00:00
use Illuminate\Support\Facades\Process ;
2024-10-25 13:13:23 +00:00
use Illuminate\Support\Facades\RateLimiter ;
2023-12-11 19:01:54 +00:00
use Illuminate\Support\Facades\Request ;
2023-05-24 12:26:50 +00:00
use Illuminate\Support\Facades\Route ;
2024-06-26 11:32:36 +00:00
use Illuminate\Support\Facades\Validator ;
2023-05-24 12:26:50 +00:00
use Illuminate\Support\Str ;
2023-09-27 10:45:53 +00:00
use Illuminate\Support\Stringable ;
2025-01-10 17:27:48 +00:00
use Laravel\Horizon\Contracts\JobRepository ;
2024-02-28 12:48:39 +00:00
use Lcobucci\JWT\Encoding\ChainedFormatter ;
use Lcobucci\JWT\Encoding\JoseEncoder ;
use Lcobucci\JWT\Signer\Hmac\Sha256 ;
2024-06-10 20:43:34 +00:00
use Lcobucci\JWT\Signer\Key\InMemory ;
2024-02-28 12:48:39 +00:00
use Lcobucci\JWT\Token\Builder ;
2024-04-03 11:45:49 +00:00
use phpseclib3\Crypt\EC ;
2023-08-22 15:44:49 +00:00
use phpseclib3\Crypt\RSA ;
2024-06-10 20:43:34 +00:00
use Poliander\Cron\CronExpression ;
use PurplePixie\PhpDns\DNSQuery ;
2023-09-22 12:47:25 +00:00
use Spatie\Url\Url ;
2023-11-24 14:48:23 +00:00
use Symfony\Component\Yaml\Yaml ;
2024-06-10 20:43:34 +00:00
use Visus\Cuid2\Cuid2 ;
2023-05-24 12:26:50 +00:00
2023-09-21 15:48:31 +00:00
function base_configuration_dir () : string
{
return '/data/coolify' ;
}
2023-08-09 13:57:53 +00:00
function application_configuration_dir () : string
{
2024-12-09 14:38:21 +00:00
return base_configuration_dir () . '/applications' ;
2023-09-21 15:48:31 +00:00
}
function service_configuration_dir () : string
{
2024-12-09 14:38:21 +00:00
return base_configuration_dir () . '/services' ;
2023-08-09 12:44:36 +00:00
}
2023-08-09 13:57:53 +00:00
function database_configuration_dir () : string
{
2024-12-09 14:38:21 +00:00
return base_configuration_dir () . '/databases' ;
2023-08-09 12:44:36 +00:00
}
2023-09-07 11:23:34 +00:00
function database_proxy_dir ( $uuid ) : string
{
2024-12-09 14:38:21 +00:00
return base_configuration_dir () . " /databases/ $uuid /proxy " ;
2023-09-07 11:23:34 +00:00
}
2023-08-09 13:57:53 +00:00
function backup_dir () : string
{
2024-12-09 14:38:21 +00:00
return base_configuration_dir () . '/backups' ;
2023-08-09 12:44:36 +00:00
}
2024-06-20 08:44:31 +00:00
function metrics_dir () : string
{
2024-12-09 14:38:21 +00:00
return base_configuration_dir () . '/metrics' ;
2024-06-20 08:44:31 +00:00
}
2023-08-09 13:57:53 +00:00
2024-12-03 14:39:24 +00:00
function sanitize_string ( ? string $input = null ) : ? string
2024-12-02 21:49:41 +00:00
{
2024-12-03 14:39:24 +00:00
if ( is_null ( $input )) {
return null ;
}
2024-12-02 21:49:41 +00:00
// Remove any HTML/PHP tags
$sanitized = strip_tags ( $input );
// Convert special characters to HTML entities
$sanitized = htmlspecialchars ( $sanitized , ENT_QUOTES | ENT_HTML5 , 'UTF-8' );
// Remove any control characters
$sanitized = preg_replace ( '/[\x00-\x1F\x7F]/u' , '' , $sanitized );
// Trim whitespace
$sanitized = trim ( $sanitized );
return $sanitized ;
2024-06-20 08:44:31 +00:00
}
2023-08-09 13:57:53 +00:00
function generate_readme_file ( string $name , string $updated_at ) : string
{
2024-12-02 21:49:41 +00:00
$name = sanitize_string ( $name );
$updated_at = sanitize_string ( $updated_at );
2023-08-09 13:57:53 +00:00
return " Resource name: $name\nLatest Deployment Date: $updated_at " ;
2023-08-09 12:44:36 +00:00
}
2023-08-22 15:44:49 +00:00
function isInstanceAdmin ()
2023-08-14 14:56:13 +00:00
{
2023-08-22 15:44:49 +00:00
return auth () ? -> user () ? -> isInstanceAdmin () ? ? false ;
2023-08-14 14:56:13 +00:00
}
2023-08-22 15:44:49 +00:00
function currentTeam ()
{
2024-11-04 13:18:16 +00:00
return Auth :: user () ? -> currentTeam () ? ? null ;
2023-08-22 15:44:49 +00:00
}
function showBoarding () : bool
{
2024-11-05 10:53:11 +00:00
if ( Auth :: user () ? -> isMember ()) {
2024-05-21 12:29:06 +00:00
return false ;
}
2024-06-10 20:43:34 +00:00
2023-08-27 13:44:36 +00:00
return currentTeam () -> show_boarding ? ? false ;
2023-08-22 15:44:49 +00:00
}
2023-09-08 16:33:26 +00:00
function refreshSession ( ? Team $team = null ) : void
2023-08-22 15:44:49 +00:00
{
2024-12-09 14:38:21 +00:00
if ( ! $team ) {
2024-11-04 13:18:16 +00:00
if ( Auth :: user () -> currentTeam ()) {
$team = Team :: find ( Auth :: user () -> currentTeam () -> id );
2023-09-15 09:28:44 +00:00
} else {
2024-11-04 13:18:16 +00:00
$team = User :: find ( Auth :: id ()) -> teams -> first ();
2023-09-15 09:28:44 +00:00
}
2023-09-08 16:33:26 +00:00
}
2024-12-09 14:38:21 +00:00
Cache :: forget ( 'team:' . Auth :: id ());
Cache :: remember ( 'team:' . Auth :: id (), 3600 , function () use ( $team ) {
2023-09-08 16:33:26 +00:00
return $team ;
});
2023-08-30 14:01:38 +00:00
session ([ 'currentTeam' => $team ]);
2023-08-22 15:44:49 +00:00
}
2023-09-15 13:34:25 +00:00
function handleError ( ? Throwable $error = null , ? Livewire\Component $livewire = null , ? string $customErrorMessage = null )
{
2023-11-20 09:32:06 +00:00
if ( $error instanceof TooManyRequestsException ) {
if ( isset ( $livewire )) {
2024-03-27 10:35:57 +00:00
return $livewire -> dispatch ( 'error' , " Too many requests. Please try again in { $error -> secondsUntilAvailable } seconds. " );
2023-11-20 09:32:06 +00:00
}
2024-06-10 20:43:34 +00:00
2023-11-20 09:32:06 +00:00
return " Too many requests. Please try again in { $error -> secondsUntilAvailable } seconds. " ;
}
2024-01-30 08:48:51 +00:00
if ( $error instanceof UniqueConstraintViolationException ) {
if ( isset ( $livewire )) {
2024-02-22 13:56:41 +00:00
return $livewire -> dispatch ( 'error' , 'Duplicate entry found. Please use a different name.' );
2024-01-30 08:48:51 +00:00
}
2024-06-10 20:43:34 +00:00
return 'Duplicate entry found. Please use a different name.' ;
2024-01-30 08:48:51 +00:00
}
2023-11-20 09:32:06 +00:00
2024-10-17 19:48:47 +00:00
if ( $error instanceof \Illuminate\Database\Eloquent\ModelNotFoundException ) {
abort ( 404 );
}
2023-09-15 13:34:25 +00:00
if ( $error instanceof Throwable ) {
$message = $error -> getMessage ();
} else {
$message = null ;
}
if ( $customErrorMessage ) {
2024-12-09 14:38:21 +00:00
$message = $customErrorMessage . ' ' . $message ;
2023-09-15 13:34:25 +00:00
}
2023-11-20 09:32:06 +00:00
2023-09-15 13:34:25 +00:00
if ( isset ( $livewire )) {
2023-12-07 18:06:32 +00:00
return $livewire -> dispatch ( 'error' , $message );
2023-09-15 13:34:25 +00:00
}
2023-11-21 11:07:06 +00:00
throw new Exception ( $message );
2023-05-24 12:26:50 +00:00
}
2023-08-09 13:57:53 +00:00
function get_route_parameters () : array
2023-05-24 12:26:50 +00:00
{
return Route :: current () -> parameters ();
}
2024-05-08 17:19:32 +00:00
function get_latest_sentinel_version () : string
{
try {
2024-10-15 11:39:19 +00:00
$response = Http :: get ( 'https://cdn.coollabs.io/coolify/versions.json' );
2024-05-08 17:19:32 +00:00
$versions = $response -> json ();
2024-06-18 14:43:18 +00:00
2024-10-15 12:03:10 +00:00
return data_get ( $versions , 'coolify.sentinel.version' );
2024-10-31 14:19:37 +00:00
} catch ( \Throwable ) {
2024-05-08 17:19:32 +00:00
return '0.0.0' ;
}
}
2023-08-09 13:57:53 +00:00
function get_latest_version_of_coolify () : string
2023-05-24 12:26:50 +00:00
{
2023-06-19 13:43:53 +00:00
try {
2024-05-22 07:23:17 +00:00
$versions = File :: get ( base_path ( 'versions.json' ));
$versions = json_decode ( $versions , true );
2024-06-10 20:43:34 +00:00
2023-06-19 13:43:53 +00:00
return data_get ( $versions , 'coolify.v4.version' );
2023-09-15 13:34:25 +00:00
} catch ( \Throwable $e ) {
2023-09-11 15:36:30 +00:00
ray ( $e -> getMessage ());
2024-06-10 20:43:34 +00:00
2023-06-19 13:43:53 +00:00
return '0.0.0' ;
}
2023-05-24 12:26:50 +00:00
}
2023-09-19 13:51:13 +00:00
function generate_random_name ( ? string $cuid = null ) : string
2023-05-24 12:26:50 +00:00
{
2023-11-13 10:44:13 +00:00
$generator = new \Nubs\RandomNameGenerator\All (
[
2024-07-24 19:11:12 +00:00
new \Nubs\RandomNameGenerator\Alliteration ,
2023-11-13 10:44:13 +00:00
]
);
2023-09-19 13:51:13 +00:00
if ( is_null ( $cuid )) {
2024-07-25 11:31:59 +00:00
$cuid = new Cuid2 ;
2023-09-19 13:51:13 +00:00
}
2024-06-10 20:43:34 +00:00
2023-08-09 13:57:53 +00:00
return Str :: kebab ( " { $generator -> getName () } - $cuid " );
2023-05-24 12:26:50 +00:00
}
2024-04-03 11:45:49 +00:00
function generateSSHKey ( string $type = 'rsa' )
{
if ( $type === 'rsa' ) {
$key = RSA :: createKey ();
2024-06-10 20:43:34 +00:00
2024-04-03 11:45:49 +00:00
return [
'private' => $key -> toString ( 'PKCS1' ),
2024-06-10 20:43:34 +00:00
'public' => $key -> getPublicKey () -> toString ( 'OpenSSH' , [ 'comment' => 'coolify-generated-ssh-key' ]),
2024-04-03 11:45:49 +00:00
];
2024-06-10 20:43:34 +00:00
} elseif ( $type === 'ed25519' ) {
2024-04-03 11:45:49 +00:00
$key = EC :: createKey ( 'Ed25519' );
2024-06-10 20:43:34 +00:00
2024-04-03 11:45:49 +00:00
return [
'private' => $key -> toString ( 'OpenSSH' ),
2024-06-10 20:43:34 +00:00
'public' => $key -> getPublicKey () -> toString ( 'OpenSSH' , [ 'comment' => 'coolify-generated-ssh-key' ]),
2024-04-03 11:45:49 +00:00
];
}
throw new Exception ( 'Invalid key type' );
2023-08-22 15:44:49 +00:00
}
2023-08-31 13:00:59 +00:00
function formatPrivateKey ( string $privateKey )
{
2023-08-22 15:44:49 +00:00
$privateKey = trim ( $privateKey );
2024-12-09 14:38:21 +00:00
if ( ! str_ends_with ( $privateKey , " \n " )) {
2023-08-22 15:44:49 +00:00
$privateKey .= " \n " ;
}
2024-06-10 20:43:34 +00:00
2023-08-22 15:44:49 +00:00
return $privateKey ;
}
2023-09-19 13:51:13 +00:00
function generate_application_name ( string $git_repository , string $git_branch , ? string $cuid = null ) : string
2023-05-24 13:47:04 +00:00
{
2023-09-19 13:51:13 +00:00
if ( is_null ( $cuid )) {
2024-07-25 11:31:59 +00:00
$cuid = new Cuid2 ;
2023-09-19 13:51:13 +00:00
}
2024-06-10 20:43:34 +00:00
2023-08-09 13:57:53 +00:00
return Str :: kebab ( " $git_repository : $git_branch - $cuid " );
2023-05-24 13:47:04 +00:00
}
2023-06-12 10:00:01 +00:00
2023-08-09 13:57:53 +00:00
function base_ip () : string
2023-06-16 11:37:02 +00:00
{
2023-08-27 13:23:47 +00:00
if ( isDev ()) {
2024-06-10 20:43:34 +00:00
return 'localhost' ;
2023-07-28 11:40:47 +00:00
}
2024-10-01 08:37:40 +00:00
$settings = instanceSettings ();
2023-08-15 13:39:15 +00:00
if ( $settings -> public_ipv4 ) {
return " $settings->public_ipv4 " ;
}
if ( $settings -> public_ipv6 ) {
return " $settings->public_ipv6 " ;
}
2024-06-10 20:43:34 +00:00
return 'localhost' ;
2023-06-16 11:35:35 +00:00
}
2024-06-10 20:43:34 +00:00
function getFqdnWithoutPort ( string $fqdn )
2023-09-24 10:10:36 +00:00
{
2023-12-28 16:53:47 +00:00
try {
$url = Url :: fromString ( $fqdn );
$host = $url -> getHost ();
$scheme = $url -> getScheme ();
$path = $url -> getPath ();
2024-06-10 20:43:34 +00:00
2023-12-28 16:53:47 +00:00
return " $scheme :// $host $path " ;
2024-10-31 14:19:37 +00:00
} catch ( \Throwable ) {
2023-12-28 16:53:47 +00:00
return $fqdn ;
}
2023-09-22 12:47:25 +00:00
}
2023-08-09 13:57:53 +00:00
/**
* If fqdn is set , return it , otherwise return public ip .
*/
function base_url ( bool $withPort = true ) : string
2023-06-13 13:01:11 +00:00
{
2024-10-01 08:37:40 +00:00
$settings = instanceSettings ();
2023-06-13 13:01:11 +00:00
if ( $settings -> fqdn ) {
return $settings -> fqdn ;
}
2023-06-14 07:05:13 +00:00
$port = config ( 'app.port' );
if ( $settings -> public_ipv4 ) {
2023-06-16 09:01:27 +00:00
if ( $withPort ) {
2023-08-27 13:23:47 +00:00
if ( isDev ()) {
2023-08-09 13:57:53 +00:00
return " http://localhost: $port " ;
2023-06-16 09:01:27 +00:00
}
2024-06-10 20:43:34 +00:00
2023-08-09 13:57:53 +00:00
return " http:// $settings->public_ipv4 : $port " ;
2023-06-16 09:01:27 +00:00
}
2023-08-27 13:23:47 +00:00
if ( isDev ()) {
2024-06-10 20:43:34 +00:00
return 'http://localhost' ;
2023-06-16 09:01:27 +00:00
}
2024-06-10 20:43:34 +00:00
2023-08-09 13:57:53 +00:00
return " http:// $settings->public_ipv4 " ;
2023-06-14 07:05:13 +00:00
}
if ( $settings -> public_ipv6 ) {
2023-06-16 09:01:27 +00:00
if ( $withPort ) {
2023-08-09 13:57:53 +00:00
return " http:// $settings->public_ipv6 : $port " ;
2023-06-16 09:01:27 +00:00
}
2024-06-10 20:43:34 +00:00
2023-08-09 13:57:53 +00:00
return " http:// $settings->public_ipv6 " ;
2023-06-14 07:05:13 +00:00
}
2024-06-10 20:43:34 +00:00
2023-06-14 07:05:13 +00:00
return url ( '/' );
2023-06-13 13:01:11 +00:00
}
2023-06-16 09:01:27 +00:00
2024-03-21 13:30:35 +00:00
function isSubscribed ()
{
2024-03-29 23:23:48 +00:00
return isSubscriptionActive () || auth () -> user () -> isInstanceAdmin ();
2024-03-21 13:30:35 +00:00
}
2024-10-01 07:31:01 +00:00
function isProduction () : bool
{
2024-12-09 14:38:21 +00:00
return ! isDev ();
2024-10-01 07:31:01 +00:00
}
2023-08-27 13:23:47 +00:00
function isDev () : bool
2023-06-16 09:01:27 +00:00
{
return config ( 'app.env' ) === 'local' ;
}
2023-08-08 09:51:36 +00:00
2023-08-31 07:56:37 +00:00
function isCloud () : bool
2023-07-13 13:07:42 +00:00
{
2024-11-13 17:41:23 +00:00
return ! config ( 'constants.coolify.self_hosted' );
2023-08-08 09:51:36 +00:00
}
2023-08-09 13:57:53 +00:00
2024-08-26 13:26:08 +00:00
function translate_cron_expression ( $expression_to_validate ) : string
{
if ( isset ( VALID_CRON_STRINGS [ $expression_to_validate ])) {
return VALID_CRON_STRINGS [ $expression_to_validate ];
}
return $expression_to_validate ;
}
2023-08-10 13:52:54 +00:00
function validate_cron_expression ( $expression_to_validate ) : bool
{
2024-10-30 13:54:27 +00:00
if ( empty ( $expression_to_validate )) {
return false ;
}
2023-08-10 13:52:54 +00:00
$isValid = false ;
$expression = new CronExpression ( $expression_to_validate );
$isValid = $expression -> isValid ();
if ( isset ( VALID_CRON_STRINGS [ $expression_to_validate ])) {
$isValid = true ;
}
2024-06-10 20:43:34 +00:00
2023-08-10 13:52:54 +00:00
return $isValid ;
}
2024-11-14 09:02:37 +00:00
function validate_timezone ( string $timezone ) : bool
{
return in_array ( $timezone , timezone_identifiers_list ());
}
2024-06-10 20:43:34 +00:00
2023-09-15 13:34:25 +00:00
function parseEnvFormatToArray ( $env_file_contents )
{
2024-06-10 20:43:34 +00:00
$env_array = [];
2023-09-08 14:16:59 +00:00
$lines = explode ( " \n " , $env_file_contents );
foreach ( $lines as $line ) {
if ( $line === '' || substr ( $line , 0 , 1 ) === '#' ) {
continue ;
}
$equals_pos = strpos ( $line , '=' );
if ( $equals_pos !== false ) {
$key = substr ( $line , 0 , $equals_pos );
$value = substr ( $line , $equals_pos + 1 );
if ( substr ( $value , 0 , 1 ) === '"' && substr ( $value , - 1 ) === '"' ) {
$value = substr ( $value , 1 , - 1 );
2023-09-15 13:34:25 +00:00
} elseif ( substr ( $value , 0 , 1 ) === " ' " && substr ( $value , - 1 ) === " ' " ) {
2023-09-08 14:16:59 +00:00
$value = substr ( $value , 1 , - 1 );
}
$env_array [ $key ] = $value ;
}
}
2024-06-10 20:43:34 +00:00
2023-09-08 14:16:59 +00:00
return $env_array ;
}
2023-09-27 10:45:53 +00:00
function data_get_str ( $data , $key , $default = null ) : Stringable
{
$str = data_get ( $data , $key , $default ) ? ? $default ;
2024-06-10 20:43:34 +00:00
2024-06-25 08:34:56 +00:00
return str ( $str );
2023-09-27 10:45:53 +00:00
}
2023-09-28 08:53:00 +00:00
2024-09-16 14:35:47 +00:00
function generateFqdn ( Server $server , string $random , bool $forceHttps = false ) : string
2023-09-30 13:39:40 +00:00
{
$wildcard = data_get ( $server , 'settings.wildcard_domain' );
if ( is_null ( $wildcard ) || $wildcard === '' ) {
$wildcard = sslip ( $server );
}
$url = Url :: fromString ( $wildcard );
$host = $url -> getHost ();
$path = $url -> getPath () === '/' ? '' : $url -> getPath ();
$scheme = $url -> getScheme ();
2024-09-16 14:35:47 +00:00
if ( $forceHttps ) {
$scheme = 'https' ;
}
2024-06-10 20:43:34 +00:00
2024-10-31 17:20:11 +00:00
return " $scheme :// { $random } . $host $path " ;
2023-09-30 13:39:40 +00:00
}
2023-09-28 08:53:00 +00:00
function sslip ( Server $server )
{
2024-01-09 11:48:46 +00:00
if ( isDev () && $server -> id === 0 ) {
2024-06-10 20:43:34 +00:00
return 'http://127.0.0.1.sslip.io' ;
2023-09-28 08:53:00 +00:00
}
if ( $server -> ip === 'host.docker.internal' ) {
$baseIp = base_ip ();
2024-06-10 20:43:34 +00:00
2023-09-30 13:39:40 +00:00
return " http:// $baseIp .sslip.io " ;
2023-09-28 08:53:00 +00:00
}
2024-09-26 11:47:13 +00:00
// ipv6
if ( str ( $server -> ip ) -> contains ( ':' )) {
$ipv6 = str ( $server -> ip ) -> replace ( ':' , '-' );
return " http:// { $ipv6 } .sslip.io " ;
}
2024-06-10 20:43:34 +00:00
2023-09-30 13:39:40 +00:00
return " http:// { $server -> ip } .sslip.io " ;
2023-09-28 08:53:00 +00:00
}
2023-09-28 20:20:49 +00:00
2024-05-27 08:27:18 +00:00
function get_service_templates ( bool $force = false ) : Collection
{
2024-10-07 09:02:01 +00:00
2024-05-27 08:27:18 +00:00
if ( $force ) {
try {
2024-08-07 07:50:29 +00:00
$response = Http :: retry ( 3 , 1000 ) -> get ( config ( 'constants.services.official' ));
2024-05-27 08:27:18 +00:00
if ( $response -> failed ()) {
return collect ([]);
}
$services = $response -> json ();
2024-06-10 20:43:34 +00:00
2024-05-27 08:27:18 +00:00
return collect ( $services );
2024-10-31 14:19:37 +00:00
} catch ( \Throwable ) {
2024-05-27 08:27:18 +00:00
$services = File :: get ( base_path ( 'templates/service-templates.json' ));
2024-06-10 20:43:34 +00:00
2024-05-27 08:27:18 +00:00
return collect ( json_decode ( $services )) -> sortKeys ();
}
} else {
$services = File :: get ( base_path ( 'templates/service-templates.json' ));
2024-06-10 20:43:34 +00:00
2024-05-27 08:27:18 +00:00
return collect ( json_decode ( $services )) -> sortKeys ();
}
2023-09-28 20:20:49 +00:00
}
2023-10-20 12:51:01 +00:00
function getResourceByUuid ( string $uuid , ? int $teamId = null )
{
2024-04-10 13:00:46 +00:00
if ( is_null ( $teamId )) {
2023-10-20 12:51:01 +00:00
return null ;
2024-04-10 13:00:46 +00:00
}
$resource = queryResourcesByUuid ( $uuid );
2024-12-09 14:38:21 +00:00
if ( ! is_null ( $resource ) && $resource -> environment -> project -> team_id === $teamId ) {
2023-10-20 12:51:01 +00:00
return $resource ;
}
2024-06-10 20:43:34 +00:00
2024-04-10 13:00:46 +00:00
return null ;
2023-10-20 12:51:01 +00:00
}
2024-07-01 14:26:50 +00:00
function queryDatabaseByUuidWithinTeam ( string $uuid , string $teamId )
{
$postgresql = StandalonePostgresql :: whereUuid ( $uuid ) -> first ();
if ( $postgresql && $postgresql -> team () -> id == $teamId ) {
return $postgresql -> unsetRelation ( 'environment' ) -> unsetRelation ( 'destination' );
}
$redis = StandaloneRedis :: whereUuid ( $uuid ) -> first ();
if ( $redis && $redis -> team () -> id == $teamId ) {
return $redis -> unsetRelation ( 'environment' );
}
$mongodb = StandaloneMongodb :: whereUuid ( $uuid ) -> first ();
if ( $mongodb && $mongodb -> team () -> id == $teamId ) {
return $mongodb -> unsetRelation ( 'environment' );
}
$mysql = StandaloneMysql :: whereUuid ( $uuid ) -> first ();
if ( $mysql && $mysql -> team () -> id == $teamId ) {
return $mysql -> unsetRelation ( 'environment' );
}
$mariadb = StandaloneMariadb :: whereUuid ( $uuid ) -> first ();
if ( $mariadb && $mariadb -> team () -> id == $teamId ) {
return $mariadb -> unsetRelation ( 'environment' );
}
$keydb = StandaloneKeydb :: whereUuid ( $uuid ) -> first ();
if ( $keydb && $keydb -> team () -> id == $teamId ) {
return $keydb -> unsetRelation ( 'environment' );
}
$dragonfly = StandaloneDragonfly :: whereUuid ( $uuid ) -> first ();
if ( $dragonfly && $dragonfly -> team () -> id == $teamId ) {
return $dragonfly -> unsetRelation ( 'environment' );
}
$clickhouse = StandaloneClickhouse :: whereUuid ( $uuid ) -> first ();
if ( $clickhouse && $clickhouse -> team () -> id == $teamId ) {
return $clickhouse -> unsetRelation ( 'environment' );
}
return null ;
}
2023-10-20 12:51:01 +00:00
function queryResourcesByUuid ( string $uuid )
{
$resource = null ;
$application = Application :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $application ) {
return $application ;
}
2023-10-20 12:51:01 +00:00
$service = Service :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $service ) {
return $service ;
}
2023-10-20 12:51:01 +00:00
$postgresql = StandalonePostgresql :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $postgresql ) {
return $postgresql ;
}
2023-10-20 12:51:01 +00:00
$redis = StandaloneRedis :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $redis ) {
return $redis ;
}
2023-10-20 12:51:01 +00:00
$mongodb = StandaloneMongodb :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $mongodb ) {
return $mongodb ;
}
2023-10-25 08:43:07 +00:00
$mysql = StandaloneMysql :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $mysql ) {
return $mysql ;
}
2023-10-25 08:43:07 +00:00
$mariadb = StandaloneMariadb :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $mariadb ) {
return $mariadb ;
}
2024-04-10 13:00:46 +00:00
$keydb = StandaloneKeydb :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $keydb ) {
return $keydb ;
}
2024-04-10 13:00:46 +00:00
$dragonfly = StandaloneDragonfly :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $dragonfly ) {
return $dragonfly ;
}
2024-04-10 13:00:46 +00:00
$clickhouse = StandaloneClickhouse :: whereUuid ( $uuid ) -> first ();
2024-06-10 20:43:34 +00:00
if ( $clickhouse ) {
return $clickhouse ;
}
2023-10-20 12:51:01 +00:00
return $resource ;
}
2024-10-25 08:59:12 +00:00
function generateTagDeployWebhook ( $tag_name )
2024-02-01 14:38:12 +00:00
{
$baseUrl = base_url ();
2024-12-09 14:38:21 +00:00
$api = Url :: fromString ( $baseUrl ) . '/api/v1' ;
2024-02-02 10:50:28 +00:00
$endpoint = " /deploy?tag= $tag_name " ;
2024-06-10 20:43:34 +00:00
2024-12-09 14:38:21 +00:00
return $api . $endpoint ;
2024-02-01 14:38:12 +00:00
}
2023-11-13 10:44:13 +00:00
function generateDeployWebhook ( $resource )
{
2023-10-25 08:43:07 +00:00
$baseUrl = base_url ();
2024-12-09 14:38:21 +00:00
$api = Url :: fromString ( $baseUrl ) . '/api/v1' ;
2023-10-25 08:43:07 +00:00
$endpoint = '/deploy' ;
$uuid = data_get ( $resource , 'uuid' );
2024-06-10 20:43:34 +00:00
2024-12-09 14:38:21 +00:00
return $api . $endpoint . " ?uuid= $uuid &force=false " ;
2023-10-25 08:43:07 +00:00
}
2023-11-24 14:48:23 +00:00
function generateGitManualWebhook ( $resource , $type )
{
2024-12-09 14:38:21 +00:00
if ( $resource -> source_id !== 0 && ! is_null ( $resource -> source_id )) {
2023-11-14 13:14:21 +00:00
return null ;
}
2024-10-28 13:56:13 +00:00
if ( $resource -> getMorphClass () === \App\Models\Application :: class ) {
2023-11-14 12:26:14 +00:00
$baseUrl = base_url ();
2024-06-10 20:43:34 +00:00
2024-12-09 14:38:21 +00:00
return Url :: fromString ( $baseUrl ) . " /webhooks/source/ $type /events/manual " ;
2023-11-14 12:26:14 +00:00
}
2024-06-10 20:43:34 +00:00
2023-11-14 12:26:14 +00:00
return null ;
}
2023-11-13 10:44:13 +00:00
function removeAnsiColors ( $text )
{
2023-11-07 13:40:58 +00:00
return preg_replace ( '/\e[[][A-Za-z0-9];?[0-9]*m?/' , '' , $text );
}
2023-11-24 14:48:23 +00:00
2023-11-27 08:58:31 +00:00
function getTopLevelNetworks ( Service | Application $resource )
{
2024-10-28 13:56:13 +00:00
if ( $resource -> getMorphClass () === \App\Models\Service :: class ) {
2023-11-27 08:58:31 +00:00
if ( $resource -> docker_compose_raw ) {
try {
$yaml = Yaml :: parse ( $resource -> docker_compose_raw );
} catch ( \Exception $e ) {
throw new \Exception ( $e -> getMessage ());
}
$services = data_get ( $yaml , 'services' );
$topLevelNetworks = collect ( data_get ( $yaml , 'networks' , []));
$definedNetwork = collect ([ $resource -> uuid ]);
$services = collect ( $services ) -> map ( function ( $service , $_ ) use ( $topLevelNetworks , $definedNetwork ) {
$serviceNetworks = collect ( data_get ( $service , 'networks' , []));
2024-02-14 14:00:24 +00:00
$hasHostNetworkMode = data_get ( $service , 'network_mode' ) === 'host' ? true : false ;
2023-11-27 08:58:31 +00:00
2024-02-14 14:00:24 +00:00
// Only add 'networks' key if 'network_mode' is not 'host'
2024-12-09 14:38:21 +00:00
if ( ! $hasHostNetworkMode ) {
2024-02-11 15:22:09 +00:00
// Collect/create/update networks
if ( $serviceNetworks -> count () > 0 ) {
foreach ( $serviceNetworks as $networkName => $networkDetails ) {
2024-05-31 08:21:38 +00:00
if ( $networkName === 'default' ) {
continue ;
}
// ignore alias
if ( $networkDetails [ 'aliases' ] ? ? false ) {
continue ;
}
2024-02-11 15:22:09 +00:00
$networkExists = $topLevelNetworks -> contains ( function ( $value , $key ) use ( $networkName ) {
return $value == $networkName || $key == $networkName ;
});
2024-12-09 14:38:21 +00:00
if ( ! $networkExists ) {
2024-10-03 13:04:40 +00:00
if ( is_string ( $networkDetails ) || is_int ( $networkDetails )) {
$topLevelNetworks -> put ( $networkDetails , null );
}
2024-02-11 15:22:09 +00:00
}
2023-11-27 08:58:31 +00:00
}
}
2024-02-11 15:22:09 +00:00
$definedNetworkExists = $topLevelNetworks -> contains ( function ( $value , $_ ) use ( $definedNetwork ) {
return $value == $definedNetwork ;
});
2024-12-09 14:38:21 +00:00
if ( ! $definedNetworkExists ) {
2024-02-11 15:22:09 +00:00
foreach ( $definedNetwork as $network ) {
2024-06-10 20:43:34 +00:00
$topLevelNetworks -> put ( $network , [
2024-02-11 15:22:09 +00:00
'name' => $network ,
2024-06-10 20:43:34 +00:00
'external' => true ,
2024-02-11 15:22:09 +00:00
]);
}
2023-11-27 08:58:31 +00:00
}
}
return $service ;
});
2024-06-10 20:43:34 +00:00
2023-11-27 08:58:31 +00:00
return $topLevelNetworks -> keys ();
}
2024-10-28 13:56:13 +00:00
} elseif ( $resource -> getMorphClass () === \App\Models\Application :: class ) {
2023-11-27 08:58:31 +00:00
try {
$yaml = Yaml :: parse ( $resource -> docker_compose_raw );
} catch ( \Exception $e ) {
throw new \Exception ( $e -> getMessage ());
}
$server = $resource -> destination -> server ;
$topLevelNetworks = collect ( data_get ( $yaml , 'networks' , []));
$services = data_get ( $yaml , 'services' );
$definedNetwork = collect ([ $resource -> uuid ]);
$services = collect ( $services ) -> map ( function ( $service , $_ ) use ( $topLevelNetworks , $definedNetwork ) {
$serviceNetworks = collect ( data_get ( $service , 'networks' , []));
// Collect/create/update networks
if ( $serviceNetworks -> count () > 0 ) {
foreach ( $serviceNetworks as $networkName => $networkDetails ) {
2024-05-31 08:21:38 +00:00
if ( $networkName === 'default' ) {
continue ;
}
// ignore alias
if ( $networkDetails [ 'aliases' ] ? ? false ) {
continue ;
}
2023-11-27 08:58:31 +00:00
$networkExists = $topLevelNetworks -> contains ( function ( $value , $key ) use ( $networkName ) {
return $value == $networkName || $key == $networkName ;
});
2024-12-09 14:38:21 +00:00
if ( ! $networkExists ) {
2024-10-03 13:04:40 +00:00
if ( is_string ( $networkDetails ) || is_int ( $networkDetails )) {
$topLevelNetworks -> put ( $networkDetails , null );
}
2023-11-27 08:58:31 +00:00
}
}
}
$definedNetworkExists = $topLevelNetworks -> contains ( function ( $value , $_ ) use ( $definedNetwork ) {
return $value == $definedNetwork ;
});
2024-12-09 14:38:21 +00:00
if ( ! $definedNetworkExists ) {
2023-11-27 08:58:31 +00:00
foreach ( $definedNetwork as $network ) {
2024-06-10 20:43:34 +00:00
$topLevelNetworks -> put ( $network , [
2023-11-27 08:58:31 +00:00
'name' => $network ,
2024-06-10 20:43:34 +00:00
'external' => true ,
2023-11-27 08:58:31 +00:00
]);
}
}
2024-06-10 20:43:34 +00:00
2023-11-27 08:58:31 +00:00
return $service ;
});
2024-06-10 20:43:34 +00:00
2023-11-27 08:58:31 +00:00
return $topLevelNetworks -> keys ();
}
}
2024-08-21 18:32:02 +00:00
function sourceIsLocal ( Stringable $source )
{
if ( $source -> startsWith ( './' ) || $source -> startsWith ( '/' ) || $source -> startsWith ( '~' ) || $source -> startsWith ( '..' ) || $source -> startsWith ( '~/' ) || $source -> startsWith ( '../' )) {
return true ;
}
return false ;
}
function replaceLocalSource ( Stringable $source , Stringable $replacedWith )
{
if ( $source -> startsWith ( '.' )) {
$source = $source -> replaceFirst ( '.' , $replacedWith -> value ());
}
if ( $source -> startsWith ( '~' )) {
$source = $source -> replaceFirst ( '~' , $replacedWith -> value ());
}
if ( $source -> startsWith ( '..' )) {
$source = $source -> replaceFirst ( '..' , $replacedWith -> value ());
}
2024-09-13 09:12:28 +00:00
if ( $source -> endsWith ( '/' ) && $source -> value () !== '/' ) {
2024-08-23 12:21:12 +00:00
$source = $source -> replaceLast ( '/' , '' );
2024-08-21 18:32:02 +00:00
}
2024-08-22 13:05:04 +00:00
2024-08-23 12:21:12 +00:00
return $source ;
2024-08-21 18:32:02 +00:00
}
2024-08-22 13:05:04 +00:00
function convertToArray ( $collection )
{
if ( $collection instanceof Collection ) {
return $collection -> map ( function ( $item ) {
return convertToArray ( $item );
}) -> toArray ();
} elseif ( $collection instanceof Stringable ) {
return ( string ) $collection ;
} elseif ( is_array ( $collection )) {
return array_map ( function ( $item ) {
return convertToArray ( $item );
}, $collection );
}
return $collection ;
}
2023-11-28 11:05:04 +00:00
2024-10-03 20:02:18 +00:00
function parseCommandFromMagicEnvVariable ( Str | string $key ) : Stringable
{
$value = str ( $key );
$count = substr_count ( $value -> value (), '_' );
2025-02-28 19:28:35 +00:00
$command = null ;
2024-10-03 20:02:18 +00:00
if ( $count === 2 ) {
if ( $value -> startsWith ( 'SERVICE_FQDN' ) || $value -> startsWith ( 'SERVICE_URL' )) {
// SERVICE_FQDN_UMAMI
$command = $value -> after ( 'SERVICE_' ) -> beforeLast ( '_' );
} else {
// SERVICE_BASE64_UMAMI
$command = $value -> after ( 'SERVICE_' ) -> beforeLast ( '_' );
}
}
if ( $count === 3 ) {
if ( $value -> startsWith ( 'SERVICE_FQDN' ) || $value -> startsWith ( 'SERVICE_URL' )) {
// SERVICE_FQDN_UMAMI_1000
$command = $value -> after ( 'SERVICE_' ) -> before ( '_' );
} else {
// SERVICE_BASE64_64_UMAMI
$command = $value -> after ( 'SERVICE_' ) -> beforeLast ( '_' );
}
}
return str ( $command );
}
2023-11-28 11:05:04 +00:00
function parseEnvVariable ( Str | string $value )
{
$value = str ( $value );
$count = substr_count ( $value -> value (), '_' );
$command = null ;
$forService = null ;
$generatedValue = null ;
$port = null ;
2024-03-21 14:36:37 +00:00
if ( $value -> startsWith ( 'SERVICE' )) {
if ( $count === 2 ) {
if ( $value -> startsWith ( 'SERVICE_FQDN' ) || $value -> startsWith ( 'SERVICE_URL' )) {
// SERVICE_FQDN_UMAMI
$command = $value -> after ( 'SERVICE_' ) -> beforeLast ( '_' );
$forService = $value -> afterLast ( '_' );
} else {
// SERVICE_BASE64_UMAMI
$command = $value -> after ( 'SERVICE_' ) -> beforeLast ( '_' );
}
2023-11-28 11:05:04 +00:00
}
2024-03-21 14:36:37 +00:00
if ( $count === 3 ) {
if ( $value -> startsWith ( 'SERVICE_FQDN' ) || $value -> startsWith ( 'SERVICE_URL' )) {
// SERVICE_FQDN_UMAMI_1000
$command = $value -> after ( 'SERVICE_' ) -> before ( '_' );
$forService = $value -> after ( 'SERVICE_' ) -> after ( '_' ) -> before ( '_' );
$port = $value -> afterLast ( '_' );
if ( filter_var ( $port , FILTER_VALIDATE_INT ) === false ) {
$port = null ;
}
} else {
// SERVICE_BASE64_64_UMAMI
$command = $value -> after ( 'SERVICE_' ) -> beforeLast ( '_' );
2023-12-28 16:53:47 +00:00
}
2023-11-28 11:05:04 +00:00
}
}
2024-06-10 20:43:34 +00:00
2023-11-28 11:05:04 +00:00
return [
'command' => $command ,
'forService' => $forService ,
'generatedValue' => $generatedValue ,
'port' => $port ,
];
}
2024-08-27 19:48:25 +00:00
function generateEnvValue ( string $command , Service | Application | null $service = null )
2023-11-28 11:05:04 +00:00
{
switch ( $command ) {
case 'PASSWORD' :
$generatedValue = Str :: password ( symbols : false );
break ;
case 'PASSWORD_64' :
$generatedValue = Str :: password ( length : 64 , symbols : false );
break ;
2024-12-12 10:06:00 +00:00
case 'PASSWORDWITHSYMBOLS' :
$generatedValue = Str :: password ( symbols : true );
break ;
case 'PASSWORDWITHSYMBOLS_64' :
$generatedValue = Str :: password ( length : 64 , symbols : true );
break ;
2024-12-09 14:38:21 +00:00
// This is not base64, it's just a random string
2023-11-28 11:05:04 +00:00
case 'BASE64_64' :
2024-03-04 11:50:56 +00:00
$generatedValue = Str :: random ( 64 );
2023-11-28 11:05:04 +00:00
break ;
case 'BASE64_128' :
2024-03-04 11:50:56 +00:00
$generatedValue = Str :: random ( 128 );
2023-11-28 11:05:04 +00:00
break ;
case 'BASE64' :
2024-03-04 11:46:37 +00:00
case 'BASE64_32' :
2024-03-04 11:50:56 +00:00
$generatedValue = Str :: random ( 32 );
break ;
2024-12-09 14:38:21 +00:00
// This is base64,
2024-03-04 11:50:56 +00:00
case 'REALBASE64_64' :
$generatedValue = base64_encode ( Str :: random ( 64 ));
break ;
case 'REALBASE64_128' :
$generatedValue = base64_encode ( Str :: random ( 128 ));
break ;
case 'REALBASE64' :
case 'REALBASE64_32' :
2024-03-04 11:46:37 +00:00
$generatedValue = base64_encode ( Str :: random ( 32 ));
2023-11-28 11:05:04 +00:00
break ;
2024-11-26 12:01:42 +00:00
case 'HEX_32' :
$generatedValue = bin2hex ( Str :: random ( 32 ));
break ;
case 'HEX_64' :
$generatedValue = bin2hex ( Str :: random ( 64 ));
break ;
case 'HEX_128' :
$generatedValue = bin2hex ( Str :: random ( 128 ));
break ;
2023-11-28 11:05:04 +00:00
case 'USER' :
$generatedValue = Str :: random ( 16 );
break ;
2024-02-28 12:48:39 +00:00
case 'SUPABASEANON' :
$signingKey = $service -> environment_variables () -> where ( 'key' , 'SERVICE_PASSWORD_JWT' ) -> first ();
if ( is_null ( $signingKey )) {
return ;
} else {
$signingKey = $signingKey -> value ;
}
$key = InMemory :: plainText ( $signingKey );
2024-07-24 19:11:12 +00:00
$algorithm = new Sha256 ;
$tokenBuilder = ( new Builder ( new JoseEncoder , ChainedFormatter :: default ()));
2024-10-31 15:47:08 +00:00
$now = CarbonImmutable :: now ();
2024-02-28 12:48:39 +00:00
$now = $now -> setTime ( $now -> format ( 'H' ), $now -> format ( 'i' ));
$token = $tokenBuilder
-> issuedBy ( 'supabase' )
-> issuedAt ( $now )
-> expiresAt ( $now -> modify ( '+100 year' ))
-> withClaim ( 'role' , 'anon' )
-> getToken ( $algorithm , $key );
$generatedValue = $token -> toString ();
break ;
case 'SUPABASESERVICE' :
$signingKey = $service -> environment_variables () -> where ( 'key' , 'SERVICE_PASSWORD_JWT' ) -> first ();
if ( is_null ( $signingKey )) {
return ;
} else {
$signingKey = $signingKey -> value ;
}
$key = InMemory :: plainText ( $signingKey );
2024-07-24 19:11:12 +00:00
$algorithm = new Sha256 ;
$tokenBuilder = ( new Builder ( new JoseEncoder , ChainedFormatter :: default ()));
2024-10-31 15:47:08 +00:00
$now = CarbonImmutable :: now ();
2024-02-28 12:48:39 +00:00
$now = $now -> setTime ( $now -> format ( 'H' ), $now -> format ( 'i' ));
$token = $tokenBuilder
-> issuedBy ( 'supabase' )
-> issuedAt ( $now )
-> expiresAt ( $now -> modify ( '+100 year' ))
-> withClaim ( 'role' , 'service_role' )
-> getToken ( $algorithm , $key );
$generatedValue = $token -> toString ();
break ;
2023-12-14 14:34:05 +00:00
default :
2024-08-27 19:48:25 +00:00
// $generatedValue = Str::random(16);
$generatedValue = null ;
2023-12-14 14:34:05 +00:00
break ;
2023-11-28 11:05:04 +00:00
}
2024-06-10 20:43:34 +00:00
2023-11-28 11:05:04 +00:00
return $generatedValue ;
}
2023-12-11 19:01:54 +00:00
2023-12-11 19:13:41 +00:00
function getRealtime ()
{
2024-11-12 14:53:05 +00:00
$envDefined = config ( 'constants.pusher.port' );
2023-12-11 19:22:31 +00:00
if ( empty ( $envDefined )) {
2023-12-11 19:13:41 +00:00
$url = Url :: fromString ( Request :: getSchemeAndHttpHost ());
$port = $url -> getPort ();
if ( $port ) {
return '6001' ;
} else {
return null ;
}
2023-12-11 19:01:54 +00:00
} else {
2023-12-11 19:13:41 +00:00
return $envDefined ;
2023-12-11 19:01:54 +00:00
}
}
2024-01-15 09:03:15 +00:00
function validate_dns_entry ( string $fqdn , Server $server )
{
2024-06-10 20:43:34 +00:00
// https://www.cloudflare.com/ips-v4/#
2024-01-15 10:37:26 +00:00
$cloudflare_ips = collect ([ '173.245.48.0/20' , '103.21.244.0/22' , '103.22.200.0/22' , '103.31.4.0/22' , '141.101.64.0/18' , '108.162.192.0/18' , '190.93.240.0/20' , '188.114.96.0/20' , '197.234.240.0/22' , '198.41.128.0/17' , '162.158.0.0/15' , '104.16.0.0/13' , '172.64.0.0/13' , '131.0.72.0/22' ]);
2024-01-15 09:03:15 +00:00
$url = Url :: fromString ( $fqdn );
$host = $url -> getHost ();
if ( str ( $host ) -> contains ( 'sslip.io' )) {
return true ;
}
2024-10-01 08:37:40 +00:00
$settings = instanceSettings ();
2024-01-15 09:03:15 +00:00
$is_dns_validation_enabled = data_get ( $settings , 'is_dns_validation_enabled' );
2024-12-09 14:38:21 +00:00
if ( ! $is_dns_validation_enabled ) {
2024-01-15 09:03:15 +00:00
return true ;
}
2024-01-15 10:37:26 +00:00
$dns_servers = data_get ( $settings , 'custom_dns_servers' );
$dns_servers = str ( $dns_servers ) -> explode ( ',' );
2024-01-15 09:03:15 +00:00
if ( $server -> id === 0 ) {
2024-05-06 10:33:22 +00:00
$ip = data_get ( $settings , 'public_ipv4' , data_get ( $settings , 'public_ipv6' , $server -> ip ));
2024-01-15 09:03:15 +00:00
} else {
$ip = $server -> ip ;
}
2024-01-15 10:37:26 +00:00
$found_matching_ip = false ;
2024-01-15 09:03:15 +00:00
$type = \PurplePixie\PhpDns\DNSTypes :: NAME_A ;
2024-01-15 10:37:26 +00:00
foreach ( $dns_servers as $dns_server ) {
2024-01-15 09:03:15 +00:00
try {
2024-01-15 10:37:26 +00:00
$query = new DNSQuery ( $dns_server );
2024-01-15 09:03:15 +00:00
$results = $query -> query ( $host , $type );
if ( $results === false || $query -> hasError ()) {
2024-12-09 14:38:21 +00:00
ray ( 'Error: ' . $query -> getLasterror ());
2024-01-15 09:03:15 +00:00
} else {
foreach ( $results as $result ) {
if ( $result -> getType () == $type ) {
2024-01-15 10:37:26 +00:00
if ( ip_match ( $result -> getData (), $cloudflare_ips -> toArray (), $match )) {
$found_matching_ip = true ;
break ;
}
2024-01-15 09:03:15 +00:00
if ( $result -> getData () === $ip ) {
2024-01-15 10:37:26 +00:00
$found_matching_ip = true ;
2024-01-15 09:03:15 +00:00
break ;
}
}
}
}
2024-10-31 14:19:37 +00:00
} catch ( \Exception ) {
2024-01-15 09:03:15 +00:00
}
}
2024-06-10 20:43:34 +00:00
2024-01-15 10:37:26 +00:00
return $found_matching_ip ;
}
function ip_match ( $ip , $cidrs , & $match = null )
{
foreach (( array ) $cidrs as $cidr ) {
2024-06-10 20:43:34 +00:00
[ $subnet , $mask ] = explode ( '/' , $cidr );
2024-01-15 10:37:26 +00:00
if ((( ip2long ( $ip ) & ( $mask = ~ (( 1 << ( 32 - $mask )) - 1 ))) == ( ip2long ( $subnet ) & $mask ))) {
$match = $cidr ;
2024-06-10 20:43:34 +00:00
2024-01-15 10:37:26 +00:00
return true ;
}
}
2024-06-10 20:43:34 +00:00
2024-01-15 10:37:26 +00:00
return false ;
2024-01-15 09:03:15 +00:00
}
2024-07-11 08:02:35 +00:00
function checkIfDomainIsAlreadyUsed ( Collection | array $domains , ? string $teamId = null , ? string $uuid = null )
2024-07-01 09:39:10 +00:00
{
if ( is_null ( $teamId )) {
return response () -> json ([ 'error' => 'Team ID is required.' ], 400 );
}
if ( is_array ( $domains )) {
$domains = collect ( $domains );
}
$domains = $domains -> map ( function ( $domain ) {
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
return str ( $domain );
});
2024-07-11 08:02:35 +00:00
$applications = Application :: ownedByCurrentTeamAPI ( $teamId ) -> get ([ 'fqdn' , 'uuid' ]);
$serviceApplications = ServiceApplication :: ownedByCurrentTeamAPI ( $teamId ) -> get ([ 'fqdn' , 'uuid' ]);
if ( $uuid ) {
2024-12-09 14:38:21 +00:00
$applications = $applications -> filter ( fn ( $app ) => $app -> uuid !== $uuid );
$serviceApplications = $serviceApplications -> filter ( fn ( $app ) => $app -> uuid !== $uuid );
2024-07-11 08:02:35 +00:00
}
2024-07-01 09:39:10 +00:00
$domainFound = false ;
foreach ( $applications as $app ) {
if ( is_null ( $app -> fqdn )) {
continue ;
}
2024-12-09 14:38:21 +00:00
$list_of_domains = collect ( explode ( ',' , $app -> fqdn )) -> filter ( fn ( $fqdn ) => $fqdn !== '' );
2024-07-01 09:39:10 +00:00
foreach ( $list_of_domains as $domain ) {
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
$naked_domain = str ( $domain ) -> value ();
if ( $domains -> contains ( $naked_domain )) {
$domainFound = true ;
break ;
}
}
}
if ( $domainFound ) {
return true ;
}
foreach ( $serviceApplications as $app ) {
2024-07-10 09:09:29 +00:00
if ( str ( $app -> fqdn ) -> isEmpty ()) {
2024-07-01 09:39:10 +00:00
continue ;
}
2024-12-09 14:38:21 +00:00
$list_of_domains = collect ( explode ( ',' , $app -> fqdn )) -> filter ( fn ( $fqdn ) => $fqdn !== '' );
2024-07-01 09:39:10 +00:00
foreach ( $list_of_domains as $domain ) {
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
$naked_domain = str ( $domain ) -> value ();
if ( $domains -> contains ( $naked_domain )) {
$domainFound = true ;
break ;
}
}
}
if ( $domainFound ) {
return true ;
}
2024-10-01 08:37:40 +00:00
$settings = instanceSettings ();
2024-07-01 09:39:10 +00:00
if ( data_get ( $settings , 'fqdn' )) {
$domain = data_get ( $settings , 'fqdn' );
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
$naked_domain = str ( $domain ) -> value ();
if ( $domains -> contains ( $naked_domain )) {
return true ;
}
}
}
2024-04-08 10:15:44 +00:00
function check_domain_usage ( ServiceApplication | Application | null $resource = null , ? string $domain = null )
2024-01-30 08:22:34 +00:00
{
2024-04-08 10:15:44 +00:00
if ( $resource ) {
2024-10-28 13:56:13 +00:00
if ( $resource -> getMorphClass () === \App\Models\Application :: class && $resource -> build_pack === 'dockercompose' ) {
2024-06-10 20:43:34 +00:00
$domains = data_get ( json_decode ( $resource -> docker_compose_domains , true ), '*.domain' );
2024-04-08 10:15:44 +00:00
$domains = collect ( $domains );
} else {
$domains = collect ( $resource -> fqdns );
}
2024-06-10 20:43:34 +00:00
} elseif ( $domain ) {
2024-04-08 10:15:44 +00:00
$domains = collect ( $domain );
} else {
2024-06-10 20:43:34 +00:00
throw new \RuntimeException ( 'No resource or FQDN provided.' );
2024-04-08 10:15:44 +00:00
}
$domains = $domains -> map ( function ( $domain ) {
2024-02-01 09:53:05 +00:00
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
2024-06-10 20:43:34 +00:00
2024-04-08 10:15:44 +00:00
return str ( $domain );
2024-01-30 08:22:34 +00:00
});
$apps = Application :: all ();
foreach ( $apps as $app ) {
2024-12-09 14:38:21 +00:00
$list_of_domains = collect ( explode ( ',' , $app -> fqdn )) -> filter ( fn ( $fqdn ) => $fqdn !== '' );
2024-01-30 08:22:34 +00:00
foreach ( $list_of_domains as $domain ) {
2024-02-01 09:53:05 +00:00
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
2024-04-08 10:15:44 +00:00
$naked_domain = str ( $domain ) -> value ();
2024-01-30 08:22:34 +00:00
if ( $domains -> contains ( $naked_domain )) {
2024-04-08 10:15:44 +00:00
if ( data_get ( $resource , 'uuid' )) {
if ( $resource -> uuid !== $app -> uuid ) {
2024-10-10 08:24:11 +00:00
throw new \RuntimeException ( " Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href=' { $app -> link () } '> { $app -> name } </a> " );
2024-04-08 10:15:44 +00:00
}
2024-06-10 20:43:34 +00:00
} elseif ( $domain ) {
2024-10-10 08:24:11 +00:00
throw new \RuntimeException ( " Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href=' { $app -> link () } '> { $app -> name } </a> " );
2024-01-30 08:22:34 +00:00
}
}
}
}
$apps = ServiceApplication :: all ();
foreach ( $apps as $app ) {
2024-12-09 14:38:21 +00:00
$list_of_domains = collect ( explode ( ',' , $app -> fqdn )) -> filter ( fn ( $fqdn ) => $fqdn !== '' );
2024-01-30 08:22:34 +00:00
foreach ( $list_of_domains as $domain ) {
2024-02-01 09:53:05 +00:00
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
2024-04-08 10:15:44 +00:00
$naked_domain = str ( $domain ) -> value ();
2024-01-30 08:22:34 +00:00
if ( $domains -> contains ( $naked_domain )) {
2024-04-08 10:15:44 +00:00
if ( data_get ( $resource , 'uuid' )) {
if ( $resource -> uuid !== $app -> uuid ) {
2024-10-10 08:24:11 +00:00
throw new \RuntimeException ( " Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href=' { $app -> service -> link () } '> { $app -> service -> name } </a> " );
2024-04-08 10:15:44 +00:00
}
2024-06-10 20:43:34 +00:00
} elseif ( $domain ) {
2024-10-10 08:24:11 +00:00
throw new \RuntimeException ( " Domain $naked_domain is already in use by another resource: <br><br>Link: <a class='underline' target='_blank' href=' { $app -> service -> link () } '> { $app -> service -> name } </a> " );
2024-01-30 08:22:34 +00:00
}
}
}
}
2024-04-08 10:15:44 +00:00
if ( $resource ) {
2024-10-01 08:37:40 +00:00
$settings = instanceSettings ();
2024-04-08 10:15:44 +00:00
if ( data_get ( $settings , 'fqdn' )) {
$domain = data_get ( $settings , 'fqdn' );
if ( str ( $domain ) -> endsWith ( '/' )) {
$domain = str ( $domain ) -> beforeLast ( '/' );
}
$naked_domain = str ( $domain ) -> value ();
if ( $domains -> contains ( $naked_domain )) {
throw new \RuntimeException ( " Domain $naked_domain is already in use by this Coolify instance. " );
}
}
}
2024-01-30 08:22:34 +00:00
}
2024-04-16 18:57:54 +00:00
2024-04-16 19:22:57 +00:00
function parseCommandsByLineForSudo ( Collection $commands , Server $server ) : array
{
2024-04-16 18:57:54 +00:00
$commands = $commands -> map ( function ( $line ) {
2024-10-02 16:26:40 +00:00
if (
2024-12-09 14:38:21 +00:00
! str ( trim ( $line )) -> startsWith ([
2024-10-02 16:26:40 +00:00
'cd' ,
'command' ,
'echo' ,
'true' ,
'if' ,
'fi' ,
])
) {
2024-04-16 18:57:54 +00:00
return " sudo $line " ;
}
2024-06-10 20:43:34 +00:00
2024-09-30 21:21:58 +00:00
if ( str ( trim ( $line )) -> startsWith ( 'if' )) {
return str_replace ( 'if' , 'if sudo' , $line );
}
2024-04-16 18:57:54 +00:00
return $line ;
});
2024-09-30 21:21:58 +00:00
2024-04-16 18:57:54 +00:00
$commands = $commands -> map ( function ( $line ) use ( $server ) {
if ( Str :: startsWith ( $line , 'sudo mkdir -p' )) {
2024-12-09 14:38:21 +00:00
return " $line && sudo chown -R $server->user : $server->user " . Str :: after ( $line , 'sudo mkdir -p' ) . ' && sudo chmod -R o-rwx ' . Str :: after ( $line , 'sudo mkdir -p' );
2024-04-16 18:57:54 +00:00
}
2024-06-10 20:43:34 +00:00
2024-04-16 18:57:54 +00:00
return $line ;
});
2024-09-30 21:21:58 +00:00
2024-04-16 18:57:54 +00:00
$commands = $commands -> map ( function ( $line ) {
2024-04-17 08:49:34 +00:00
$line = str ( $line );
if ( str ( $line ) -> contains ( '$(' )) {
$line = $line -> replace ( '$(' , '$(sudo ' );
2024-04-16 18:57:54 +00:00
}
if ( str ( $line ) -> contains ( '||' )) {
2024-04-17 08:49:34 +00:00
$line = $line -> replace ( '||' , '|| sudo' );
2024-04-16 18:57:54 +00:00
}
if ( str ( $line ) -> contains ( '&&' )) {
2024-04-17 08:49:34 +00:00
$line = $line -> replace ( '&&' , '&& sudo' );
2024-04-16 18:57:54 +00:00
}
2024-04-17 08:49:34 +00:00
if ( str ( $line ) -> contains ( ' | ' )) {
$line = $line -> replace ( ' | ' , ' | sudo ' );
}
2024-06-10 20:43:34 +00:00
2024-04-17 08:49:34 +00:00
return $line -> value ();
2024-04-16 18:57:54 +00:00
});
return $commands -> toArray ();
}
2024-04-16 19:22:57 +00:00
function parseLineForSudo ( string $command , Server $server ) : string
{
2024-12-09 14:38:21 +00:00
if ( ! str ( $command ) -> startSwith ( 'cd' ) && ! str ( $command ) -> startSwith ( 'command' )) {
2024-04-16 19:22:57 +00:00
$command = " sudo $command " ;
}
if ( Str :: startsWith ( $command , 'sudo mkdir -p' )) {
2024-12-09 14:38:21 +00:00
$command = " $command && sudo chown -R $server->user : $server->user " . Str :: after ( $command , 'sudo mkdir -p' ) . ' && sudo chmod -R o-rwx ' . Str :: after ( $command , 'sudo mkdir -p' );
2024-04-16 19:22:57 +00:00
}
if ( str ( $command ) -> contains ( '$(' ) || str ( $command ) -> contains ( '`' )) {
$command = str ( $command ) -> replace ( '$(' , '$(sudo ' ) -> replace ( '`' , '`sudo ' ) -> value ();
}
if ( str ( $command ) -> contains ( '||' )) {
$command = str ( $command ) -> replace ( '||' , '|| sudo ' ) -> value ();
}
if ( str ( $command ) -> contains ( '&&' )) {
$command = str ( $command ) -> replace ( '&&' , '&& sudo ' ) -> value ();
}
return $command ;
}
2024-04-25 11:52:52 +00:00
function get_public_ips ()
{
try {
[ $first , $second ] = Process :: concurrently ( function ( Pool $pool ) {
$pool -> path ( __DIR__ ) -> command ( 'curl -4s https://ifconfig.io' );
$pool -> path ( __DIR__ ) -> command ( 'curl -6s https://ifconfig.io' );
});
$ipv4 = $first -> output ();
if ( $ipv4 ) {
$ipv4 = trim ( $ipv4 );
$validate_ipv4 = filter_var ( $ipv4 , FILTER_VALIDATE_IP );
if ( $validate_ipv4 == false ) {
echo " Invalid ipv4: $ipv4\n " ;
2024-06-10 20:43:34 +00:00
2024-04-25 11:52:52 +00:00
return ;
}
2024-09-29 18:12:30 +00:00
InstanceSettings :: get () -> update ([ 'public_ipv4' => $ipv4 ]);
2024-04-25 11:52:52 +00:00
}
2024-09-23 18:31:50 +00:00
} catch ( \Exception $e ) {
echo " Error: { $e -> getMessage () } \n " ;
}
try {
2024-04-25 11:52:52 +00:00
$ipv6 = $second -> output ();
if ( $ipv6 ) {
$ipv6 = trim ( $ipv6 );
$validate_ipv6 = filter_var ( $ipv6 , FILTER_VALIDATE_IP );
if ( $validate_ipv6 == false ) {
echo " Invalid ipv6: $ipv6\n " ;
2024-06-10 20:43:34 +00:00
2024-04-25 11:52:52 +00:00
return ;
}
2024-09-29 18:12:30 +00:00
InstanceSettings :: get () -> update ([ 'public_ipv6' => $ipv6 ]);
2024-04-25 11:52:52 +00:00
}
} catch ( \Throwable $e ) {
echo " Error: { $e -> getMessage () } \n " ;
}
}
2024-06-11 10:37:39 +00:00
2024-06-11 10:38:24 +00:00
function isAnyDeploymentInprogress ()
{
2025-01-10 17:34:16 +00:00
$runningJobs = ApplicationDeploymentQueue :: where ( 'horizon_job_worker' , gethostname ()) -> where ( 'status' , ApplicationDeploymentStatus :: IN_PROGRESS -> value ) -> get ();
2025-03-28 14:30:21 +00:00
$basicDetails = $runningJobs -> map ( function ( $job ) {
return [
'id' => $job -> id ,
'created_at' => $job -> created_at ,
'application_id' => $job -> application_id ,
'server_id' => $job -> server_id ,
'horizon_job_id' => $job -> horizon_job_id ,
'status' => $job -> status ,
];
});
echo 'Running jobs: ' . json_encode ( $basicDetails ) . " \n " ;
2025-01-10 17:34:16 +00:00
$horizonJobIds = [];
foreach ( $runningJobs as $runningJob ) {
2025-01-10 18:53:13 +00:00
$horizonJobStatus = getJobStatus ( $runningJob -> horizon_job_id );
2025-03-28 14:42:25 +00:00
if ( $horizonJobStatus === 'unknown' || $horizonJobStatus === 'reserved' ) {
2025-03-28 14:09:38 +00:00
$horizonJobIds [] = $runningJob -> horizon_job_id ;
2025-01-10 17:34:16 +00:00
}
}
if ( count ( $horizonJobIds ) === 0 ) {
echo " No deployments in progress. \n " ;
exit ( 0 );
}
$horizonJobIds = collect ( $horizonJobIds ) -> unique () -> toArray ();
echo 'There are ' . count ( $horizonJobIds ) . " deployments in progress. \n " ;
exit ( 1 );
2024-06-11 10:37:39 +00:00
}
2024-06-18 14:42:42 +00:00
2024-06-25 19:22:23 +00:00
function isBase64Encoded ( $strValue )
{
return base64_encode ( base64_decode ( $strValue , true )) === $strValue ;
}
2024-06-26 11:32:36 +00:00
function customApiValidator ( Collection | array $item , array $rules )
{
if ( is_array ( $item )) {
$item = collect ( $item );
}
return Validator :: make ( $item -> toArray (), $rules , [
'required' => 'This field is required.' ,
]);
}
2024-08-12 14:06:24 +00:00
function parseServiceVolumes ( $serviceVolumes , $resource , $topLevelVolumes , $pull_request_id = 0 )
{
2024-08-13 10:43:17 +00:00
$serviceVolumes = $serviceVolumes -> map ( function ( $volume ) use ( $resource , $topLevelVolumes , $pull_request_id ) {
2024-08-12 14:06:24 +00:00
$type = null ;
$source = null ;
$target = null ;
$content = null ;
$isDirectory = false ;
if ( is_string ( $volume )) {
$source = str ( $volume ) -> before ( ':' );
$target = str ( $volume ) -> after ( ':' ) -> beforeLast ( ':' );
2024-08-21 12:31:17 +00:00
$foundConfig = $resource -> fileStorages () -> whereMountPath ( $target ) -> first ();
2024-08-12 14:06:24 +00:00
if ( $source -> startsWith ( './' ) || $source -> startsWith ( '/' ) || $source -> startsWith ( '~' )) {
$type = str ( 'bind' );
2024-08-21 12:31:17 +00:00
if ( $foundConfig ) {
$contentNotNull = data_get ( $foundConfig , 'content' );
if ( $contentNotNull ) {
$content = $contentNotNull ;
}
$isDirectory = data_get ( $foundConfig , 'is_directory' );
} else {
// By default, we cannot determine if the bind is a directory or not, so we set it to directory
$isDirectory = true ;
}
2024-08-12 14:06:24 +00:00
} else {
$type = str ( 'volume' );
}
} elseif ( is_array ( $volume )) {
$type = data_get_str ( $volume , 'type' );
$source = data_get_str ( $volume , 'source' );
$target = data_get_str ( $volume , 'target' );
$content = data_get ( $volume , 'content' );
$isDirectory = ( bool ) data_get ( $volume , 'isDirectory' , null ) || ( bool ) data_get ( $volume , 'is_directory' , null );
$foundConfig = $resource -> fileStorages () -> whereMountPath ( $target ) -> first ();
if ( $foundConfig ) {
$contentNotNull = data_get ( $foundConfig , 'content' );
if ( $contentNotNull ) {
$content = $contentNotNull ;
}
2024-08-21 12:31:17 +00:00
$isDirectory = data_get ( $foundConfig , 'is_directory' );
} else {
2024-08-12 14:06:24 +00:00
$isDirectory = ( bool ) data_get ( $volume , 'isDirectory' , null ) || ( bool ) data_get ( $volume , 'is_directory' , null );
2024-12-09 14:38:21 +00:00
if (( is_null ( $isDirectory ) || ! $isDirectory ) && is_null ( $content )) {
2024-08-21 12:31:17 +00:00
// if isDirectory is not set (or false) & content is also not set, we assume it is a directory
$isDirectory = true ;
}
2024-08-12 14:06:24 +00:00
}
}
if ( $type ? -> value () === 'bind' ) {
if ( $source -> value () === '/var/run/docker.sock' ) {
return $volume ;
}
if ( $source -> value () === '/tmp' || $source -> value () === '/tmp/' ) {
return $volume ;
}
2024-10-28 13:56:13 +00:00
if ( get_class ( $resource ) === \App\Models\Application :: class ) {
2024-12-09 14:38:21 +00:00
$dir = base_configuration_dir () . '/applications/' . $resource -> uuid ;
2024-08-12 14:06:24 +00:00
} else {
2024-12-09 14:38:21 +00:00
$dir = base_configuration_dir () . '/services/' . $resource -> service -> uuid ;
2024-08-12 14:06:24 +00:00
}
if ( $source -> startsWith ( '.' )) {
$source = $source -> replaceFirst ( '.' , $dir );
}
if ( $source -> startsWith ( '~' )) {
$source = $source -> replaceFirst ( '~' , $dir );
}
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$source = $source . " -pr- $pull_request_id " ;
2024-08-12 14:06:24 +00:00
}
2024-12-09 14:38:21 +00:00
if ( ! $resource ? -> settings ? -> is_preserve_repository_enabled || $foundConfig ? -> is_based_on_git ) {
2025-03-29 21:16:12 +00:00
LocalFileVolume :: updateOrCreate (
[
'mount_path' => $target ,
'resource_id' => $resource -> id ,
'resource_type' => get_class ( $resource ),
],
[
'fs_path' => $source ,
'mount_path' => $target ,
'content' => $content ,
'is_directory' => $isDirectory ,
'resource_id' => $resource -> id ,
'resource_type' => get_class ( $resource ),
]
);
2024-08-21 12:31:17 +00:00
}
2024-08-12 14:06:24 +00:00
} elseif ( $type -> value () === 'volume' ) {
if ( $topLevelVolumes -> has ( $source -> value ())) {
$v = $topLevelVolumes -> get ( $source -> value ());
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
return $volume ;
}
}
$slugWithoutUuid = Str :: slug ( $source , '-' );
2024-10-28 13:56:13 +00:00
if ( get_class ( $resource ) === \App\Models\Application :: class ) {
2024-08-12 14:06:24 +00:00
$name = " { $resource -> uuid } _ { $slugWithoutUuid } " ;
} else {
$name = " { $resource -> service -> uuid } _ { $slugWithoutUuid } " ;
}
if ( is_string ( $volume )) {
$source = str ( $volume ) -> before ( ':' );
$target = str ( $volume ) -> after ( ':' ) -> beforeLast ( ':' );
$source = $name ;
$volume = " $source : $target " ;
} elseif ( is_array ( $volume )) {
data_set ( $volume , 'source' , $name );
}
$topLevelVolumes -> put ( $name , [
'name' => $name ,
]);
LocalPersistentVolume :: updateOrCreate (
[
'mount_path' => $target ,
'resource_id' => $resource -> id ,
'resource_type' => get_class ( $resource ),
],
[
'name' => $name ,
'mount_path' => $target ,
'resource_id' => $resource -> id ,
'resource_type' => get_class ( $resource ),
]
);
}
dispatch ( new ServerFilesFromServerJob ( $resource ));
2024-08-13 10:43:17 +00:00
return $volume ;
2024-08-12 14:06:24 +00:00
});
2024-08-13 10:43:17 +00:00
return [
'serviceVolumes' => $serviceVolumes ,
'topLevelVolumes' => $topLevelVolumes ,
];
2024-08-12 14:06:24 +00:00
}
2024-08-23 18:54:38 +00:00
function parseDockerComposeFile ( Service | Application $resource , bool $isNew = false , int $pull_request_id = 0 , ? int $preview_id = null )
{
2024-10-28 13:56:13 +00:00
if ( $resource -> getMorphClass () === \App\Models\Service :: class ) {
2024-08-23 18:54:38 +00:00
if ( $resource -> docker_compose_raw ) {
try {
$yaml = Yaml :: parse ( $resource -> docker_compose_raw );
} catch ( \Exception $e ) {
throw new \Exception ( $e -> getMessage ());
}
$allServices = get_service_templates ();
$topLevelVolumes = collect ( data_get ( $yaml , 'volumes' , []));
$topLevelNetworks = collect ( data_get ( $yaml , 'networks' , []));
$topLevelConfigs = collect ( data_get ( $yaml , 'configs' , []));
$topLevelSecrets = collect ( data_get ( $yaml , 'secrets' , []));
$services = data_get ( $yaml , 'services' );
$generatedServiceFQDNS = collect ([]);
if ( is_null ( $resource -> destination )) {
$destination = $resource -> server -> destinations () -> first ();
if ( $destination ) {
$resource -> destination () -> associate ( $destination );
$resource -> save ();
}
}
$definedNetwork = collect ([ $resource -> uuid ]);
if ( $topLevelVolumes -> count () > 0 ) {
$tempTopLevelVolumes = collect ([]);
foreach ( $topLevelVolumes as $volumeName => $volume ) {
if ( is_null ( $volume )) {
continue ;
}
$tempTopLevelVolumes -> put ( $volumeName , $volume );
}
$topLevelVolumes = collect ( $tempTopLevelVolumes );
}
$services = collect ( $services ) -> map ( function ( $service , $serviceName ) use ( $topLevelVolumes , $topLevelNetworks , $definedNetwork , $isNew , $generatedServiceFQDNS , $resource , $allServices ) {
// Workarounds for beta users.
if ( $serviceName === 'registry' ) {
$tempServiceName = 'docker-registry' ;
} else {
$tempServiceName = $serviceName ;
}
if ( str ( data_get ( $service , 'image' )) -> contains ( 'glitchtip' )) {
$tempServiceName = 'glitchtip' ;
}
if ( $serviceName === 'supabase-kong' ) {
$tempServiceName = 'supabase' ;
}
$serviceDefinition = data_get ( $allServices , $tempServiceName );
$predefinedPort = data_get ( $serviceDefinition , 'port' );
if ( $serviceName === 'plausible' ) {
$predefinedPort = '8000' ;
}
// End of workarounds for beta users.
$serviceVolumes = collect ( data_get ( $service , 'volumes' , []));
$servicePorts = collect ( data_get ( $service , 'ports' , []));
$serviceNetworks = collect ( data_get ( $service , 'networks' , []));
$serviceVariables = collect ( data_get ( $service , 'environment' , []));
$serviceLabels = collect ( data_get ( $service , 'labels' , []));
$hasHostNetworkMode = data_get ( $service , 'network_mode' ) === 'host' ? true : false ;
if ( $serviceLabels -> count () > 0 ) {
$removedLabels = collect ([]);
$serviceLabels = $serviceLabels -> filter ( function ( $serviceLabel , $serviceLabelName ) use ( $removedLabels ) {
2024-12-09 14:38:21 +00:00
if ( ! str ( $serviceLabel ) -> contains ( '=' )) {
2024-08-23 18:54:38 +00:00
$removedLabels -> put ( $serviceLabelName , $serviceLabel );
return false ;
}
return $serviceLabel ;
});
foreach ( $removedLabels as $removedLabelName => $removedLabel ) {
$serviceLabels -> push ( " $removedLabelName = $removedLabel " );
}
}
$containerName = " $serviceName - { $resource -> uuid } " ;
// Decide if the service is a database
$isDatabase = isDatabaseImage ( data_get_str ( $service , 'image' ));
$image = data_get_str ( $service , 'image' );
data_set ( $service , 'is_database' , $isDatabase );
// Create new serviceApplication or serviceDatabase
if ( $isDatabase ) {
if ( $isNew ) {
$savedService = ServiceDatabase :: create ([
'name' => $serviceName ,
'image' => $image ,
'service_id' => $resource -> id ,
]);
} else {
$savedService = ServiceDatabase :: where ([
'name' => $serviceName ,
'service_id' => $resource -> id ,
]) -> first ();
}
} else {
if ( $isNew ) {
$savedService = ServiceApplication :: create ([
'name' => $serviceName ,
'image' => $image ,
'service_id' => $resource -> id ,
]);
} else {
$savedService = ServiceApplication :: where ([
'name' => $serviceName ,
'service_id' => $resource -> id ,
]) -> first ();
}
}
if ( is_null ( $savedService )) {
if ( $isDatabase ) {
$savedService = ServiceDatabase :: create ([
'name' => $serviceName ,
'image' => $image ,
'service_id' => $resource -> id ,
]);
} else {
$savedService = ServiceApplication :: create ([
'name' => $serviceName ,
'image' => $image ,
'service_id' => $resource -> id ,
]);
}
}
// Check if image changed
if ( $savedService -> image !== $image ) {
$savedService -> image = $image ;
$savedService -> save ();
}
// Collect/create/update networks
if ( $serviceNetworks -> count () > 0 ) {
foreach ( $serviceNetworks as $networkName => $networkDetails ) {
if ( $networkName === 'default' ) {
continue ;
}
// ignore alias
if ( $networkDetails [ 'aliases' ] ? ? false ) {
continue ;
}
$networkExists = $topLevelNetworks -> contains ( function ( $value , $key ) use ( $networkName ) {
return $value == $networkName || $key == $networkName ;
});
2024-12-09 14:38:21 +00:00
if ( ! $networkExists ) {
2024-10-03 13:04:40 +00:00
if ( is_string ( $networkDetails ) || is_int ( $networkDetails )) {
$topLevelNetworks -> put ( $networkDetails , null );
}
2024-08-23 18:54:38 +00:00
}
}
}
// Collect/create/update ports
$collectedPorts = collect ([]);
if ( $servicePorts -> count () > 0 ) {
foreach ( $servicePorts as $sport ) {
if ( is_string ( $sport ) || is_numeric ( $sport )) {
$collectedPorts -> push ( $sport );
}
if ( is_array ( $sport )) {
$target = data_get ( $sport , 'target' );
$published = data_get ( $sport , 'published' );
$protocol = data_get ( $sport , 'protocol' );
$collectedPorts -> push ( " $target : $published / $protocol " );
}
}
}
$savedService -> ports = $collectedPorts -> implode ( ',' );
$savedService -> save ();
2024-12-09 14:38:21 +00:00
if ( ! $hasHostNetworkMode ) {
2024-08-23 18:54:38 +00:00
// Add Coolify specific networks
$definedNetworkExists = $topLevelNetworks -> contains ( function ( $value , $_ ) use ( $definedNetwork ) {
return $value == $definedNetwork ;
});
2024-12-09 14:38:21 +00:00
if ( ! $definedNetworkExists ) {
2024-08-23 18:54:38 +00:00
foreach ( $definedNetwork as $network ) {
$topLevelNetworks -> put ( $network , [
'name' => $network ,
'external' => true ,
]);
}
}
$networks = collect ();
foreach ( $serviceNetworks as $key => $serviceNetwork ) {
if ( gettype ( $serviceNetwork ) === 'string' ) {
// networks:
// - appwrite
$networks -> put ( $serviceNetwork , null );
} elseif ( gettype ( $serviceNetwork ) === 'array' ) {
// networks:
// default:
// ipv4_address: 192.168.203.254
// $networks->put($serviceNetwork, null);
$networks -> put ( $key , $serviceNetwork );
}
}
foreach ( $definedNetwork as $key => $network ) {
$networks -> put ( $network , null );
}
data_set ( $service , 'networks' , $networks -> toArray ());
}
// Collect/create/update volumes
if ( $serviceVolumes -> count () > 0 ) {
$serviceVolumes = $serviceVolumes -> map ( function ( $volume ) use ( $savedService , $topLevelVolumes ) {
$type = null ;
$source = null ;
$target = null ;
$content = null ;
$isDirectory = false ;
if ( is_string ( $volume )) {
$source = str ( $volume ) -> before ( ':' );
$target = str ( $volume ) -> after ( ':' ) -> beforeLast ( ':' );
if ( $source -> startsWith ( './' ) || $source -> startsWith ( '/' ) || $source -> startsWith ( '~' )) {
$type = str ( 'bind' );
// By default, we cannot determine if the bind is a directory or not, so we set it to directory
$isDirectory = true ;
} else {
$type = str ( 'volume' );
}
} elseif ( is_array ( $volume )) {
$type = data_get_str ( $volume , 'type' );
$source = data_get_str ( $volume , 'source' );
$target = data_get_str ( $volume , 'target' );
$content = data_get ( $volume , 'content' );
$isDirectory = ( bool ) data_get ( $volume , 'isDirectory' , null ) || ( bool ) data_get ( $volume , 'is_directory' , null );
$foundConfig = $savedService -> fileStorages () -> whereMountPath ( $target ) -> first ();
if ( $foundConfig ) {
$contentNotNull = data_get ( $foundConfig , 'content' );
if ( $contentNotNull ) {
$content = $contentNotNull ;
}
$isDirectory = ( bool ) data_get ( $volume , 'isDirectory' , null ) || ( bool ) data_get ( $volume , 'is_directory' , null );
}
if ( is_null ( $isDirectory ) && is_null ( $content )) {
// if isDirectory is not set & content is also not set, we assume it is a directory
$isDirectory = true ;
}
}
if ( $type ? -> value () === 'bind' ) {
if ( $source -> value () === '/var/run/docker.sock' ) {
return $volume ;
}
if ( $source -> value () === '/tmp' || $source -> value () === '/tmp/' ) {
return $volume ;
}
2025-03-28 21:10:33 +00:00
2025-03-29 21:16:12 +00:00
LocalFileVolume :: updateOrCreate (
[
2024-08-23 18:54:38 +00:00
'mount_path' => $target ,
'resource_id' => $savedService -> id ,
'resource_type' => get_class ( $savedService ),
2025-03-29 21:16:12 +00:00
],
[
2024-08-23 18:54:38 +00:00
'fs_path' => $source ,
'mount_path' => $target ,
'content' => $content ,
'is_directory' => $isDirectory ,
'resource_id' => $savedService -> id ,
'resource_type' => get_class ( $savedService ),
2025-03-29 21:16:12 +00:00
]
);
2024-08-23 18:54:38 +00:00
} elseif ( $type -> value () === 'volume' ) {
if ( $topLevelVolumes -> has ( $source -> value ())) {
$v = $topLevelVolumes -> get ( $source -> value ());
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
return $volume ;
}
}
$slugWithoutUuid = Str :: slug ( $source , '-' );
$name = " { $savedService -> service -> uuid } _ { $slugWithoutUuid } " ;
if ( is_string ( $volume )) {
$source = str ( $volume ) -> before ( ':' );
$target = str ( $volume ) -> after ( ':' ) -> beforeLast ( ':' );
$source = $name ;
$volume = " $source : $target " ;
} elseif ( is_array ( $volume )) {
data_set ( $volume , 'source' , $name );
}
$topLevelVolumes -> put ( $name , [
'name' => $name ,
]);
LocalPersistentVolume :: updateOrCreate (
[
'mount_path' => $target ,
'resource_id' => $savedService -> id ,
'resource_type' => get_class ( $savedService ),
],
[
'name' => $name ,
'mount_path' => $target ,
'resource_id' => $savedService -> id ,
'resource_type' => get_class ( $savedService ),
]
);
}
dispatch ( new ServerFilesFromServerJob ( $savedService ));
return $volume ;
});
data_set ( $service , 'volumes' , $serviceVolumes -> toArray ());
}
2024-08-24 09:00:27 +00:00
// convert - SESSION_SECRET: 123 to - SESSION_SECRET=123
$convertedServiceVariables = collect ([]);
foreach ( $serviceVariables as $variableName => $variable ) {
if ( is_numeric ( $variableName )) {
if ( is_array ( $variable )) {
$key = str ( collect ( $variable ) -> keys () -> first ());
$value = str ( collect ( $variable ) -> values () -> first ());
$variable = " $key = $value " ;
$convertedServiceVariables -> put ( $variableName , $variable );
} elseif ( is_string ( $variable )) {
$convertedServiceVariables -> put ( $variableName , $variable );
}
2024-08-27 14:02:52 +00:00
} elseif ( is_string ( $variableName )) {
$convertedServiceVariables -> put ( $variableName , $variable );
2024-08-24 09:00:27 +00:00
}
}
$serviceVariables = $convertedServiceVariables ;
2024-08-23 18:54:38 +00:00
// Get variables from the service
foreach ( $serviceVariables as $variableName => $variable ) {
if ( is_numeric ( $variableName )) {
if ( is_array ( $variable )) {
// - SESSION_SECRET: 123
// - SESSION_SECRET:
$key = str ( collect ( $variable ) -> keys () -> first ());
$value = str ( collect ( $variable ) -> values () -> first ());
} else {
$variable = str ( $variable );
if ( $variable -> contains ( '=' )) {
// - SESSION_SECRET=123
// - SESSION_SECRET=
$key = $variable -> before ( '=' );
$value = $variable -> after ( '=' );
} else {
// - SESSION_SECRET
$key = $variable ;
$value = null ;
}
}
} else {
// SESSION_SECRET: 123
// SESSION_SECRET:
$key = str ( $variableName );
$value = str ( $variable );
}
if ( $key -> startsWith ( 'SERVICE_FQDN' )) {
if ( $isNew || $savedService -> fqdn === null ) {
$name = $key -> after ( 'SERVICE_FQDN_' ) -> beforeLast ( '_' ) -> lower ();
$fqdn = generateFqdn ( $resource -> server , " { $name -> value () } - { $resource -> uuid } " );
if ( substr_count ( $key -> value (), '_' ) === 3 ) {
// SERVICE_FQDN_UMAMI_1000
$port = $key -> afterLast ( '_' );
} else {
$last = $key -> afterLast ( '_' );
if ( is_numeric ( $last -> value ())) {
// SERVICE_FQDN_3001
$port = $last ;
} else {
// SERVICE_FQDN_UMAMI
$port = null ;
}
}
if ( $port ) {
$fqdn = " $fqdn : $port " ;
}
if ( substr_count ( $key -> value (), '_' ) >= 2 ) {
if ( $value ) {
$path = $value -> value ();
} else {
$path = null ;
}
if ( $generatedServiceFQDNS -> count () > 0 ) {
$alreadyGenerated = $generatedServiceFQDNS -> has ( $key -> value ());
if ( $alreadyGenerated ) {
$fqdn = $generatedServiceFQDNS -> get ( $key -> value ());
} else {
$generatedServiceFQDNS -> put ( $key -> value (), $fqdn );
}
} else {
$generatedServiceFQDNS -> put ( $key -> value (), $fqdn );
}
$fqdn = " $fqdn $path " ;
}
2024-12-09 14:38:21 +00:00
if ( ! $isDatabase ) {
2024-08-23 18:54:38 +00:00
if ( $savedService -> fqdn ) {
2024-12-09 14:38:21 +00:00
data_set ( $savedService , 'fqdn' , $savedService -> fqdn . ',' . $fqdn );
2024-08-23 18:54:38 +00:00
} else {
data_set ( $savedService , 'fqdn' , $fqdn );
}
$savedService -> save ();
}
EnvironmentVariable :: create ([
'key' => $key ,
'value' => $fqdn ,
'is_build_time' => false ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]);
}
// Caddy needs exact port in some cases.
2024-12-09 14:38:21 +00:00
if ( $predefinedPort && ! $key -> endsWith ( " _ { $predefinedPort } " )) {
2024-08-23 18:54:38 +00:00
$fqdns_exploded = str ( $savedService -> fqdn ) -> explode ( ',' );
if ( $fqdns_exploded -> count () > 1 ) {
continue ;
}
$env = EnvironmentVariable :: where ([
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
]) -> first ();
if ( $env ) {
$env_url = Url :: fromString ( $savedService -> fqdn );
$env_port = $env_url -> getPort ();
if ( $env_port !== $predefinedPort ) {
$env_url = $env_url -> withPort ( $predefinedPort );
$savedService -> fqdn = $env_url -> __toString ();
$savedService -> save ();
}
}
}
// data_forget($service, "environment.$variableName");
// $yaml = data_forget($yaml, "services.$serviceName.environment.$variableName");
// if (count(data_get($yaml, 'services.' . $serviceName . '.environment')) === 0) {
// $yaml = data_forget($yaml, "services.$serviceName.environment");
// }
continue ;
}
if ( $value ? -> startsWith ( '$' )) {
$foundEnv = EnvironmentVariable :: where ([
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
]) -> first ();
2024-09-09 13:04:51 +00:00
$value = replaceVariables ( $value );
2024-08-23 18:54:38 +00:00
$key = $value ;
if ( $value -> startsWith ( 'SERVICE_' )) {
$foundEnv = EnvironmentVariable :: where ([
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
]) -> first ();
[ 'command' => $command , 'forService' => $forService , 'generatedValue' => $generatedValue , 'port' => $port ] = parseEnvVariable ( $value );
2024-12-09 14:38:21 +00:00
if ( ! is_null ( $command )) {
2024-08-23 18:54:38 +00:00
if ( $command ? -> value () === 'FQDN' || $command ? -> value () === 'URL' ) {
if ( Str :: lower ( $forService ) === $serviceName ) {
$fqdn = generateFqdn ( $resource -> server , $containerName );
} else {
2024-12-09 14:38:21 +00:00
$fqdn = generateFqdn ( $resource -> server , Str :: lower ( $forService ) . '-' . $resource -> uuid );
2024-08-23 18:54:38 +00:00
}
if ( $port ) {
$fqdn = " $fqdn : $port " ;
}
if ( $foundEnv ) {
$fqdn = data_get ( $foundEnv , 'value' );
// if ($savedService->fqdn) {
// $savedServiceFqdn = Url::fromString($savedService->fqdn);
// $parsedFqdn = Url::fromString($fqdn);
// $savedServicePath = $savedServiceFqdn->getPath();
// $parsedFqdnPath = $parsedFqdn->getPath();
// if ($savedServicePath != $parsedFqdnPath) {
// $fqdn = $parsedFqdn->withPath($savedServicePath)->__toString();
// $foundEnv->value = $fqdn;
// $foundEnv->save();
// }
// }
} else {
if ( $command -> value () === 'URL' ) {
$fqdn = str ( $fqdn ) -> after ( '://' ) -> value ();
}
EnvironmentVariable :: create ([
'key' => $key ,
'value' => $fqdn ,
'is_build_time' => false ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]);
}
2024-12-09 14:38:21 +00:00
if ( ! $isDatabase ) {
if ( $command -> value () === 'FQDN' && is_null ( $savedService -> fqdn ) && ! $foundEnv ) {
2024-08-23 18:54:38 +00:00
$savedService -> fqdn = $fqdn ;
$savedService -> save ();
}
// Caddy needs exact port in some cases.
2024-12-09 14:38:21 +00:00
if ( $predefinedPort && ! $key -> endsWith ( " _ { $predefinedPort } " ) && $command ? -> value () === 'FQDN' && $resource -> server -> proxyType () === 'CADDY' ) {
2024-08-23 18:54:38 +00:00
$fqdns_exploded = str ( $savedService -> fqdn ) -> explode ( ',' );
if ( $fqdns_exploded -> count () > 1 ) {
continue ;
}
$env = EnvironmentVariable :: where ([
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
]) -> first ();
if ( $env ) {
$env_url = Url :: fromString ( $env -> value );
$env_port = $env_url -> getPort ();
if ( $env_port !== $predefinedPort ) {
$env_url = $env_url -> withPort ( $predefinedPort );
$savedService -> fqdn = $env_url -> __toString ();
$savedService -> save ();
}
}
}
}
} else {
$generatedValue = generateEnvValue ( $command , $resource );
2024-12-09 14:38:21 +00:00
if ( ! $foundEnv ) {
2024-08-23 18:54:38 +00:00
EnvironmentVariable :: create ([
'key' => $key ,
'value' => $generatedValue ,
'is_build_time' => false ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]);
}
}
}
} else {
if ( $value -> contains ( ':-' )) {
$key = $value -> before ( ':' );
$defaultValue = $value -> after ( ':-' );
} elseif ( $value -> contains ( '-' )) {
$key = $value -> before ( '-' );
$defaultValue = $value -> after ( '-' );
} elseif ( $value -> contains ( ':?' )) {
$key = $value -> before ( ':' );
$defaultValue = $value -> after ( ':?' );
} elseif ( $value -> contains ( '?' )) {
$key = $value -> before ( '?' );
$defaultValue = $value -> after ( '?' );
} else {
$key = $value ;
$defaultValue = null ;
}
$foundEnv = EnvironmentVariable :: where ([
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
]) -> first ();
if ( $foundEnv ) {
$defaultValue = data_get ( $foundEnv , 'value' );
}
EnvironmentVariable :: updateOrCreate ([
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
], [
'value' => $defaultValue ,
'is_build_time' => false ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]);
}
}
}
// Add labels to the service
if ( $savedService -> serviceType ()) {
$fqdns = generateServiceSpecificFqdns ( $savedService );
} else {
$fqdns = collect ( data_get ( $savedService , 'fqdns' )) -> filter ();
}
2024-11-17 21:49:44 +00:00
$defaultLabels = defaultLabels (
id : $resource -> id ,
name : $containerName ,
projectName : $resource -> project () -> name ,
resourceName : $resource -> name ,
type : 'service' ,
2025-01-20 12:58:52 +00:00
subType : $isDatabase ? 'database' : 'application' ,
2024-11-17 21:49:44 +00:00
subId : $savedService -> id ,
subName : $savedService -> name ,
2024-12-02 17:38:21 +00:00
environment : $resource -> environment -> name ,
2024-11-17 21:49:44 +00:00
);
2024-08-23 18:54:38 +00:00
$serviceLabels = $serviceLabels -> merge ( $defaultLabels );
2024-12-09 14:38:21 +00:00
if ( ! $isDatabase && $fqdns -> count () > 0 ) {
2024-08-23 18:54:38 +00:00
if ( $fqdns ) {
$shouldGenerateLabelsExactly = $resource -> server -> settings -> generate_exact_labels ;
if ( $shouldGenerateLabelsExactly ) {
switch ( $resource -> server -> proxyType ()) {
case ProxyTypes :: TRAEFIK -> value :
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForTraefik (
2024-08-23 18:54:38 +00:00
uuid : $resource -> uuid ,
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $savedService -> isGzipEnabled (),
is_stripprefix_enabled : $savedService -> isStripprefixEnabled (),
service_name : $serviceName ,
image : data_get ( $service , 'image' )
2025-02-28 19:25:19 +00:00
));
2024-08-23 18:54:38 +00:00
break ;
case ProxyTypes :: CADDY -> value :
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForCaddy (
2024-08-23 18:54:38 +00:00
network : $resource -> destination -> network ,
uuid : $resource -> uuid ,
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $savedService -> isGzipEnabled (),
is_stripprefix_enabled : $savedService -> isStripprefixEnabled (),
service_name : $serviceName ,
image : data_get ( $service , 'image' )
2025-02-28 19:25:19 +00:00
));
2024-08-23 18:54:38 +00:00
break ;
}
} else {
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForTraefik (
2024-08-23 18:54:38 +00:00
uuid : $resource -> uuid ,
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $savedService -> isGzipEnabled (),
is_stripprefix_enabled : $savedService -> isStripprefixEnabled (),
service_name : $serviceName ,
image : data_get ( $service , 'image' )
2025-02-28 19:25:19 +00:00
));
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForCaddy (
2024-08-23 18:54:38 +00:00
network : $resource -> destination -> network ,
uuid : $resource -> uuid ,
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $savedService -> isGzipEnabled (),
is_stripprefix_enabled : $savedService -> isStripprefixEnabled (),
service_name : $serviceName ,
image : data_get ( $service , 'image' )
2025-02-28 19:25:19 +00:00
));
2024-08-23 18:54:38 +00:00
}
}
}
if ( $resource -> server -> isLogDrainEnabled () && $savedService -> isLogDrainEnabled ()) {
2024-08-28 09:11:14 +00:00
data_set ( $service , 'logging' , generate_fluentd_configuration ());
2024-08-23 18:54:38 +00:00
}
if ( $serviceLabels -> count () > 0 ) {
if ( $resource -> is_container_label_escape_enabled ) {
$serviceLabels = $serviceLabels -> map ( function ( $value , $key ) {
return escapeDollarSign ( $value );
});
}
}
data_set ( $service , 'labels' , $serviceLabels -> toArray ());
data_forget ( $service , 'is_database' );
2024-12-09 14:38:21 +00:00
if ( ! data_get ( $service , 'restart' )) {
2024-08-23 18:54:38 +00:00
data_set ( $service , 'restart' , RESTART_MODE );
}
if ( data_get ( $service , 'restart' ) === 'no' || data_get ( $service , 'exclude_from_hc' )) {
$savedService -> update ([ 'exclude_from_status' => true ]);
}
data_set ( $service , 'container_name' , $containerName );
data_forget ( $service , 'volumes.*.content' );
data_forget ( $service , 'volumes.*.isDirectory' );
data_forget ( $service , 'volumes.*.is_directory' );
data_forget ( $service , 'exclude_from_hc' );
data_set ( $service , 'environment' , $serviceVariables -> toArray ());
updateCompose ( $savedService );
return $service ;
});
$envs_from_coolify = $resource -> environment_variables () -> get ();
$services = collect ( $services ) -> map ( function ( $service , $serviceName ) use ( $resource , $envs_from_coolify ) {
$serviceVariables = collect ( data_get ( $service , 'environment' , []));
$parsedServiceVariables = collect ([]);
foreach ( $serviceVariables as $key => $value ) {
if ( is_numeric ( $key )) {
$value = str ( $value );
if ( $value -> contains ( '=' )) {
$key = $value -> before ( '=' ) -> value ();
$value = $value -> after ( '=' ) -> value ();
} else {
$key = $value -> value ();
$value = null ;
}
$parsedServiceVariables -> put ( $key , $value );
} else {
$parsedServiceVariables -> put ( $key , $value );
}
}
2025-01-24 11:04:34 +00:00
$parsedServiceVariables -> put ( 'COOLIFY_RESOURCE_UUID' , " { $resource -> uuid } " );
2024-08-23 18:54:38 +00:00
$parsedServiceVariables -> put ( 'COOLIFY_CONTAINER_NAME' , " $serviceName - { $resource -> uuid } " );
2024-08-27 17:36:22 +00:00
// TODO: move this in a shared function
2024-12-09 14:38:21 +00:00
if ( ! $parsedServiceVariables -> has ( 'COOLIFY_APP_NAME' )) {
2024-09-13 06:23:05 +00:00
$parsedServiceVariables -> put ( 'COOLIFY_APP_NAME' , " \" { $resource -> name } \" " );
2024-08-27 17:36:22 +00:00
}
2024-12-09 14:38:21 +00:00
if ( ! $parsedServiceVariables -> has ( 'COOLIFY_SERVER_IP' )) {
2024-09-13 06:23:05 +00:00
$parsedServiceVariables -> put ( 'COOLIFY_SERVER_IP' , " \" { $resource -> destination -> server -> ip } \" " );
2024-08-27 17:36:22 +00:00
}
2024-12-09 14:38:21 +00:00
if ( ! $parsedServiceVariables -> has ( 'COOLIFY_ENVIRONMENT_NAME' )) {
2024-09-13 06:23:05 +00:00
$parsedServiceVariables -> put ( 'COOLIFY_ENVIRONMENT_NAME' , " \" { $resource -> environment -> name } \" " );
2024-08-27 17:36:22 +00:00
}
2024-12-09 14:38:21 +00:00
if ( ! $parsedServiceVariables -> has ( 'COOLIFY_PROJECT_NAME' )) {
2024-09-13 06:23:05 +00:00
$parsedServiceVariables -> put ( 'COOLIFY_PROJECT_NAME' , " \" { $resource -> project () -> name } \" " );
2024-08-27 17:36:22 +00:00
}
2024-08-23 18:54:38 +00:00
$parsedServiceVariables = $parsedServiceVariables -> map ( function ( $value , $key ) use ( $envs_from_coolify ) {
2024-12-09 14:38:21 +00:00
if ( ! str ( $value ) -> startsWith ( '$' )) {
2024-08-23 18:54:38 +00:00
$found_env = $envs_from_coolify -> where ( 'key' , $key ) -> first ();
if ( $found_env ) {
return $found_env -> value ;
}
}
return $value ;
});
data_set ( $service , 'environment' , $parsedServiceVariables -> toArray ());
return $service ;
});
$finalServices = [
'services' => $services -> toArray (),
'volumes' => $topLevelVolumes -> toArray (),
'networks' => $topLevelNetworks -> toArray (),
'configs' => $topLevelConfigs -> toArray (),
'secrets' => $topLevelSecrets -> toArray (),
];
$yaml = data_forget ( $yaml , 'services.*.volumes.*.content' );
$resource -> docker_compose_raw = Yaml :: dump ( $yaml , 10 , 2 );
$resource -> docker_compose = Yaml :: dump ( $finalServices , 10 , 2 );
2024-08-26 08:51:01 +00:00
2024-08-23 18:54:38 +00:00
$resource -> save ();
$resource -> saveComposeConfigs ();
return collect ( $finalServices );
} else {
return collect ([]);
}
2024-10-28 13:56:13 +00:00
} elseif ( $resource -> getMorphClass () === \App\Models\Application :: class ) {
2024-08-23 18:54:38 +00:00
try {
$yaml = Yaml :: parse ( $resource -> docker_compose_raw );
2024-10-31 14:19:37 +00:00
} catch ( \Exception ) {
2024-08-23 18:54:38 +00:00
return ;
}
$server = $resource -> destination -> server ;
$topLevelVolumes = collect ( data_get ( $yaml , 'volumes' , []));
if ( $pull_request_id !== 0 ) {
$topLevelVolumes = collect ([]);
}
if ( $topLevelVolumes -> count () > 0 ) {
$tempTopLevelVolumes = collect ([]);
foreach ( $topLevelVolumes as $volumeName => $volume ) {
if ( is_null ( $volume )) {
continue ;
}
$tempTopLevelVolumes -> put ( $volumeName , $volume );
}
$topLevelVolumes = collect ( $tempTopLevelVolumes );
}
$topLevelNetworks = collect ( data_get ( $yaml , 'networks' , []));
$topLevelConfigs = collect ( data_get ( $yaml , 'configs' , []));
$topLevelSecrets = collect ( data_get ( $yaml , 'secrets' , []));
$services = data_get ( $yaml , 'services' );
$generatedServiceFQDNS = collect ([]);
if ( is_null ( $resource -> destination )) {
$destination = $server -> destinations () -> first ();
if ( $destination ) {
$resource -> destination () -> associate ( $destination );
$resource -> save ();
}
}
$definedNetwork = collect ([ $resource -> uuid ]);
if ( $pull_request_id !== 0 ) {
$definedNetwork = collect ([ " { $resource -> uuid } - $pull_request_id " ]);
}
$services = collect ( $services ) -> map ( function ( $service , $serviceName ) use ( $topLevelVolumes , $topLevelNetworks , $definedNetwork , $isNew , $generatedServiceFQDNS , $resource , $server , $pull_request_id , $preview_id ) {
$serviceVolumes = collect ( data_get ( $service , 'volumes' , []));
$servicePorts = collect ( data_get ( $service , 'ports' , []));
$serviceNetworks = collect ( data_get ( $service , 'networks' , []));
$serviceVariables = collect ( data_get ( $service , 'environment' , []));
$serviceDependencies = collect ( data_get ( $service , 'depends_on' , []));
$serviceLabels = collect ( data_get ( $service , 'labels' , []));
$serviceBuildVariables = collect ( data_get ( $service , 'build.args' , []));
$serviceVariables = $serviceVariables -> merge ( $serviceBuildVariables );
if ( $serviceLabels -> count () > 0 ) {
$removedLabels = collect ([]);
$serviceLabels = $serviceLabels -> filter ( function ( $serviceLabel , $serviceLabelName ) use ( $removedLabels ) {
2024-12-09 14:38:21 +00:00
if ( ! str ( $serviceLabel ) -> contains ( '=' )) {
2024-08-23 18:54:38 +00:00
$removedLabels -> put ( $serviceLabelName , $serviceLabel );
return false ;
}
return $serviceLabel ;
});
foreach ( $removedLabels as $removedLabelName => $removedLabel ) {
$serviceLabels -> push ( " $removedLabelName = $removedLabel " );
}
}
$baseName = generateApplicationContainerName ( $resource , $pull_request_id );
$containerName = " $serviceName - $baseName " ;
if ( $resource -> compose_parsing_version === '1' ) {
if ( count ( $serviceVolumes ) > 0 ) {
$serviceVolumes = $serviceVolumes -> map ( function ( $volume ) use ( $resource , $topLevelVolumes , $pull_request_id ) {
if ( is_string ( $volume )) {
$volume = str ( $volume );
2024-12-09 14:38:21 +00:00
if ( $volume -> contains ( ':' ) && ! $volume -> startsWith ( '/' )) {
2024-08-23 18:54:38 +00:00
$name = $volume -> before ( ':' );
$mount = $volume -> after ( ':' );
if ( $name -> startsWith ( '.' ) || $name -> startsWith ( '~' )) {
2024-12-09 14:38:21 +00:00
$dir = base_configuration_dir () . '/applications/' . $resource -> uuid ;
2024-08-23 18:54:38 +00:00
if ( $name -> startsWith ( '.' )) {
$name = $name -> replaceFirst ( '.' , $dir );
}
if ( $name -> startsWith ( '~' )) {
$name = $name -> replaceFirst ( '~' , $dir );
}
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$name = $name . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
}
$volume = str ( " $name : $mount " );
} else {
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$name = $name . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
$volume = str ( " $name : $mount " );
if ( $topLevelVolumes -> has ( $name )) {
$v = $topLevelVolumes -> get ( $name );
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
// Do nothing
} else {
if ( is_null ( data_get ( $v , 'name' ))) {
data_set ( $v , 'name' , $name );
data_set ( $topLevelVolumes , $name , $v );
}
}
} else {
$topLevelVolumes -> put ( $name , [
'name' => $name ,
]);
}
} else {
if ( $topLevelVolumes -> has ( $name -> value ())) {
$v = $topLevelVolumes -> get ( $name -> value ());
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
// Do nothing
} else {
if ( is_null ( data_get ( $v , 'name' ))) {
data_set ( $topLevelVolumes , $name -> value (), $v );
}
}
} else {
$topLevelVolumes -> put ( $name -> value (), [
'name' => $name -> value (),
]);
}
}
}
} else {
if ( $volume -> startsWith ( '/' )) {
$name = $volume -> before ( ':' );
$mount = $volume -> after ( ':' );
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$name = $name . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
}
$volume = str ( " $name : $mount " );
}
}
} elseif ( is_array ( $volume )) {
$source = data_get ( $volume , 'source' );
$target = data_get ( $volume , 'target' );
$read_only = data_get ( $volume , 'read_only' );
if ( $source && $target ) {
if (( str ( $source ) -> startsWith ( '.' ) || str ( $source ) -> startsWith ( '~' ))) {
2024-12-09 14:38:21 +00:00
$dir = base_configuration_dir () . '/applications/' . $resource -> uuid ;
2024-08-23 18:54:38 +00:00
if ( str ( $source , '.' )) {
$source = str ( $source ) -> replaceFirst ( '.' , $dir );
}
if ( str ( $source , '~' )) {
$source = str ( $source ) -> replaceFirst ( '~' , $dir );
}
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$source = $source . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
}
if ( $read_only ) {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target . ':ro' );
2024-08-23 18:54:38 +00:00
} else {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target );
2024-08-23 18:54:38 +00:00
}
} else {
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$source = $source . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
}
if ( $read_only ) {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target . ':ro' );
2024-08-23 18:54:38 +00:00
} else {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target );
2024-08-23 18:54:38 +00:00
}
2024-12-09 14:38:21 +00:00
if ( ! str ( $source ) -> startsWith ( '/' )) {
2024-08-23 18:54:38 +00:00
if ( $topLevelVolumes -> has ( $source )) {
$v = $topLevelVolumes -> get ( $source );
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
// Do nothing
} else {
if ( is_null ( data_get ( $v , 'name' ))) {
data_set ( $v , 'name' , $source );
data_set ( $topLevelVolumes , $source , $v );
}
}
} else {
$topLevelVolumes -> put ( $source , [
'name' => $source ,
]);
}
}
}
}
}
if ( is_array ( $volume )) {
return data_get ( $volume , 'source' );
}
return $volume -> value ();
});
data_set ( $service , 'volumes' , $serviceVolumes -> toArray ());
}
} elseif ( $resource -> compose_parsing_version === '2' ) {
if ( count ( $serviceVolumes ) > 0 ) {
$serviceVolumes = $serviceVolumes -> map ( function ( $volume ) use ( $resource , $topLevelVolumes , $pull_request_id ) {
if ( is_string ( $volume )) {
$volume = str ( $volume );
2024-12-09 14:38:21 +00:00
if ( $volume -> contains ( ':' ) && ! $volume -> startsWith ( '/' )) {
2024-08-23 18:54:38 +00:00
$name = $volume -> before ( ':' );
$mount = $volume -> after ( ':' );
if ( $name -> startsWith ( '.' ) || $name -> startsWith ( '~' )) {
2024-12-09 14:38:21 +00:00
$dir = base_configuration_dir () . '/applications/' . $resource -> uuid ;
2024-08-23 18:54:38 +00:00
if ( $name -> startsWith ( '.' )) {
$name = $name -> replaceFirst ( '.' , $dir );
}
if ( $name -> startsWith ( '~' )) {
$name = $name -> replaceFirst ( '~' , $dir );
}
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$name = $name . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
}
$volume = str ( " $name : $mount " );
} else {
if ( $pull_request_id !== 0 ) {
$uuid = $resource -> uuid ;
2024-12-09 14:38:21 +00:00
$name = $uuid . " - $name -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
$volume = str ( " $name : $mount " );
if ( $topLevelVolumes -> has ( $name )) {
$v = $topLevelVolumes -> get ( $name );
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
// Do nothing
} else {
if ( is_null ( data_get ( $v , 'name' ))) {
data_set ( $v , 'name' , $name );
data_set ( $topLevelVolumes , $name , $v );
}
}
} else {
$topLevelVolumes -> put ( $name , [
'name' => $name ,
]);
}
} else {
$uuid = $resource -> uuid ;
2024-12-09 14:38:21 +00:00
$name = str ( $uuid . " - $name " );
2024-08-23 18:54:38 +00:00
$volume = str ( " $name : $mount " );
if ( $topLevelVolumes -> has ( $name -> value ())) {
$v = $topLevelVolumes -> get ( $name -> value ());
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
// Do nothing
} else {
if ( is_null ( data_get ( $v , 'name' ))) {
data_set ( $topLevelVolumes , $name -> value (), $v );
}
}
} else {
$topLevelVolumes -> put ( $name -> value (), [
'name' => $name -> value (),
]);
}
}
}
} else {
if ( $volume -> startsWith ( '/' )) {
$name = $volume -> before ( ':' );
$mount = $volume -> after ( ':' );
if ( $pull_request_id !== 0 ) {
2024-12-09 14:38:21 +00:00
$name = $name . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
}
$volume = str ( " $name : $mount " );
}
}
} elseif ( is_array ( $volume )) {
$source = data_get ( $volume , 'source' );
$target = data_get ( $volume , 'target' );
$read_only = data_get ( $volume , 'read_only' );
if ( $source && $target ) {
$uuid = $resource -> uuid ;
if (( str ( $source ) -> startsWith ( '.' ) || str ( $source ) -> startsWith ( '~' ) || str ( $source ) -> startsWith ( '/' ))) {
2024-12-09 14:38:21 +00:00
$dir = base_configuration_dir () . '/applications/' . $resource -> uuid ;
2024-08-23 18:54:38 +00:00
if ( str ( $source , '.' )) {
$source = str ( $source ) -> replaceFirst ( '.' , $dir );
}
if ( str ( $source , '~' )) {
$source = str ( $source ) -> replaceFirst ( '~' , $dir );
}
if ( $read_only ) {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target . ':ro' );
2024-08-23 18:54:38 +00:00
} else {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target );
2024-08-23 18:54:38 +00:00
}
} else {
if ( $pull_request_id === 0 ) {
2024-12-09 14:38:21 +00:00
$source = $uuid . " - $source " ;
2024-08-23 18:54:38 +00:00
} else {
2024-12-09 14:38:21 +00:00
$source = $uuid . " - $source -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
}
if ( $read_only ) {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target . ':ro' );
2024-08-23 18:54:38 +00:00
} else {
2024-12-09 14:38:21 +00:00
data_set ( $volume , 'source' , $source . ':' . $target );
2024-08-23 18:54:38 +00:00
}
2024-12-09 14:38:21 +00:00
if ( ! str ( $source ) -> startsWith ( '/' )) {
2024-08-23 18:54:38 +00:00
if ( $topLevelVolumes -> has ( $source )) {
$v = $topLevelVolumes -> get ( $source );
if ( data_get ( $v , 'driver_opts.type' ) === 'cifs' ) {
// Do nothing
} else {
if ( is_null ( data_get ( $v , 'name' ))) {
data_set ( $v , 'name' , $source );
data_set ( $topLevelVolumes , $source , $v );
}
}
} else {
$topLevelVolumes -> put ( $source , [
'name' => $source ,
]);
}
}
}
}
}
if ( is_array ( $volume )) {
return data_get ( $volume , 'source' );
}
dispatch ( new ServerFilesFromServerJob ( $resource ));
return $volume -> value ();
});
data_set ( $service , 'volumes' , $serviceVolumes -> toArray ());
}
}
if ( $pull_request_id !== 0 && count ( $serviceDependencies ) > 0 ) {
$serviceDependencies = $serviceDependencies -> map ( function ( $dependency ) use ( $pull_request_id ) {
2024-12-09 14:38:21 +00:00
return $dependency . " -pr- $pull_request_id " ;
2024-08-23 18:54:38 +00:00
});
data_set ( $service , 'depends_on' , $serviceDependencies -> toArray ());
}
// Decide if the service is a database
$isDatabase = isDatabaseImage ( data_get_str ( $service , 'image' ));
data_set ( $service , 'is_database' , $isDatabase );
// Collect/create/update networks
if ( $serviceNetworks -> count () > 0 ) {
foreach ( $serviceNetworks as $networkName => $networkDetails ) {
if ( $networkName === 'default' ) {
continue ;
}
// ignore alias
if ( $networkDetails [ 'aliases' ] ? ? false ) {
continue ;
}
$networkExists = $topLevelNetworks -> contains ( function ( $value , $key ) use ( $networkName ) {
return $value == $networkName || $key == $networkName ;
});
2024-12-09 14:38:21 +00:00
if ( ! $networkExists ) {
2024-10-03 13:04:40 +00:00
if ( is_string ( $networkDetails ) || is_int ( $networkDetails )) {
$topLevelNetworks -> put ( $networkDetails , null );
}
2024-08-23 18:54:38 +00:00
}
}
}
// Collect/create/update ports
$collectedPorts = collect ([]);
if ( $servicePorts -> count () > 0 ) {
foreach ( $servicePorts as $sport ) {
if ( is_string ( $sport ) || is_numeric ( $sport )) {
$collectedPorts -> push ( $sport );
}
if ( is_array ( $sport )) {
$target = data_get ( $sport , 'target' );
$published = data_get ( $sport , 'published' );
$protocol = data_get ( $sport , 'protocol' );
$collectedPorts -> push ( " $target : $published / $protocol " );
}
}
}
$definedNetworkExists = $topLevelNetworks -> contains ( function ( $value , $_ ) use ( $definedNetwork ) {
return $value == $definedNetwork ;
});
2024-12-09 14:38:21 +00:00
if ( ! $definedNetworkExists ) {
2024-08-23 18:54:38 +00:00
foreach ( $definedNetwork as $network ) {
if ( $pull_request_id !== 0 ) {
$topLevelNetworks -> put ( $network , [
'name' => $network ,
'external' => true ,
]);
} else {
$topLevelNetworks -> put ( $network , [
'name' => $network ,
'external' => true ,
]);
}
}
}
$networks = collect ();
foreach ( $serviceNetworks as $key => $serviceNetwork ) {
if ( gettype ( $serviceNetwork ) === 'string' ) {
// networks:
// - appwrite
$networks -> put ( $serviceNetwork , null );
} elseif ( gettype ( $serviceNetwork ) === 'array' ) {
// networks:
// default:
// ipv4_address: 192.168.203.254
// $networks->put($serviceNetwork, null);
$networks -> put ( $key , $serviceNetwork );
}
}
foreach ( $definedNetwork as $key => $network ) {
$networks -> put ( $network , null );
}
if ( data_get ( $resource , 'settings.connect_to_docker_network' )) {
$network = $resource -> destination -> network ;
$networks -> put ( $network , null );
$topLevelNetworks -> put ( $network , [
'name' => $network ,
'external' => true ,
]);
}
data_set ( $service , 'networks' , $networks -> toArray ());
// Get variables from the service
foreach ( $serviceVariables as $variableName => $variable ) {
if ( is_numeric ( $variableName )) {
if ( is_array ( $variable )) {
// - SESSION_SECRET: 123
// - SESSION_SECRET:
$key = str ( collect ( $variable ) -> keys () -> first ());
$value = str ( collect ( $variable ) -> values () -> first ());
} else {
$variable = str ( $variable );
if ( $variable -> contains ( '=' )) {
// - SESSION_SECRET=123
// - SESSION_SECRET=
$key = $variable -> before ( '=' );
$value = $variable -> after ( '=' );
} else {
// - SESSION_SECRET
$key = $variable ;
$value = null ;
}
}
} else {
// SESSION_SECRET: 123
// SESSION_SECRET:
$key = str ( $variableName );
$value = str ( $variable );
}
if ( $key -> startsWith ( 'SERVICE_FQDN' )) {
if ( $isNew ) {
$name = $key -> after ( 'SERVICE_FQDN_' ) -> beforeLast ( '_' ) -> lower ();
$fqdn = generateFqdn ( $server , " { $name -> value () } - { $resource -> uuid } " );
if ( substr_count ( $key -> value (), '_' ) === 3 ) {
// SERVICE_FQDN_UMAMI_1000
$port = $key -> afterLast ( '_' );
} else {
// SERVICE_FQDN_UMAMI
$port = null ;
}
if ( $port ) {
$fqdn = " $fqdn : $port " ;
}
if ( substr_count ( $key -> value (), '_' ) >= 2 ) {
if ( $value ) {
$path = $value -> value ();
} else {
$path = null ;
}
if ( $generatedServiceFQDNS -> count () > 0 ) {
$alreadyGenerated = $generatedServiceFQDNS -> has ( $key -> value ());
if ( $alreadyGenerated ) {
$fqdn = $generatedServiceFQDNS -> get ( $key -> value ());
} else {
$generatedServiceFQDNS -> put ( $key -> value (), $fqdn );
}
} else {
$generatedServiceFQDNS -> put ( $key -> value (), $fqdn );
}
$fqdn = " $fqdn $path " ;
}
}
continue ;
}
if ( $value ? -> startsWith ( '$' )) {
$foundEnv = EnvironmentVariable :: where ([
'key' => $key ,
2025-01-22 09:21:41 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]) -> first ();
2024-09-09 13:04:51 +00:00
$value = replaceVariables ( $value );
2024-08-23 18:54:38 +00:00
$key = $value ;
if ( $value -> startsWith ( 'SERVICE_' )) {
$foundEnv = EnvironmentVariable :: where ([
'key' => $key ,
2025-01-22 09:21:41 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
]) -> first ();
[ 'command' => $command , 'forService' => $forService , 'generatedValue' => $generatedValue , 'port' => $port ] = parseEnvVariable ( $value );
2024-12-09 14:38:21 +00:00
if ( ! is_null ( $command )) {
2024-08-23 18:54:38 +00:00
if ( $command ? -> value () === 'FQDN' || $command ? -> value () === 'URL' ) {
if ( Str :: lower ( $forService ) === $serviceName ) {
$fqdn = generateFqdn ( $server , $containerName );
} else {
2024-12-09 14:38:21 +00:00
$fqdn = generateFqdn ( $server , Str :: lower ( $forService ) . '-' . $resource -> uuid );
2024-08-23 18:54:38 +00:00
}
if ( $port ) {
$fqdn = " $fqdn : $port " ;
}
if ( $foundEnv ) {
$fqdn = data_get ( $foundEnv , 'value' );
} else {
if ( $command ? -> value () === 'URL' ) {
$fqdn = str ( $fqdn ) -> after ( '://' ) -> value ();
}
EnvironmentVariable :: create ([
'key' => $key ,
'value' => $fqdn ,
'is_build_time' => false ,
2025-01-22 09:21:41 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]);
}
} else {
$generatedValue = generateEnvValue ( $command );
2024-12-09 14:38:21 +00:00
if ( ! $foundEnv ) {
2024-08-23 18:54:38 +00:00
EnvironmentVariable :: create ([
'key' => $key ,
'value' => $generatedValue ,
'is_build_time' => false ,
2025-01-22 09:21:41 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]);
}
}
}
} else {
if ( $value -> contains ( ':-' )) {
$key = $value -> before ( ':' );
$defaultValue = $value -> after ( ':-' );
} elseif ( $value -> contains ( '-' )) {
$key = $value -> before ( '-' );
$defaultValue = $value -> after ( '-' );
} elseif ( $value -> contains ( ':?' )) {
$key = $value -> before ( ':' );
$defaultValue = $value -> after ( ':?' );
} elseif ( $value -> contains ( '?' )) {
$key = $value -> before ( '?' );
$defaultValue = $value -> after ( '?' );
} else {
$key = $value ;
$defaultValue = null ;
}
$foundEnv = EnvironmentVariable :: where ([
'key' => $key ,
2025-01-22 09:21:41 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]) -> first ();
if ( $foundEnv ) {
$defaultValue = data_get ( $foundEnv , 'value' );
}
$isBuildTime = data_get ( $foundEnv , 'is_build_time' , false );
if ( $foundEnv ) {
$foundEnv -> update ([
'key' => $key ,
2025-01-22 09:21:41 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_build_time' => $isBuildTime ,
'value' => $defaultValue ,
]);
} else {
EnvironmentVariable :: create ([
'key' => $key ,
'value' => $defaultValue ,
'is_build_time' => $isBuildTime ,
2025-01-22 09:21:41 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-23 18:54:38 +00:00
'is_preview' => false ,
]);
}
}
}
}
// Add labels to the service
if ( $resource -> serviceType ()) {
$fqdns = generateServiceSpecificFqdns ( $resource );
} else {
$domains = collect ( json_decode ( $resource -> docker_compose_domains )) ? ? [];
if ( $domains ) {
$fqdns = data_get ( $domains , " $serviceName .domain " );
if ( $fqdns ) {
$fqdns = str ( $fqdns ) -> explode ( ',' );
if ( $pull_request_id !== 0 ) {
$preview = $resource -> previews () -> find ( $preview_id );
$docker_compose_domains = collect ( json_decode ( data_get ( $preview , 'docker_compose_domains' )));
if ( $docker_compose_domains -> count () > 0 ) {
$found_fqdn = data_get ( $docker_compose_domains , " $serviceName .domain " );
if ( $found_fqdn ) {
$fqdns = collect ( $found_fqdn );
} else {
$fqdns = collect ([]);
}
} else {
$fqdns = $fqdns -> map ( function ( $fqdn ) use ( $pull_request_id , $resource ) {
$preview = ApplicationPreview :: findPreviewByApplicationAndPullId ( $resource -> id , $pull_request_id );
$url = Url :: fromString ( $fqdn );
$template = $resource -> preview_url_template ;
$host = $url -> getHost ();
$schema = $url -> getScheme ();
$random = new Cuid2 ;
$preview_fqdn = str_replace ( '{{random}}' , $random , $template );
$preview_fqdn = str_replace ( '{{domain}}' , $host , $preview_fqdn );
$preview_fqdn = str_replace ( '{{pr_id}}' , $pull_request_id , $preview_fqdn );
$preview_fqdn = " $schema :// $preview_fqdn " ;
$preview -> fqdn = $preview_fqdn ;
$preview -> save ();
return $preview_fqdn ;
});
}
}
$shouldGenerateLabelsExactly = $server -> settings -> generate_exact_labels ;
if ( $shouldGenerateLabelsExactly ) {
switch ( $server -> proxyType ()) {
case ProxyTypes :: TRAEFIK -> value :
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge (
fqdnLabelsForTraefik (
uuid : $resource -> uuid ,
domains : $fqdns ,
serviceLabels : $serviceLabels ,
generate_unique_uuid : $resource -> build_pack === 'dockercompose' ,
image : data_get ( $service , 'image' ),
is_force_https_enabled : $resource -> isForceHttpsEnabled (),
is_gzip_enabled : $resource -> isGzipEnabled (),
is_stripprefix_enabled : $resource -> isStripprefixEnabled (),
)
2024-08-23 18:54:38 +00:00
);
break ;
case ProxyTypes :: CADDY -> value :
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge (
fqdnLabelsForCaddy (
network : $resource -> destination -> network ,
uuid : $resource -> uuid ,
domains : $fqdns ,
serviceLabels : $serviceLabels ,
image : data_get ( $service , 'image' ),
is_force_https_enabled : $resource -> isForceHttpsEnabled (),
is_gzip_enabled : $resource -> isGzipEnabled (),
is_stripprefix_enabled : $resource -> isStripprefixEnabled (),
)
2024-08-23 18:54:38 +00:00
);
break ;
}
} else {
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge (
fqdnLabelsForTraefik (
uuid : $resource -> uuid ,
domains : $fqdns ,
serviceLabels : $serviceLabels ,
generate_unique_uuid : $resource -> build_pack === 'dockercompose' ,
image : data_get ( $service , 'image' ),
is_force_https_enabled : $resource -> isForceHttpsEnabled (),
is_gzip_enabled : $resource -> isGzipEnabled (),
is_stripprefix_enabled : $resource -> isStripprefixEnabled (),
)
2024-08-23 18:54:38 +00:00
);
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge (
2024-08-23 18:54:38 +00:00
fqdnLabelsForCaddy (
network : $resource -> destination -> network ,
uuid : $resource -> uuid ,
domains : $fqdns ,
serviceLabels : $serviceLabels ,
image : data_get ( $service , 'image' ),
is_force_https_enabled : $resource -> isForceHttpsEnabled (),
is_gzip_enabled : $resource -> isGzipEnabled (),
is_stripprefix_enabled : $resource -> isStripprefixEnabled (),
2025-02-28 19:25:19 +00:00
)
);
2024-08-23 18:54:38 +00:00
}
}
}
}
2024-11-17 21:49:44 +00:00
$defaultLabels = defaultLabels (
id : $resource -> id ,
name : $containerName ,
projectName : $resource -> project () -> name ,
resourceName : $resource -> name ,
2024-12-02 17:38:21 +00:00
environment : $resource -> environment -> name ,
2024-11-17 21:49:44 +00:00
pull_request_id : $pull_request_id ,
type : 'application'
);
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge ( $defaultLabels );
2024-08-23 18:54:38 +00:00
2024-09-02 08:57:03 +00:00
if ( $server -> isLogDrainEnabled ()) {
if ( $resource instanceof Application && $resource -> isLogDrainEnabled ()) {
data_set ( $service , 'logging' , generate_fluentd_configuration ());
}
2024-08-23 18:54:38 +00:00
}
if ( $serviceLabels -> count () > 0 ) {
if ( $resource -> settings -> is_container_label_escape_enabled ) {
$serviceLabels = $serviceLabels -> map ( function ( $value , $key ) {
return escapeDollarSign ( $value );
});
}
}
data_set ( $service , 'labels' , $serviceLabels -> toArray ());
data_forget ( $service , 'is_database' );
2024-12-09 14:38:21 +00:00
if ( ! data_get ( $service , 'restart' )) {
2024-08-23 18:54:38 +00:00
data_set ( $service , 'restart' , RESTART_MODE );
}
data_set ( $service , 'container_name' , $containerName );
data_forget ( $service , 'volumes.*.content' );
data_forget ( $service , 'volumes.*.isDirectory' );
2024-12-17 09:38:32 +00:00
data_forget ( $service , 'volumes.*.is_directory' );
data_forget ( $service , 'exclude_from_hc' );
data_set ( $service , 'environment' , $serviceVariables -> toArray ());
2024-08-23 18:54:38 +00:00
return $service ;
});
if ( $pull_request_id !== 0 ) {
$services -> each ( function ( $service , $serviceName ) use ( $pull_request_id , $services ) {
2024-12-09 14:38:21 +00:00
$services [ $serviceName . " -pr- $pull_request_id " ] = $service ;
2024-08-23 18:54:38 +00:00
data_forget ( $services , $serviceName );
});
}
$finalServices = [
'services' => $services -> toArray (),
'volumes' => $topLevelVolumes -> toArray (),
'networks' => $topLevelNetworks -> toArray (),
'configs' => $topLevelConfigs -> toArray (),
'secrets' => $topLevelSecrets -> toArray (),
];
2024-08-26 08:51:01 +00:00
$resource -> docker_compose_raw = Yaml :: dump ( $yaml , 10 , 2 );
$resource -> docker_compose = Yaml :: dump ( $finalServices , 10 , 2 );
data_forget ( $resource , 'environment_variables' );
data_forget ( $resource , 'environment_variables_preview' );
2024-08-23 18:54:38 +00:00
$resource -> save ();
return collect ( $finalServices );
}
}
2024-09-07 18:56:26 +00:00
2024-08-28 13:45:11 +00:00
function newParser ( Application | Service $resource , int $pull_request_id = 0 , ? int $preview_id = null ) : Collection
2024-08-27 14:02:52 +00:00
{
$isApplication = $resource instanceof Application ;
$isService = $resource instanceof Service ;
$uuid = data_get ( $resource , 'uuid' );
$compose = data_get ( $resource , 'docker_compose_raw' );
2024-12-09 14:38:21 +00:00
if ( ! $compose ) {
2024-08-28 13:45:11 +00:00
return collect ([]);
}
2024-08-27 14:02:52 +00:00
if ( $isApplication ) {
$pullRequestId = $pull_request_id ;
$isPullRequest = $pullRequestId == 0 ? false : true ;
$server = data_get ( $resource , 'destination.server' );
$fileStorages = $resource -> fileStorages ();
} elseif ( $isService ) {
$server = data_get ( $resource , 'server' );
$allServices = get_service_templates ();
} else {
2024-08-28 13:45:11 +00:00
return collect ([]);
2024-08-27 14:02:52 +00:00
}
try {
$yaml = Yaml :: parse ( $compose );
2024-10-31 14:19:37 +00:00
} catch ( \Exception ) {
2024-08-28 13:45:11 +00:00
return collect ([]);
2024-08-27 14:02:52 +00:00
}
$services = data_get ( $yaml , 'services' , collect ([]));
$topLevel = collect ([
'volumes' => collect ( data_get ( $yaml , 'volumes' , [])),
'networks' => collect ( data_get ( $yaml , 'networks' , [])),
'configs' => collect ( data_get ( $yaml , 'configs' , [])),
'secrets' => collect ( data_get ( $yaml , 'secrets' , [])),
]);
// If there are predefined volumes, make sure they are not null
if ( $topLevel -> get ( 'volumes' ) -> count () > 0 ) {
$temp = collect ([]);
foreach ( $topLevel [ 'volumes' ] as $volumeName => $volume ) {
if ( is_null ( $volume )) {
continue ;
}
$temp -> put ( $volumeName , $volume );
}
$topLevel [ 'volumes' ] = $temp ;
}
// Get the base docker network
$baseNetwork = collect ([ $uuid ]);
if ( $isApplication && $isPullRequest ) {
$baseNetwork = collect ([ " { $uuid } - { $pullRequestId } " ]);
}
$parsedServices = collect ([]);
2024-09-07 18:56:26 +00:00
$allMagicEnvironments = collect ([]);
foreach ( $services as $serviceName => $service ) {
2024-09-23 08:46:34 +00:00
$predefinedPort = null ;
2024-09-07 18:56:26 +00:00
$magicEnvironments = collect ([]);
$image = data_get_str ( $service , 'image' );
$environment = collect ( data_get ( $service , 'environment' , []));
$buildArgs = collect ( data_get ( $service , 'build.args' , []));
$environment = $environment -> merge ( $buildArgs );
$isDatabase = isDatabaseImage ( data_get_str ( $service , 'image' ));
if ( $isService ) {
2024-09-23 08:46:34 +00:00
$containerName = " $serviceName - { $resource -> uuid } " ;
if ( $serviceName === 'registry' ) {
$tempServiceName = 'docker-registry' ;
} else {
$tempServiceName = $serviceName ;
}
if ( str ( data_get ( $service , 'image' )) -> contains ( 'glitchtip' )) {
$tempServiceName = 'glitchtip' ;
}
if ( $serviceName === 'supabase-kong' ) {
$tempServiceName = 'supabase' ;
}
$serviceDefinition = data_get ( $allServices , $tempServiceName );
$predefinedPort = data_get ( $serviceDefinition , 'port' );
if ( $serviceName === 'plausible' ) {
$predefinedPort = '8000' ;
}
2024-09-07 18:56:26 +00:00
if ( $isDatabase ) {
2025-04-09 23:06:01 +00:00
$applicationFound = ServiceApplication :: where ( 'name' , $serviceName ) -> where ( 'service_id' , $resource -> id ) -> first ();
2024-10-03 11:49:43 +00:00
if ( $applicationFound ) {
$savedService = $applicationFound ;
2025-04-29 12:27:17 +00:00
// $savedService = ServiceDatabase::firstOrCreate([
// 'name' => $applicationFound->name,
// 'image' => $applicationFound->image,
// 'service_id' => $applicationFound->service_id,
// ]);
// $applicationFound->delete();
2024-10-03 11:49:43 +00:00
} else {
$savedService = ServiceDatabase :: firstOrCreate ([
'name' => $serviceName ,
'service_id' => $resource -> id ,
]);
}
2024-09-07 18:56:26 +00:00
} else {
$savedService = ServiceApplication :: firstOrCreate ([
'name' => $serviceName ,
'service_id' => $resource -> id ,
]);
}
2025-04-09 23:06:01 +00:00
// Check if image changed
if ( $savedService -> image !== $image ) {
$savedService -> image = $image ;
$savedService -> save ();
}
2025-04-16 13:26:40 +00:00
}
$environment = collect ( data_get ( $service , 'environment' , []));
$buildArgs = collect ( data_get ( $service , 'build.args' , []));
$environment = $environment -> merge ( $buildArgs );
2025-04-09 23:06:01 +00:00
2025-04-16 13:26:40 +00:00
// convert environment variables to one format
$environment = convertToKeyValueCollection ( $environment );
2024-09-07 18:56:26 +00:00
2025-04-16 13:26:40 +00:00
// Add Coolify defined environments
$allEnvironments = $resource -> environment_variables () -> get ([ 'key' , 'value' ]);
2024-09-07 18:56:26 +00:00
2025-04-16 13:26:40 +00:00
$allEnvironments = $allEnvironments -> mapWithKeys ( function ( $item ) {
return [ $item [ 'key' ] => $item [ 'value' ]];
});
// filter and add magic environments
foreach ( $environment as $key => $value ) {
// Get all SERVICE_ variables from keys and values
$key = str ( $key );
$value = str ( $value );
$regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/' ;
preg_match_all ( $regex , $value , $valueMatches );
if ( count ( $valueMatches [ 1 ]) > 0 ) {
foreach ( $valueMatches [ 1 ] as $match ) {
$match = replaceVariables ( $match );
if ( $match -> startsWith ( 'SERVICE_' )) {
if ( $magicEnvironments -> has ( $match -> value ())) {
continue ;
2024-09-07 18:56:26 +00:00
}
2025-04-16 13:26:40 +00:00
$magicEnvironments -> put ( $match -> value (), '' );
2024-09-07 18:56:26 +00:00
}
}
2025-04-16 13:26:40 +00:00
}
2024-09-09 13:04:51 +00:00
2025-04-16 13:26:40 +00:00
// Get magic environments where we need to preset the FQDN
if ( $key -> startsWith ( 'SERVICE_FQDN_' )) {
// SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000
if ( substr_count ( str ( $key ) -> value (), '_' ) === 3 ) {
$fqdnFor = $key -> after ( 'SERVICE_FQDN_' ) -> beforeLast ( '_' ) -> lower () -> value ();
$port = $key -> afterLast ( '_' ) -> value ();
} else {
$fqdnFor = $key -> after ( 'SERVICE_FQDN_' ) -> lower () -> value ();
$port = null ;
}
if ( $isApplication ) {
$fqdn = generateFqdn ( $server , " $uuid " );
} elseif ( $isService ) {
if ( $fqdnFor ) {
$fqdn = generateFqdn ( $server , " $fqdnFor - $uuid " );
2024-09-18 07:21:57 +00:00
} else {
2025-04-16 13:26:40 +00:00
$fqdn = generateFqdn ( $server , " { $savedService -> name } - $uuid " );
2024-09-07 18:56:26 +00:00
}
2025-04-16 13:26:40 +00:00
}
2024-09-23 08:46:34 +00:00
2025-04-16 13:26:40 +00:00
if ( $value && get_class ( $value ) === \Illuminate\Support\Stringable :: class && $value -> startsWith ( '/' )) {
$path = $value -> value ();
if ( $path !== '/' ) {
$fqdn = " $fqdn $path " ;
2024-09-09 13:04:51 +00:00
}
2025-04-16 13:26:40 +00:00
}
$fqdnWithPort = $fqdn ;
if ( $port ) {
$fqdnWithPort = " $fqdn : $port " ;
}
if ( $isApplication && is_null ( $resource -> fqdn )) {
data_forget ( $resource , 'environment_variables' );
data_forget ( $resource , 'environment_variables_preview' );
$resource -> fqdn = $fqdnWithPort ;
$resource -> save ();
} elseif ( $isService && is_null ( $savedService -> fqdn )) {
$savedService -> fqdn = $fqdnWithPort ;
$savedService -> save ();
}
2024-09-09 13:04:51 +00:00
2025-04-16 13:26:40 +00:00
if ( substr_count ( str ( $key ) -> value (), '_' ) === 2 ) {
$resource -> environment_variables () -> firstOrCreate ([
'key' => $key -> value (),
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
], [
'value' => $fqdn ,
'is_build_time' => false ,
'is_preview' => false ,
]);
}
if ( substr_count ( str ( $key ) -> value (), '_' ) === 3 ) {
$newKey = str ( $key ) -> beforeLast ( '_' );
$resource -> environment_variables () -> firstOrCreate ([
'key' => $newKey -> value (),
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
], [
'value' => $fqdn ,
'is_build_time' => false ,
'is_preview' => false ,
]);
2024-09-07 18:56:26 +00:00
}
}
2025-04-16 13:26:40 +00:00
}
2024-09-09 13:04:51 +00:00
2025-04-16 13:26:40 +00:00
$allMagicEnvironments = $allMagicEnvironments -> merge ( $magicEnvironments );
if ( $magicEnvironments -> count () > 0 ) {
foreach ( $magicEnvironments as $key => $value ) {
$key = str ( $key );
$value = replaceVariables ( $value );
$command = parseCommandFromMagicEnvVariable ( $key );
$found = $resource -> environment_variables () -> where ( 'key' , $key -> value ()) -> where ( 'resourceable_type' , get_class ( $resource )) -> where ( 'resourceable_id' , $resource -> id ) -> first ();
if ( $found ) {
continue ;
}
if ( $command -> value () === 'FQDN' ) {
$fqdnFor = $key -> after ( 'SERVICE_FQDN_' ) -> lower () -> value ();
if ( str ( $fqdnFor ) -> contains ( '_' )) {
$fqdnFor = str ( $fqdnFor ) -> before ( '_' );
2024-09-09 13:04:51 +00:00
}
2025-04-16 13:26:40 +00:00
$fqdn = generateFqdn ( $server , " $fqdnFor - $uuid " );
$resource -> environment_variables () -> firstOrCreate ([
'key' => $key -> value (),
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
], [
'value' => $fqdn ,
'is_build_time' => false ,
'is_preview' => false ,
]);
} elseif ( $command -> value () === 'URL' ) {
$fqdnFor = $key -> after ( 'SERVICE_URL_' ) -> lower () -> value ();
if ( str ( $fqdnFor ) -> contains ( '_' )) {
$fqdnFor = str ( $fqdnFor ) -> before ( '_' );
2024-09-07 18:56:26 +00:00
}
2025-04-16 13:26:40 +00:00
$fqdn = generateFqdn ( $server , " $fqdnFor - $uuid " );
$fqdn = str ( $fqdn ) -> replace ( 'http://' , '' ) -> replace ( 'https://' , '' );
$resource -> environment_variables () -> firstOrCreate ([
'key' => $key -> value (),
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
], [
'value' => $fqdn ,
'is_build_time' => false ,
'is_preview' => false ,
]);
} else {
$value = generateEnvValue ( $command , $resource );
$resource -> environment_variables () -> firstOrCreate ([
'key' => $key -> value (),
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
], [
'value' => $value ,
'is_build_time' => false ,
'is_preview' => false ,
]);
2024-09-07 18:56:26 +00:00
}
}
}
}
2025-03-29 23:08:43 +00:00
$serviceAppsLogDrainEnabledMap = collect ([]);
if ( $resource instanceof Service ) {
$serviceAppsLogDrainEnabledMap = $resource -> applications () -> get () -> keyBy ( 'name' ) -> map ( function ( $app ) {
return $app -> isLogDrainEnabled ();
});
}
2024-09-07 18:56:26 +00:00
// Parse the rest of the services
2024-08-27 14:02:52 +00:00
foreach ( $services as $serviceName => $service ) {
$image = data_get_str ( $service , 'image' );
$restart = data_get_str ( $service , 'restart' , RESTART_MODE );
$logging = data_get ( $service , 'logging' );
2024-09-02 08:57:03 +00:00
if ( $server -> isLogDrainEnabled ()) {
if ( $resource instanceof Application && $resource -> isLogDrainEnabled ()) {
$logging = generate_fluentd_configuration ();
}
2025-03-29 23:08:43 +00:00
if ( $resource instanceof Service && $serviceAppsLogDrainEnabledMap -> get ( $serviceName )) {
$logging = generate_fluentd_configuration ();
}
2024-08-27 14:02:52 +00:00
}
$volumes = collect ( data_get ( $service , 'volumes' , []));
$networks = collect ( data_get ( $service , 'networks' , []));
2024-09-09 21:30:47 +00:00
$use_network_mode = data_get ( $service , 'network_mode' ) !== null ;
2024-08-27 14:02:52 +00:00
$depends_on = collect ( data_get ( $service , 'depends_on' , []));
$labels = collect ( data_get ( $service , 'labels' , []));
2025-04-15 16:41:21 +00:00
if ( $labels -> count () > 0 ) {
if ( isAssociativeArray ( $labels )) {
$newLabels = collect ([]);
$labels -> each ( function ( $value , $key ) use ( $newLabels ) {
$newLabels -> push ( " $key = $value " );
});
$labels = $newLabels ;
}
}
2024-08-27 14:02:52 +00:00
$environment = collect ( data_get ( $service , 'environment' , []));
2024-08-27 19:48:25 +00:00
$ports = collect ( data_get ( $service , 'ports' , []));
2024-08-27 14:02:52 +00:00
$buildArgs = collect ( data_get ( $service , 'build.args' , []));
$environment = $environment -> merge ( $buildArgs );
2024-09-07 18:56:26 +00:00
2025-02-27 10:29:04 +00:00
$environment = convertToKeyValueCollection ( $environment );
2024-09-07 18:56:26 +00:00
$coolifyEnvironments = collect ([]);
2024-08-27 14:02:52 +00:00
$isDatabase = isDatabaseImage ( data_get_str ( $service , 'image' ));
$volumesParsed = collect ([]);
if ( $isApplication ) {
$baseName = generateApplicationContainerName (
application : $resource ,
pull_request_id : $pullRequestId
);
$containerName = " $serviceName - $baseName " ;
2024-08-28 13:45:11 +00:00
$predefinedPort = null ;
2024-08-27 14:02:52 +00:00
} elseif ( $isService ) {
$containerName = " $serviceName - { $resource -> uuid } " ;
if ( $serviceName === 'registry' ) {
$tempServiceName = 'docker-registry' ;
} else {
$tempServiceName = $serviceName ;
}
if ( str ( data_get ( $service , 'image' )) -> contains ( 'glitchtip' )) {
$tempServiceName = 'glitchtip' ;
}
if ( $serviceName === 'supabase-kong' ) {
$tempServiceName = 'supabase' ;
}
$serviceDefinition = data_get ( $allServices , $tempServiceName );
$predefinedPort = data_get ( $serviceDefinition , 'port' );
if ( $serviceName === 'plausible' ) {
$predefinedPort = '8000' ;
}
2024-10-03 11:49:43 +00:00
2024-08-27 14:02:52 +00:00
if ( $isDatabase ) {
2024-10-03 11:49:43 +00:00
$applicationFound = ServiceApplication :: where ( 'name' , $serviceName ) -> where ( 'image' , $image ) -> where ( 'service_id' , $resource -> id ) -> first ();
if ( $applicationFound ) {
$savedService = $applicationFound ;
2025-04-29 12:27:17 +00:00
// $savedService = ServiceDatabase::firstOrCreate([
// 'name' => $applicationFound->name,
// 'image' => $applicationFound->image,
// 'service_id' => $applicationFound->service_id,
// ]);
// $applicationFound->delete();
2024-10-03 11:49:43 +00:00
} else {
$savedService = ServiceDatabase :: firstOrCreate ([
'name' => $serviceName ,
'image' => $image ,
'service_id' => $resource -> id ,
]);
}
2024-08-27 14:02:52 +00:00
} else {
$savedService = ServiceApplication :: firstOrCreate ([
'name' => $serviceName ,
'image' => $image ,
'service_id' => $resource -> id ,
]);
}
$fileStorages = $savedService -> fileStorages ();
if ( $savedService -> image !== $image ) {
$savedService -> image = $image ;
$savedService -> save ();
}
}
2024-08-27 19:48:25 +00:00
$originalResource = $isApplication ? $resource : $savedService ;
2024-08-27 14:02:52 +00:00
if ( $volumes -> count () > 0 ) {
foreach ( $volumes as $index => $volume ) {
$type = null ;
$source = null ;
$target = null ;
$content = null ;
$isDirectory = false ;
if ( is_string ( $volume )) {
$source = str ( $volume ) -> before ( ':' );
$target = str ( $volume ) -> after ( ':' ) -> beforeLast ( ':' );
$foundConfig = $fileStorages -> whereMountPath ( $target ) -> first ();
if ( sourceIsLocal ( $source )) {
$type = str ( 'bind' );
if ( $foundConfig ) {
$contentNotNull_temp = data_get ( $foundConfig , 'content' );
if ( $contentNotNull_temp ) {
$content = $contentNotNull_temp ;
}
$isDirectory = data_get ( $foundConfig , 'is_directory' );
} else {
// By default, we cannot determine if the bind is a directory or not, so we set it to directory
$isDirectory = true ;
}
} else {
$type = str ( 'volume' );
}
} elseif ( is_array ( $volume )) {
$type = data_get_str ( $volume , 'type' );
$source = data_get_str ( $volume , 'source' );
$target = data_get_str ( $volume , 'target' );
$content = data_get ( $volume , 'content' );
$isDirectory = ( bool ) data_get ( $volume , 'isDirectory' , null ) || ( bool ) data_get ( $volume , 'is_directory' , null );
$foundConfig = $fileStorages -> whereMountPath ( $target ) -> first ();
if ( $foundConfig ) {
$contentNotNull_temp = data_get ( $foundConfig , 'content' );
if ( $contentNotNull_temp ) {
$content = $contentNotNull_temp ;
}
$isDirectory = data_get ( $foundConfig , 'is_directory' );
} else {
// if isDirectory is not set (or false) & content is also not set, we assume it is a directory
2024-12-09 14:38:21 +00:00
if (( is_null ( $isDirectory ) || ! $isDirectory ) && is_null ( $content )) {
2024-08-27 14:02:52 +00:00
$isDirectory = true ;
}
}
}
if ( $type -> value () === 'bind' ) {
if ( $source -> value () === '/var/run/docker.sock' ) {
2024-12-09 14:38:21 +00:00
$volume = $source -> value () . ':' . $target -> value ();
2024-08-28 13:45:11 +00:00
} elseif ( $source -> value () === '/tmp' || $source -> value () === '/tmp/' ) {
2024-12-09 14:38:21 +00:00
$volume = $source -> value () . ':' . $target -> value ();
2024-08-28 13:45:11 +00:00
} else {
2024-09-30 12:15:22 +00:00
if (( int ) $resource -> compose_parsing_version >= 4 ) {
if ( $isApplication ) {
2024-12-09 14:38:21 +00:00
$mainDirectory = str ( base_configuration_dir () . '/applications/' . $uuid );
2024-09-30 12:15:22 +00:00
} elseif ( $isService ) {
2024-12-09 14:38:21 +00:00
$mainDirectory = str ( base_configuration_dir () . '/services/' . $uuid );
2024-09-30 12:15:22 +00:00
}
} else {
2024-12-09 14:38:21 +00:00
$mainDirectory = str ( base_configuration_dir () . '/applications/' . $uuid );
2024-09-30 12:15:22 +00:00
}
2024-08-28 13:45:11 +00:00
$source = replaceLocalSource ( $source , $mainDirectory );
2024-08-28 20:05:49 +00:00
if ( $isApplication && $isPullRequest ) {
2024-12-09 14:38:21 +00:00
$source = $source . " -pr- $pullRequestId " ;
2024-08-28 20:05:49 +00:00
}
2025-03-29 21:16:12 +00:00
LocalFileVolume :: updateOrCreate (
[
'mount_path' => $target ,
'resource_id' => $originalResource -> id ,
'resource_type' => get_class ( $originalResource ),
],
[
'fs_path' => $source ,
'mount_path' => $target ,
'content' => $content ,
'is_directory' => $isDirectory ,
'resource_id' => $originalResource -> id ,
'resource_type' => get_class ( $originalResource ),
]
);
2025-05-03 07:59:42 +00:00
// if (isDev()) {
// if ((int) $resource->compose_parsing_version >= 4) {
// if ($isApplication) {
// $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid);
// } elseif ($isService) {
// $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/services/'.$uuid);
// }
// } else {
// $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid);
// }
// }
2024-08-28 13:45:11 +00:00
$volume = " $source : $target " ;
2024-08-27 14:02:52 +00:00
}
} elseif ( $type -> value () === 'volume' ) {
if ( $topLevel -> get ( 'volumes' ) -> has ( $source -> value ())) {
$temp = $topLevel -> get ( 'volumes' ) -> get ( $source -> value ());
if ( data_get ( $temp , 'driver_opts.type' ) === 'cifs' ) {
2024-09-08 11:53:20 +00:00
continue ;
2024-08-27 14:02:52 +00:00
}
if ( data_get ( $temp , 'driver_opts.type' ) === 'nfs' ) {
2024-09-08 11:53:20 +00:00
continue ;
2024-08-27 14:02:52 +00:00
}
}
$slugWithoutUuid = Str :: slug ( $source , '-' );
$name = " { $uuid } _ { $slugWithoutUuid } " ;
2024-08-28 20:05:49 +00:00
if ( $isApplication && $isPullRequest ) {
$name = " { $name } -pr- $pullRequestId " ;
}
2024-08-27 14:02:52 +00:00
if ( is_string ( $volume )) {
$source = str ( $volume ) -> before ( ':' );
$target = str ( $volume ) -> after ( ':' ) -> beforeLast ( ':' );
$source = $name ;
$volume = " $source : $target " ;
} elseif ( is_array ( $volume )) {
data_set ( $volume , 'source' , $name );
}
$topLevel -> get ( 'volumes' ) -> put ( $name , [
'name' => $name ,
]);
LocalPersistentVolume :: updateOrCreate (
[
2024-09-04 12:09:52 +00:00
'name' => $name ,
2024-08-27 19:48:25 +00:00
'resource_id' => $originalResource -> id ,
'resource_type' => get_class ( $originalResource ),
2024-08-27 14:02:52 +00:00
],
[
'name' => $name ,
'mount_path' => $target ,
2024-08-27 19:48:25 +00:00
'resource_id' => $originalResource -> id ,
'resource_type' => get_class ( $originalResource ),
2024-08-27 14:02:52 +00:00
]
);
}
2024-08-27 19:48:25 +00:00
dispatch ( new ServerFilesFromServerJob ( $originalResource ));
2024-08-27 14:02:52 +00:00
$volumesParsed -> put ( $index , $volume );
}
}
2024-08-28 20:05:49 +00:00
if ( $depends_on ? -> count () > 0 ) {
if ( $isApplication && $isPullRequest ) {
$newDependsOn = collect ([]);
$depends_on -> each ( function ( $dependency , $condition ) use ( $pullRequestId , $newDependsOn ) {
if ( is_numeric ( $condition )) {
$dependency = " $dependency -pr- $pullRequestId " ;
$newDependsOn -> put ( $condition , $dependency );
} else {
$condition = " $condition -pr- $pullRequestId " ;
$newDependsOn -> put ( $condition , $dependency );
}
});
$depends_on = $newDependsOn ;
}
}
2024-12-09 14:38:21 +00:00
if ( ! $use_network_mode ) {
2024-09-09 21:30:47 +00:00
if ( $topLevel -> get ( 'networks' ) ? -> count () > 0 ) {
foreach ( $topLevel -> get ( 'networks' ) as $networkName => $network ) {
if ( $networkName === 'default' ) {
continue ;
}
// ignore aliases
if ( $network [ 'aliases' ] ? ? false ) {
continue ;
}
$networkExists = $networks -> contains ( function ( $value , $key ) use ( $networkName ) {
return $value == $networkName || $key == $networkName ;
});
2024-12-09 14:38:21 +00:00
if ( ! $networkExists ) {
2024-09-09 21:30:47 +00:00
$networks -> put ( $networkName , null );
}
2024-08-27 14:02:52 +00:00
}
}
2024-09-09 21:30:47 +00:00
$baseNetworkExists = $networks -> contains ( function ( $value , $_ ) use ( $baseNetwork ) {
return $value == $baseNetwork ;
});
2024-12-09 14:38:21 +00:00
if ( ! $baseNetworkExists ) {
2024-09-09 21:30:47 +00:00
foreach ( $baseNetwork as $network ) {
$topLevel -> get ( 'networks' ) -> put ( $network , [
'name' => $network ,
'external' => true ,
]);
}
2024-08-27 14:02:52 +00:00
}
}
2024-08-27 19:48:25 +00:00
// Collect/create/update ports
$collectedPorts = collect ([]);
if ( $ports -> count () > 0 ) {
foreach ( $ports as $sport ) {
if ( is_string ( $sport ) || is_numeric ( $sport )) {
$collectedPorts -> push ( $sport );
}
if ( is_array ( $sport )) {
$target = data_get ( $sport , 'target' );
$published = data_get ( $sport , 'published' );
$protocol = data_get ( $sport , 'protocol' );
$collectedPorts -> push ( " $target : $published / $protocol " );
}
}
}
if ( $isService ) {
$originalResource -> ports = $collectedPorts -> implode ( ',' );
$originalResource -> save ();
}
2024-08-27 14:02:52 +00:00
$networks_temp = collect ();
2024-12-09 14:38:21 +00:00
if ( ! $use_network_mode ) {
2024-09-09 21:30:47 +00:00
foreach ( $networks as $key => $network ) {
if ( gettype ( $network ) === 'string' ) {
// networks:
// - appwrite
$networks_temp -> put ( $network , null );
} elseif ( gettype ( $network ) === 'array' ) {
// networks:
// default:
// ipv4_address: 192.168.203.254
$networks_temp -> put ( $key , $network );
}
}
foreach ( $baseNetwork as $key => $network ) {
2024-08-27 14:02:52 +00:00
$networks_temp -> put ( $network , null );
}
2024-09-09 21:30:47 +00:00
if ( $isApplication ) {
if ( data_get ( $resource , 'settings.connect_to_docker_network' )) {
$network = $resource -> destination -> network ;
$networks_temp -> put ( $network , null );
$topLevel -> get ( 'networks' ) -> put ( $network , [
'name' => $network ,
'external' => true ,
]);
}
2024-08-27 14:02:52 +00:00
}
}
2024-08-28 16:12:00 +00:00
2024-09-07 18:56:26 +00:00
$normalEnvironments = $environment -> diffKeys ( $allMagicEnvironments );
$normalEnvironments = $normalEnvironments -> filter ( function ( $value , $key ) {
2024-12-09 14:38:21 +00:00
return ! str ( $value ) -> startsWith ( 'SERVICE_' );
2024-08-28 16:12:00 +00:00
});
2024-08-28 13:45:11 +00:00
foreach ( $normalEnvironments as $key => $value ) {
$key = str ( $key );
$value = str ( $value );
2024-09-09 13:04:51 +00:00
$originalValue = $value ;
$parsedValue = replaceVariables ( $value );
if ( $value -> startsWith ( '$SERVICE_' )) {
2024-12-17 09:38:32 +00:00
$resource -> environment_variables () -> firstOrCreate ([
2024-09-09 13:04:51 +00:00
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-09-09 13:04:51 +00:00
], [
'value' => $value ,
'is_build_time' => false ,
'is_preview' => false ,
]);
2024-09-07 18:56:26 +00:00
2024-09-09 13:04:51 +00:00
continue ;
}
2024-12-09 14:38:21 +00:00
if ( ! $value -> startsWith ( '$' )) {
2024-09-09 13:04:51 +00:00
continue ;
}
2024-09-07 18:56:26 +00:00
if ( $key -> value () === $parsedValue -> value ()) {
$value = null ;
2024-12-17 09:38:32 +00:00
$resource -> environment_variables () -> firstOrCreate ([
2024-08-27 14:02:52 +00:00
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-08-27 14:02:52 +00:00
], [
'value' => $value ,
'is_build_time' => false ,
'is_preview' => false ,
]);
2024-09-07 18:56:26 +00:00
} else {
if ( $value -> startsWith ( '$' )) {
2024-10-11 12:38:22 +00:00
$isRequired = false ;
2024-09-07 18:56:26 +00:00
if ( $value -> contains ( ':-' )) {
2024-09-09 13:04:51 +00:00
$value = replaceVariables ( $value );
2024-09-07 18:56:26 +00:00
$key = $value -> before ( ':' );
$value = $value -> after ( ':-' );
} elseif ( $value -> contains ( '-' )) {
2024-09-09 13:04:51 +00:00
$value = replaceVariables ( $value );
2024-09-07 18:56:26 +00:00
$key = $value -> before ( '-' );
$value = $value -> after ( '-' );
} elseif ( $value -> contains ( ':?' )) {
2024-09-09 13:04:51 +00:00
$value = replaceVariables ( $value );
2024-09-07 18:56:26 +00:00
$key = $value -> before ( ':' );
$value = $value -> after ( ':?' );
2024-10-11 12:38:22 +00:00
$isRequired = true ;
2024-09-07 18:56:26 +00:00
} elseif ( $value -> contains ( '?' )) {
2024-09-09 13:04:51 +00:00
$value = replaceVariables ( $value );
2024-09-07 18:56:26 +00:00
$key = $value -> before ( '?' );
$value = $value -> after ( '?' );
2024-10-11 12:38:22 +00:00
$isRequired = true ;
2024-09-07 18:56:26 +00:00
}
2024-09-09 13:04:51 +00:00
if ( $originalValue -> value () === $value -> value ()) {
2024-09-24 16:21:31 +00:00
// This means the variable does not have a default value, so it needs to be created in Coolify
$parsedKeyValue = replaceVariables ( $value );
2024-12-17 09:38:32 +00:00
$resource -> environment_variables () -> firstOrCreate ([
2024-09-24 16:21:31 +00:00
'key' => $parsedKeyValue ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-09-24 16:21:31 +00:00
], [
'is_build_time' => false ,
'is_preview' => false ,
2024-10-11 12:38:22 +00:00
'is_required' => $isRequired ,
2024-09-24 16:21:31 +00:00
]);
2024-09-24 16:38:35 +00:00
// Add the variable to the environment so it will be shown in the deployable compose file
2024-12-17 09:38:32 +00:00
$environment [ $parsedKeyValue -> value ()] = $resource -> environment_variables () -> where ( 'key' , $parsedKeyValue ) -> where ( 'resourceable_type' , get_class ( $resource )) -> where ( 'resourceable_id' , $resource -> id ) -> first () -> value ;
2024-09-24 16:21:31 +00:00
2024-09-09 13:04:51 +00:00
continue ;
}
2024-12-17 09:38:32 +00:00
$resource -> environment_variables () -> firstOrCreate ([
2024-09-07 18:56:26 +00:00
'key' => $key ,
2024-12-17 09:38:32 +00:00
'resourceable_type' => get_class ( $resource ),
'resourceable_id' => $resource -> id ,
2024-09-07 18:56:26 +00:00
], [
'value' => $value ,
'is_build_time' => false ,
'is_preview' => false ,
2024-10-11 12:38:22 +00:00
'is_required' => $isRequired ,
2024-09-07 18:56:26 +00:00
]);
}
2024-08-27 14:02:52 +00:00
}
}
2024-08-28 16:12:00 +00:00
if ( $isApplication ) {
2024-08-28 20:05:49 +00:00
$branch = $originalResource -> git_branch ;
2024-08-28 16:12:00 +00:00
if ( $pullRequestId !== 0 ) {
$branch = " pull/ { $pullRequestId } /head " ;
}
if ( $originalResource -> environment_variables -> where ( 'key' , 'COOLIFY_BRANCH' ) -> isEmpty ()) {
2024-09-13 06:23:05 +00:00
$coolifyEnvironments -> put ( 'COOLIFY_BRANCH' , " \" { $branch } \" " );
2024-08-28 16:12:00 +00:00
}
}
2024-08-27 14:02:52 +00:00
2025-01-24 11:04:34 +00:00
// Add COOLIFY_RESOURCE_UUID to environment
if ( $resource -> environment_variables -> where ( 'key' , 'COOLIFY_RESOURCE_UUID' ) -> isEmpty ()) {
$coolifyEnvironments -> put ( 'COOLIFY_RESOURCE_UUID' , " { $resource -> uuid } " );
}
2024-08-28 13:45:11 +00:00
// Add COOLIFY_CONTAINER_NAME to environment
if ( $resource -> environment_variables -> where ( 'key' , 'COOLIFY_CONTAINER_NAME' ) -> isEmpty ()) {
2025-01-23 02:08:31 +00:00
$coolifyEnvironments -> put ( 'COOLIFY_CONTAINER_NAME' , " { $containerName } " );
2024-08-28 13:45:11 +00:00
}
2024-08-27 19:48:25 +00:00
2024-08-28 13:45:11 +00:00
if ( $isApplication ) {
$domains = collect ( json_decode ( $resource -> docker_compose_domains )) ? ? collect ([]);
$fqdns = data_get ( $domains , " $serviceName .domain " );
if ( $fqdns ) {
$fqdns = str ( $fqdns ) -> explode ( ',' );
if ( $isPullRequest ) {
$preview = $resource -> previews () -> find ( $preview_id );
$docker_compose_domains = collect ( json_decode ( data_get ( $preview , 'docker_compose_domains' )));
if ( $docker_compose_domains -> count () > 0 ) {
$found_fqdn = data_get ( $docker_compose_domains , " $serviceName .domain " );
if ( $found_fqdn ) {
$fqdns = collect ( $found_fqdn );
2024-08-27 14:02:52 +00:00
} else {
2024-08-28 13:45:11 +00:00
$fqdns = collect ([]);
2024-08-27 14:02:52 +00:00
}
} else {
2024-08-28 20:05:49 +00:00
$fqdns = $fqdns -> map ( function ( $fqdn ) use ( $pullRequestId , $resource ) {
$preview = ApplicationPreview :: findPreviewByApplicationAndPullId ( $resource -> id , $pullRequestId );
2024-08-28 13:45:11 +00:00
$url = Url :: fromString ( $fqdn );
2024-08-28 20:05:49 +00:00
$template = $resource -> preview_url_template ;
2024-08-28 13:45:11 +00:00
$host = $url -> getHost ();
$schema = $url -> getScheme ();
$random = new Cuid2 ;
$preview_fqdn = str_replace ( '{{random}}' , $random , $template );
$preview_fqdn = str_replace ( '{{domain}}' , $host , $preview_fqdn );
$preview_fqdn = str_replace ( '{{pr_id}}' , $pullRequestId , $preview_fqdn );
$preview_fqdn = " $schema :// $preview_fqdn " ;
$preview -> fqdn = $preview_fqdn ;
$preview -> save ();
return $preview_fqdn ;
});
2024-08-27 14:02:52 +00:00
}
}
}
2024-12-02 17:38:21 +00:00
2024-08-28 13:45:11 +00:00
$defaultLabels = defaultLabels (
id : $resource -> id ,
name : $containerName ,
2024-11-17 21:49:44 +00:00
projectName : $resource -> project () -> name ,
resourceName : $resource -> name ,
2024-08-28 13:45:11 +00:00
pull_request_id : $pullRequestId ,
2024-12-02 17:38:21 +00:00
type : 'application' ,
environment : $resource -> environment -> name ,
2024-08-28 13:45:11 +00:00
);
} elseif ( $isService ) {
if ( $savedService -> serviceType ()) {
$fqdns = generateServiceSpecificFqdns ( $savedService );
} else {
$fqdns = collect ( data_get ( $savedService , 'fqdns' )) -> filter ();
}
2024-11-17 21:49:44 +00:00
$defaultLabels = defaultLabels (
id : $resource -> id ,
name : $containerName ,
projectName : $resource -> project () -> name ,
resourceName : $resource -> name ,
type : 'service' ,
subType : $isDatabase ? 'database' : 'application' ,
subId : $savedService -> id ,
subName : $savedService -> human_name ? ? $savedService -> name ,
2024-12-02 17:38:21 +00:00
environment : $resource -> environment -> name ,
2024-11-17 21:49:44 +00:00
);
2024-08-28 13:45:11 +00:00
}
2024-08-28 16:12:00 +00:00
// Add COOLIFY_FQDN & COOLIFY_URL to environment
2024-12-09 14:38:21 +00:00
if ( ! $isDatabase && $fqdns instanceof Collection && $fqdns -> count () > 0 ) {
2024-09-07 18:56:26 +00:00
$coolifyEnvironments -> put ( 'COOLIFY_URL' , $fqdns -> implode ( ',' ));
2024-08-28 16:12:00 +00:00
$urls = $fqdns -> map ( function ( $fqdn ) {
return str ( $fqdn ) -> replace ( 'http://' , '' ) -> replace ( 'https://' , '' );
});
2024-09-07 18:56:26 +00:00
$coolifyEnvironments -> put ( 'COOLIFY_FQDN' , $urls -> implode ( ',' ));
2024-08-27 14:02:52 +00:00
}
2024-09-07 18:56:26 +00:00
add_coolify_default_environment_variables ( $resource , $coolifyEnvironments , $resource -> environment_variables );
2024-08-27 19:48:25 +00:00
2024-09-07 18:56:26 +00:00
if ( $environment -> count () > 0 ) {
$environment = $environment -> filter ( function ( $value , $key ) {
2024-12-09 14:38:21 +00:00
return ! str ( $key ) -> startsWith ( 'SERVICE_FQDN_' );
2024-09-24 16:38:35 +00:00
}) -> map ( function ( $value , $key ) use ( $resource ) {
2024-09-24 16:21:31 +00:00
// if value is empty, set it to null so if you set the environment variable in the .env file (Coolify's UI), it will used
if ( str ( $value ) -> isEmpty ()) {
2024-09-24 16:38:35 +00:00
if ( $resource -> environment_variables () -> where ( 'key' , $key ) -> exists ()) {
$value = $resource -> environment_variables () -> where ( 'key' , $key ) -> first () -> value ;
} else {
$value = null ;
}
2024-09-24 16:21:31 +00:00
}
return $value ;
2024-09-07 18:56:26 +00:00
});
}
2025-02-28 19:25:19 +00:00
$serviceLabels = $labels -> merge ( $defaultLabels );
2024-10-03 20:58:06 +00:00
if ( $serviceLabels -> count () > 0 ) {
if ( $isApplication ) {
$isContainerLabelEscapeEnabled = data_get ( $resource , 'settings.is_container_label_escape_enabled' );
} else {
$isContainerLabelEscapeEnabled = data_get ( $resource , 'is_container_label_escape_enabled' );
}
if ( $isContainerLabelEscapeEnabled ) {
$serviceLabels = $serviceLabels -> map ( function ( $value , $key ) {
return escapeDollarSign ( $value );
});
}
}
2024-12-09 14:38:21 +00:00
if ( ! $isDatabase && $fqdns instanceof Collection && $fqdns -> count () > 0 ) {
2024-08-28 13:45:11 +00:00
if ( $isApplication ) {
$shouldGenerateLabelsExactly = $resource -> destination -> server -> settings -> generate_exact_labels ;
2024-08-28 20:05:49 +00:00
$uuid = $resource -> uuid ;
2024-09-13 09:12:28 +00:00
$network = data_get ( $resource , 'destination.network' );
2024-08-28 20:05:49 +00:00
if ( $isPullRequest ) {
$uuid = " { $resource -> uuid } - { $pullRequestId } " ;
}
if ( $isPullRequest ) {
$network = " { $resource -> destination -> network } - { $pullRequestId } " ;
}
2024-08-28 13:45:11 +00:00
} else {
$shouldGenerateLabelsExactly = $resource -> server -> settings -> generate_exact_labels ;
2024-08-28 20:05:49 +00:00
$uuid = $resource -> uuid ;
2024-09-13 09:12:28 +00:00
$network = data_get ( $resource , 'destination.network' );
2024-08-28 13:45:11 +00:00
}
if ( $shouldGenerateLabelsExactly ) {
switch ( $server -> proxyType ()) {
case ProxyTypes :: TRAEFIK -> value :
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForTraefik (
2024-08-28 20:05:49 +00:00
uuid : $uuid ,
2024-08-28 13:45:11 +00:00
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $originalResource -> isGzipEnabled (),
is_stripprefix_enabled : $originalResource -> isStripprefixEnabled (),
service_name : $serviceName ,
image : $image
2025-02-28 19:25:19 +00:00
));
2024-08-28 13:45:11 +00:00
break ;
case ProxyTypes :: CADDY -> value :
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForCaddy (
2024-08-28 20:05:49 +00:00
network : $network ,
uuid : $uuid ,
2024-08-28 13:45:11 +00:00
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $originalResource -> isGzipEnabled (),
is_stripprefix_enabled : $originalResource -> isStripprefixEnabled (),
service_name : $serviceName ,
image : $image ,
predefinedPort : $predefinedPort
2025-02-28 19:25:19 +00:00
));
2024-08-28 13:45:11 +00:00
break ;
2024-08-27 19:48:25 +00:00
}
2024-08-28 13:45:11 +00:00
} else {
2025-02-28 19:25:19 +00:00
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForTraefik (
2024-08-28 20:05:49 +00:00
uuid : $uuid ,
2024-08-28 13:45:11 +00:00
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $originalResource -> isGzipEnabled (),
is_stripprefix_enabled : $originalResource -> isStripprefixEnabled (),
service_name : $serviceName ,
image : $image
2025-02-28 19:25:19 +00:00
));
$serviceLabels = $serviceLabels -> merge ( fqdnLabelsForCaddy (
2024-08-28 20:05:49 +00:00
network : $network ,
uuid : $uuid ,
2024-08-28 13:45:11 +00:00
domains : $fqdns ,
is_force_https_enabled : true ,
serviceLabels : $serviceLabels ,
is_gzip_enabled : $originalResource -> isGzipEnabled (),
is_stripprefix_enabled : $originalResource -> isStripprefixEnabled (),
service_name : $serviceName ,
image : $image ,
predefinedPort : $predefinedPort
));
2024-08-27 19:48:25 +00:00
}
2024-08-27 14:02:52 +00:00
}
2024-08-28 13:45:11 +00:00
if ( $isService ) {
if ( data_get ( $service , 'restart' ) === 'no' || data_get ( $service , 'exclude_from_hc' )) {
$savedService -> update ([ 'exclude_from_status' => true ]);
}
}
data_forget ( $service , 'volumes.*.content' );
data_forget ( $service , 'volumes.*.isDirectory' );
data_forget ( $service , 'volumes.*.is_directory' );
data_forget ( $service , 'exclude_from_hc' );
2024-08-27 19:48:25 +00:00
2024-09-23 07:26:49 +00:00
$volumesParsed = $volumesParsed -> map ( function ( $volume ) {
data_forget ( $volume , 'content' );
data_forget ( $volume , 'is_directory' );
data_forget ( $volume , 'isDirectory' );
return $volume ;
});
2024-08-27 14:02:52 +00:00
$payload = collect ( $service ) -> merge ([
'container_name' => $containerName ,
2024-08-28 13:45:11 +00:00
'restart' => $restart -> value (),
2024-08-27 19:48:25 +00:00
'labels' => $serviceLabels ,
2024-08-27 14:02:52 +00:00
]);
2024-12-09 14:38:21 +00:00
if ( ! $use_network_mode ) {
2024-09-09 21:30:47 +00:00
$payload [ 'networks' ] = $networks_temp ;
}
2024-08-29 10:03:23 +00:00
if ( $ports -> count () > 0 ) {
$payload [ 'ports' ] = $ports ;
}
2024-08-28 13:45:11 +00:00
if ( $volumesParsed -> count () > 0 ) {
$payload [ 'volumes' ] = $volumesParsed ;
}
2024-09-07 18:56:26 +00:00
if ( $environment -> count () > 0 || $coolifyEnvironments -> count () > 0 ) {
$payload [ 'environment' ] = $environment -> merge ( $coolifyEnvironments );
2024-08-28 13:45:11 +00:00
}
2024-08-27 14:02:52 +00:00
if ( $logging ) {
$payload [ 'logging' ] = $logging ;
}
if ( $depends_on -> count () > 0 ) {
$payload [ 'depends_on' ] = $depends_on ;
}
if ( $isApplication && $isPullRequest ) {
$serviceName = " { $serviceName } -pr- { $pullRequestId } " ;
}
2024-08-28 13:45:11 +00:00
2024-08-27 14:02:52 +00:00
$parsedServices -> put ( $serviceName , $payload );
}
$topLevel -> put ( 'services' , $parsedServices );
2024-09-23 07:26:49 +00:00
2024-08-27 14:02:52 +00:00
$customOrder = [ 'services' , 'volumes' , 'networks' , 'configs' , 'secrets' ];
$topLevel = $topLevel -> sortBy ( function ( $value , $key ) use ( $customOrder ) {
return array_search ( $key , $customOrder );
});
2024-08-28 13:45:11 +00:00
2024-08-27 14:02:52 +00:00
$resource -> docker_compose = Yaml :: dump ( convertToArray ( $topLevel ), 10 , 2 );
data_forget ( $resource , 'environment_variables' );
data_forget ( $resource , 'environment_variables_preview' );
$resource -> save ();
return $topLevel ;
}
2024-08-28 09:11:14 +00:00
2024-08-29 13:11:54 +00:00
function generate_fluentd_configuration () : array
{
2024-08-28 09:11:14 +00:00
return [
'driver' => 'fluentd' ,
'options' => [
'fluentd-address' => 'tcp://127.0.0.1:24224' ,
'fluentd-async' => 'true' ,
'fluentd-sub-second-precision' => 'true' ,
// env vars are used in the LogDrain configurations
'env' => 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' ,
2024-08-29 13:11:54 +00:00
],
2024-08-28 09:11:14 +00:00
];
}
2024-08-28 11:30:59 +00:00
2024-09-03 15:04:56 +00:00
function isAssociativeArray ( $array )
{
if ( $array instanceof Collection ) {
$array = $array -> toArray ();
}
2024-12-09 14:38:21 +00:00
if ( ! is_array ( $array )) {
2024-09-03 15:04:56 +00:00
throw new \InvalidArgumentException ( 'Input must be an array or a Collection.' );
}
if ( $array === []) {
return false ;
}
return array_keys ( $array ) !== range ( 0 , count ( $array ) - 1 );
}
2024-08-28 11:30:59 +00:00
/**
2024-08-29 13:11:54 +00:00
* This method adds the default environment variables to the resource .
* - COOLIFY_APP_NAME
* - COOLIFY_PROJECT_NAME
* - COOLIFY_SERVER_IP
* - COOLIFY_ENVIRONMENT_NAME
*
* Theses variables are added in place to the $where_to_add array .
*/
function add_coolify_default_environment_variables ( StandaloneRedis | StandalonePostgresql | StandaloneMongodb | StandaloneMysql | StandaloneMariadb | StandaloneKeydb | StandaloneDragonfly | StandaloneClickhouse | Application | Service $resource , Collection & $where_to_add , ? Collection $where_to_check = null )
{
2024-10-11 09:04:44 +00:00
// Currently disabled
return ;
2024-09-03 15:04:56 +00:00
if ( $resource instanceof Service ) {
$ip = $resource -> server -> ip ;
} else {
$ip = $resource -> destination -> server -> ip ;
}
if ( isAssociativeArray ( $where_to_add )) {
$isAssociativeArray = true ;
} else {
$isAssociativeArray = false ;
}
2024-08-28 11:30:59 +00:00
if ( $where_to_check != null && $where_to_check -> where ( 'key' , 'COOLIFY_APP_NAME' ) -> isEmpty ()) {
2024-09-03 15:04:56 +00:00
if ( $isAssociativeArray ) {
2024-09-13 06:23:05 +00:00
$where_to_add -> put ( 'COOLIFY_APP_NAME' , " \" { $resource -> name } \" " );
2024-08-29 13:11:54 +00:00
} else {
2024-09-13 06:23:05 +00:00
$where_to_add -> push ( " COOLIFY_APP_NAME= \" { $resource -> name } \" " );
2024-08-29 13:11:54 +00:00
}
2024-08-28 11:30:59 +00:00
}
if ( $where_to_check != null && $where_to_check -> where ( 'key' , 'COOLIFY_SERVER_IP' ) -> isEmpty ()) {
2024-09-03 15:04:56 +00:00
if ( $isAssociativeArray ) {
2024-09-13 06:23:05 +00:00
$where_to_add -> put ( 'COOLIFY_SERVER_IP' , " \" { $ip } \" " );
2024-08-29 13:11:54 +00:00
} else {
2024-09-13 06:23:05 +00:00
$where_to_add -> push ( " COOLIFY_SERVER_IP= \" { $ip } \" " );
2024-08-29 13:11:54 +00:00
}
2024-08-28 11:30:59 +00:00
}
if ( $where_to_check != null && $where_to_check -> where ( 'key' , 'COOLIFY_ENVIRONMENT_NAME' ) -> isEmpty ()) {
2024-09-03 15:04:56 +00:00
if ( $isAssociativeArray ) {
2024-09-13 06:23:05 +00:00
$where_to_add -> put ( 'COOLIFY_ENVIRONMENT_NAME' , " \" { $resource -> environment -> name } \" " );
2024-08-29 13:11:54 +00:00
} else {
2024-09-13 06:23:05 +00:00
$where_to_add -> push ( " COOLIFY_ENVIRONMENT_NAME= \" { $resource -> environment -> name } \" " );
2024-08-29 13:11:54 +00:00
}
2024-08-28 11:30:59 +00:00
}
if ( $where_to_check != null && $where_to_check -> where ( 'key' , 'COOLIFY_PROJECT_NAME' ) -> isEmpty ()) {
2024-09-03 15:04:56 +00:00
if ( $isAssociativeArray ) {
2024-09-13 06:23:05 +00:00
$where_to_add -> put ( 'COOLIFY_PROJECT_NAME' , " \" { $resource -> project () -> name } \" " );
2024-08-29 13:11:54 +00:00
} else {
2024-09-13 06:23:05 +00:00
$where_to_add -> push ( " COOLIFY_PROJECT_NAME= \" { $resource -> project () -> name } \" " );
2024-08-29 13:11:54 +00:00
}
2024-08-28 11:30:59 +00:00
}
2024-08-29 13:11:54 +00:00
}
2024-08-29 12:35:04 +00:00
2025-02-27 10:29:04 +00:00
function convertToKeyValueCollection ( $environment )
2024-08-28 13:45:11 +00:00
{
$convertedServiceVariables = collect ([]);
2024-09-04 11:37:15 +00:00
if ( isAssociativeArray ( $environment )) {
2024-10-02 16:26:40 +00:00
// Example: $environment = ['FOO' => 'bar', 'BAZ' => 'qux'];
2024-09-30 09:15:23 +00:00
if ( $environment instanceof Collection ) {
$changedEnvironment = collect ([]);
$environment -> each ( function ( $value , $key ) use ( $changedEnvironment ) {
2024-10-02 16:26:40 +00:00
if ( is_numeric ( $key )) {
$parts = explode ( '=' , $value , 2 );
if ( count ( $parts ) === 2 ) {
$key = $parts [ 0 ];
$realValue = $parts [ 1 ] ? ? '' ;
$changedEnvironment -> put ( $key , $realValue );
} else {
$changedEnvironment -> put ( $key , $value );
}
2024-09-30 09:15:23 +00:00
} else {
$changedEnvironment -> put ( $key , $value );
}
});
return $changedEnvironment ;
}
2024-09-04 11:37:15 +00:00
$convertedServiceVariables = $environment ;
} else {
2024-10-02 16:26:40 +00:00
// Example: $environment = ['FOO=bar', 'BAZ=qux'];
2024-09-04 11:37:15 +00:00
foreach ( $environment as $value ) {
2024-10-03 13:04:40 +00:00
if ( is_string ( $value )) {
$parts = explode ( '=' , $value , 2 );
$key = $parts [ 0 ];
$realValue = $parts [ 1 ] ? ? '' ;
if ( $key ) {
$convertedServiceVariables -> put ( $key , $realValue );
}
2024-08-28 13:45:11 +00:00
}
}
}
return $convertedServiceVariables ;
2024-08-28 11:30:59 +00:00
}
2024-10-01 08:33:56 +00:00
function instanceSettings ()
{
return InstanceSettings :: get ();
}
2024-10-08 13:11:19 +00:00
2024-10-17 19:48:47 +00:00
function loadConfigFromGit ( string $repository , string $branch , string $base_directory , int $server_id , int $team_id )
{
2024-10-08 13:11:19 +00:00
$server = Server :: find ( $server_id ) -> where ( 'team_id' , $team_id ) -> first ();
2024-12-09 14:38:21 +00:00
if ( ! $server ) {
2024-10-08 13:11:19 +00:00
return ;
}
2024-10-17 19:48:47 +00:00
$uuid = new Cuid2 ;
2024-10-08 13:11:19 +00:00
$cloneCommand = " git clone --no-checkout -b $branch $repository . " ;
$workdir = rtrim ( $base_directory , '/' );
$fileList = collect ([ " . $workdir /coolify.json " ]);
$commands = collect ([
" rm -rf /tmp/ { $uuid } " ,
" mkdir -p /tmp/ { $uuid } " ,
" cd /tmp/ { $uuid } " ,
$cloneCommand ,
'git sparse-checkout init --cone' ,
" git sparse-checkout set { $fileList -> implode ( ' ' ) } " ,
'git read-tree -mu HEAD' ,
" cat . $workdir /coolify.json " ,
'rm -rf /tmp/{$uuid}' ,
]);
try {
return instant_remote_process ( $commands , $server );
2024-10-31 14:19:37 +00:00
} catch ( \Exception ) {
2024-10-17 19:48:47 +00:00
// continue
2024-10-08 13:11:19 +00:00
}
}
2024-10-17 08:04:49 +00:00
2024-10-25 15:49:16 +00:00
function loggy ( $message = null , array $context = [])
2024-10-17 08:04:49 +00:00
{
2024-12-09 14:38:21 +00:00
if ( ! isDev ()) {
2024-10-17 08:04:49 +00:00
return ;
}
if ( function_exists ( 'ray' ) && config ( 'app.debug' )) {
ray ( $message , $context );
}
if ( is_null ( $message )) {
return app ( 'log' );
}
return app ( 'log' ) -> debug ( $message , $context );
}
2024-10-20 20:15:31 +00:00
function sslipDomainWarning ( string $domains )
{
$domains = str ( $domains ) -> trim () -> explode ( ',' );
$showSslipHttpsWarning = false ;
$domains -> each ( function ( $domain ) use ( & $showSslipHttpsWarning ) {
if ( str ( $domain ) -> contains ( 'https' ) && str ( $domain ) -> contains ( 'sslip' )) {
$showSslipHttpsWarning = true ;
}
});
return $showSslipHttpsWarning ;
}
2024-10-25 13:13:23 +00:00
function isEmailRateLimited ( string $limiterKey , int $decaySeconds = 3600 , ? callable $callbackOnSuccess = null ) : bool
{
if ( isDev ()) {
$decaySeconds = 120 ;
}
$rateLimited = false ;
$executed = RateLimiter :: attempt (
$limiterKey ,
$maxAttempts = 0 ,
function () use ( & $rateLimited , & $limiterKey , $callbackOnSuccess ) {
2024-12-09 14:38:21 +00:00
isDev () && loggy ( 'Rate limit not reached for ' . $limiterKey );
2024-10-25 13:13:23 +00:00
$rateLimited = false ;
if ( $callbackOnSuccess ) {
$callbackOnSuccess ();
}
},
$decaySeconds ,
);
2024-12-09 14:38:21 +00:00
if ( ! $executed ) {
isDev () && loggy ( 'Rate limit reached for ' . $limiterKey . '. Rate limiter will be disabled for ' . $decaySeconds . ' seconds.' );
2024-10-25 13:13:23 +00:00
$rateLimited = true ;
}
return $rateLimited ;
}
2024-11-11 13:37:19 +00:00
2025-03-31 13:10:50 +00:00
function defaultNginxConfiguration ( string $type = 'static' ) : string
2024-11-11 13:37:19 +00:00
{
2025-03-31 13:10:50 +00:00
if ( $type === 'spa' ) {
return <<< 'NGINX'
server {
location / {
root / usr / share / nginx / html ;
index index . html ;
try_files $uri $uri / / index . html ;
}
# Handle 404 errors
error_page 404 / 404. html ;
location = / 404. html {
root / usr / share / nginx / html ;
internal ;
}
# Handle server errors (50x)
error_page 500 502 503 504 / 50 x . html ;
location = / 50 x . html {
root / usr / share / nginx / html ;
internal ;
}
}
NGINX ;
} else {
return <<< 'NGINX'
server {
2024-11-11 13:37:19 +00:00
location / {
2025-03-13 19:30:22 +00:00
root / usr / share / nginx / html ;
index index . html index . htm ;
try_files $uri $uri . html $uri / index . html $uri / index . htm $uri / = 404 ;
2024-11-11 13:37:19 +00:00
}
2025-03-13 19:30:22 +00:00
# Handle 404 errors
error_page 404 / 404. html ;
location = / 404. html {
2024-11-11 13:45:34 +00:00
root / usr / share / nginx / html ;
internal ;
2024-11-11 13:37:19 +00:00
}
2025-03-13 19:30:22 +00:00
# Handle server errors (50x)
error_page 500 502 503 504 / 50 x . html ;
location = / 50 x . html {
2024-11-11 13:37:19 +00:00
root / usr / share / nginx / html ;
internal ;
}
2025-03-31 13:10:50 +00:00
}
NGINX ;
}
2024-11-11 13:37:19 +00:00
}
2024-11-12 10:32:18 +00:00
function convertGitUrl ( string $gitRepository , string $deploymentType , ? GithubApp $source = null ) : array
{
$repository = $gitRepository ;
$providerInfo = [
'host' => null ,
'user' => 'git' ,
'port' => 22 ,
'repository' => $gitRepository ,
];
$sshMatches = [];
$matches = [];
// Let's try and parse the string to detect if it's a valid SSH string or not
preg_match ( '/((.*?)\:\/\/)?(.*@.*:.*)/' , $gitRepository , $sshMatches );
if ( $deploymentType === 'deploy_key' && empty ( $sshMatches ) && $source ) {
// If this happens, the user may have provided an HTTP URL when they needed an SSH one
// Let's try and fix that for known Git providers
switch ( $source -> getMorphClass ()) {
case \App\Models\GithubApp :: class :
$providerInfo [ 'host' ] = Url :: fromString ( $source -> html_url ) -> getHost ();
$providerInfo [ 'port' ] = $source -> custom_port ;
$providerInfo [ 'user' ] = $source -> custom_user ;
break ;
}
if ( ! empty ( $providerInfo [ 'host' ])) {
// Until we do not support more providers with App (like GithubApp), this will be always true, port will be 22
if ( $providerInfo [ 'port' ] === 22 ) {
$repository = " { $providerInfo [ 'user' ] } @ { $providerInfo [ 'host' ] } : { $providerInfo [ 'repository' ] } " ;
} else {
$repository = " ssh:// { $providerInfo [ 'user' ] } @ { $providerInfo [ 'host' ] } : { $providerInfo [ 'port' ] } / { $providerInfo [ 'repository' ] } " ;
}
}
}
preg_match ( '/(?<=:)\d+(?=\/)/' , $gitRepository , $matches );
if ( count ( $matches ) === 1 ) {
$providerInfo [ 'port' ] = $matches [ 0 ];
$gitHost = str ( $gitRepository ) -> before ( ':' );
$gitRepo = str ( $gitRepository ) -> after ( '/' );
$repository = " $gitHost : $gitRepo " ;
}
return [
'repository' => $repository ,
'port' => $providerInfo [ 'port' ],
];
}
2025-01-10 17:27:48 +00:00
2025-01-10 18:53:13 +00:00
function getJobStatus ( ? string $jobId = null )
2025-01-10 17:27:48 +00:00
{
2025-01-10 18:53:13 +00:00
if ( blank ( $jobId )) {
return 'unknown' ;
}
2025-01-10 17:27:48 +00:00
$jobFound = app ( JobRepository :: class ) -> getJobs ([ $jobId ]);
if ( $jobFound -> isEmpty ()) {
return 'unknown' ;
}
return $jobFound -> first () -> status ;
}
2025-03-24 10:43:10 +00:00
function parseDockerfileInterval ( string $something )
{
$value = preg_replace ( '/[^0-9]/' , '' , $something );
$unit = preg_replace ( '/[0-9]/' , '' , $something );
// Default to seconds if no unit specified
$unit = $unit ? : 's' ;
// Convert to seconds based on unit
$seconds = ( int ) $value ;
switch ( $unit ) {
case 'ns' :
$seconds = ( int ) ( $value / 1000000000 );
break ;
case 'us' :
case 'µs' :
$seconds = ( int ) ( $value / 1000000 );
break ;
case 'ms' :
$seconds = ( int ) ( $value / 1000 );
break ;
case 'm' :
$seconds = ( int ) ( $value * 60 );
break ;
case 'h' :
$seconds = ( int ) ( $value * 3600 );
break ;
}
return $seconds ;
}