2023-04-19 10:42:15 +00:00
< ? php
2023-12-07 18:06:32 +00:00
namespace App\Livewire\Project\Application ;
2023-04-19 10:42:15 +00:00
use App\Models\Application ;
2024-04-15 17:47:17 +00:00
use App\Models\LocalFileVolume ;
2023-09-20 13:42:41 +00:00
use Illuminate\Support\Collection ;
2023-05-16 13:41:23 +00:00
use Illuminate\Support\Str ;
2023-11-13 08:04:19 +00:00
use Livewire\Component ;
2023-11-24 14:48:23 +00:00
use Visus\Cuid2\Cuid2 ;
2023-04-19 10:42:15 +00:00
class General extends Component
{
public string $applicationId ;
public Application $application ;
2023-09-20 13:42:41 +00:00
public Collection $services ;
2023-04-19 10:42:15 +00:00
public string $name ;
2023-10-09 09:10:04 +00:00
public ? string $fqdn = null ;
2023-04-19 10:42:15 +00:00
public string $git_repository ;
public string $git_branch ;
2023-10-09 09:10:04 +00:00
public ? string $git_commit_sha = null ;
2023-04-19 10:42:15 +00:00
public string $build_pack ;
2023-10-20 10:34:25 +00:00
public ? string $ports_exposes = null ;
2023-04-19 10:42:15 +00:00
2023-10-18 08:32:08 +00:00
public $customLabels ;
public bool $labelsChanged = false ;
2024-04-12 08:28:40 +00:00
public bool $initLoadingCompose = false ;
2023-10-18 08:32:08 +00:00
2023-11-27 10:54:55 +00:00
public ? string $initialDockerComposeLocation = null ;
2023-11-27 14:50:22 +00:00
public ? string $initialDockerComposePrLocation = null ;
2023-11-27 10:54:55 +00:00
2023-11-24 14:48:23 +00:00
public $parsedServices = [];
public $parsedServiceDomains = [];
2023-11-20 10:35:31 +00:00
protected $listeners = [
2024-04-25 09:49:34 +00:00
'resetDefaultLabels' ,
'configurationChanged' => '$refresh'
2023-11-20 10:35:31 +00:00
];
2023-04-19 10:42:15 +00:00
protected $rules = [
2023-07-06 12:37:14 +00:00
'application.name' => 'required' ,
2023-08-07 16:46:40 +00:00
'application.description' => 'nullable' ,
2023-04-19 10:42:15 +00:00
'application.fqdn' => 'nullable' ,
'application.git_repository' => 'required' ,
'application.git_branch' => 'required' ,
'application.git_commit_sha' => 'nullable' ,
2023-05-05 07:02:50 +00:00
'application.install_command' => 'nullable' ,
'application.build_command' => 'nullable' ,
'application.start_command' => 'nullable' ,
2023-04-19 10:42:15 +00:00
'application.build_pack' => 'required' ,
2023-04-25 13:48:45 +00:00
'application.static_image' => 'required' ,
2023-04-19 10:42:15 +00:00
'application.base_directory' => 'required' ,
'application.publish_directory' => 'nullable' ,
2023-04-25 12:43:35 +00:00
'application.ports_exposes' => 'required' ,
'application.ports_mappings' => 'nullable' ,
2023-08-11 20:41:47 +00:00
'application.dockerfile' => 'nullable' ,
2023-10-10 09:16:38 +00:00
'application.docker_registry_image_name' => 'nullable' ,
'application.docker_registry_image_tag' => 'nullable' ,
2023-10-10 12:02:43 +00:00
'application.dockerfile_location' => 'nullable' ,
2023-11-24 14:48:23 +00:00
'application.docker_compose_location' => 'nullable' ,
2023-11-27 14:50:22 +00:00
'application.docker_compose_pr_location' => 'nullable' ,
2023-11-24 14:48:23 +00:00
'application.docker_compose' => 'nullable' ,
2023-11-28 09:11:53 +00:00
'application.docker_compose_pr' => 'nullable' ,
2023-11-24 14:48:23 +00:00
'application.docker_compose_raw' => 'nullable' ,
2023-11-28 09:11:53 +00:00
'application.docker_compose_pr_raw' => 'nullable' ,
2023-11-07 12:49:15 +00:00
'application.dockerfile_target_build' => 'nullable' ,
2023-12-17 19:56:12 +00:00
'application.docker_compose_custom_start_command' => 'nullable' ,
'application.docker_compose_custom_build_command' => 'nullable' ,
2024-01-29 15:07:00 +00:00
'application.custom_labels' => 'nullable' ,
'application.custom_docker_run_options' => 'nullable' ,
2024-02-08 10:02:30 +00:00
'application.pre_deployment_command' => 'nullable' ,
'application.pre_deployment_command_container' => 'nullable' ,
2024-02-08 09:27:43 +00:00
'application.post_deployment_command' => 'nullable' ,
'application.post_deployment_command_container' => 'nullable' ,
2024-01-29 15:07:00 +00:00
'application.settings.is_static' => 'boolean|required' ,
2024-01-18 10:40:13 +00:00
'application.settings.is_build_server_enabled' => 'boolean|required' ,
2024-03-28 14:05:12 +00:00
'application.watch_paths' => 'nullable' ,
2023-04-19 10:42:15 +00:00
];
2023-06-16 10:35:40 +00:00
protected $validationAttributes = [
'application.name' => 'name' ,
2023-08-07 16:46:40 +00:00
'application.description' => 'description' ,
2023-06-16 10:35:40 +00:00
'application.fqdn' => 'FQDN' ,
'application.git_repository' => 'Git repository' ,
'application.git_branch' => 'Git branch' ,
'application.git_commit_sha' => 'Git commit SHA' ,
'application.install_command' => 'Install command' ,
'application.build_command' => 'Build command' ,
'application.start_command' => 'Start command' ,
'application.build_pack' => 'Build pack' ,
'application.static_image' => 'Static image' ,
'application.base_directory' => 'Base directory' ,
'application.publish_directory' => 'Publish directory' ,
'application.ports_exposes' => 'Ports exposes' ,
'application.ports_mappings' => 'Ports mappings' ,
2023-08-11 20:41:47 +00:00
'application.dockerfile' => 'Dockerfile' ,
2023-10-10 09:16:38 +00:00
'application.docker_registry_image_name' => 'Docker registry image name' ,
'application.docker_registry_image_tag' => 'Docker registry image tag' ,
2023-10-10 12:02:43 +00:00
'application.dockerfile_location' => 'Dockerfile location' ,
2023-11-24 14:48:23 +00:00
'application.docker_compose_location' => 'Docker compose location' ,
2023-11-27 14:50:22 +00:00
'application.docker_compose_pr_location' => 'Docker compose location' ,
2023-11-24 14:48:23 +00:00
'application.docker_compose' => 'Docker compose' ,
2023-11-28 09:11:53 +00:00
'application.docker_compose_pr' => 'Docker compose' ,
2023-11-24 14:48:23 +00:00
'application.docker_compose_raw' => 'Docker compose raw' ,
2023-11-28 09:11:53 +00:00
'application.docker_compose_pr_raw' => 'Docker compose raw' ,
2023-10-18 08:32:08 +00:00
'application.custom_labels' => 'Custom labels' ,
2023-11-07 12:49:15 +00:00
'application.dockerfile_target_build' => 'Dockerfile target build' ,
2024-01-29 15:07:00 +00:00
'application.custom_docker_run_options' => 'Custom docker run commands' ,
2023-12-17 19:56:12 +00:00
'application.docker_compose_custom_start_command' => 'Docker compose custom start command' ,
'application.docker_compose_custom_build_command' => 'Docker compose custom build command' ,
2024-01-29 15:07:00 +00:00
'application.settings.is_static' => 'Is static' ,
2024-01-18 10:40:13 +00:00
'application.settings.is_build_server_enabled' => 'Is build server enabled' ,
2024-03-28 14:05:12 +00:00
'application.watch_paths' => 'Watch paths' ,
2023-06-16 10:35:40 +00:00
];
2023-10-18 08:32:08 +00:00
public function mount ()
{
2023-11-24 14:48:23 +00:00
try {
$this -> parsedServices = $this -> application -> parseCompose ();
} catch ( \Throwable $e ) {
2023-12-07 18:06:32 +00:00
$this -> dispatch ( 'error' , $e -> getMessage ());
2023-11-24 14:48:23 +00:00
}
2024-03-11 08:42:16 +00:00
if ( $this -> application -> build_pack === 'dockercompose' ) {
$this -> application -> fqdn = null ;
$this -> application -> settings -> save ();
}
2023-11-24 14:48:23 +00:00
$this -> parsedServiceDomains = $this -> application -> docker_compose_domains ? json_decode ( $this -> application -> docker_compose_domains , true ) : [];
2023-10-20 10:34:25 +00:00
$this -> ports_exposes = $this -> application -> ports_exposes ;
2024-04-15 17:47:17 +00:00
$this -> customLabels = $this -> application -> parseContainerLabels ();
2024-03-11 14:08:05 +00:00
if ( ! $this -> customLabels && $this -> application -> destination -> server -> proxyType () !== 'NONE' ) {
2024-01-15 11:30:49 +00:00
$this -> customLabels = str ( implode ( " | " , generateLabelsApplication ( $this -> application ))) -> replace ( " | " , " \n " );
2024-01-02 16:14:52 +00:00
$this -> application -> custom_labels = base64_encode ( $this -> customLabels );
$this -> application -> save ();
2024-01-02 15:44:41 +00:00
}
2023-11-27 10:54:55 +00:00
$this -> initialDockerComposeLocation = $this -> application -> docker_compose_location ;
2024-04-12 08:28:40 +00:00
if ( $this -> application -> build_pack === 'dockercompose' && ! $this -> application -> docker_compose_raw ) {
$this -> initLoadingCompose = true ;
$this -> dispatch ( 'info' , 'Loading docker compose file...' );
}
2024-04-12 10:44:49 +00:00
if ( str ( $this -> application -> status ) -> startsWith ( 'running' ) && is_null ( $this -> application -> config_hash )) {
$this -> dispatch ( 'configurationChanged' );
}
2023-10-18 08:32:08 +00:00
}
2023-11-20 10:35:31 +00:00
public function instantSave ()
{
$this -> application -> settings -> save ();
2023-12-07 18:06:32 +00:00
$this -> dispatch ( 'success' , 'Settings saved.' );
2023-12-06 20:32:23 +00:00
$this -> application -> refresh ();
if ( $this -> ports_exposes !== $this -> application -> ports_exposes ) {
$this -> resetDefaultLabels ( false );
}
2023-11-20 10:35:31 +00:00
}
2023-11-24 14:48:23 +00:00
public function loadComposeFile ( $isInit = false )
{
2023-11-27 10:54:55 +00:00
try {
if ( $isInit && $this -> application -> docker_compose_raw ) {
return ;
}
2023-11-27 14:50:22 +00:00
[ 'parsedServices' => $this -> parsedServices , 'initialDockerComposeLocation' => $this -> initialDockerComposeLocation , 'initialDockerComposePrLocation' => $this -> initialDockerComposePrLocation ] = $this -> application -> loadComposeFile ( $isInit );
2024-04-15 17:47:17 +00:00
$compose = $this -> application -> parseCompose ();
$services = data_get ( $compose , 'services' );
if ( $services ) {
$volumes = collect ( $services ) -> map ( function ( $service ) {
return data_get ( $service , 'volumes' );
}) -> flatten () -> filter ( function ( $volume ) {
return str ( $volume ) -> startsWith ( '/data/coolify' );
}) -> unique () -> values ();
foreach ( $volumes as $volume ) {
$source = Str :: of ( $volume ) -> before ( ':' );
$target = Str :: of ( $volume ) -> after ( ':' ) -> beforeLast ( ':' );
LocalFileVolume :: updateOrCreate (
[
'mount_path' => $target ,
'resource_id' => $this -> application -> id ,
'resource_type' => get_class ( $this -> application )
],
[
'fs_path' => $source ,
'mount_path' => $target ,
'resource_id' => $this -> application -> id ,
'resource_type' => get_class ( $this -> application )
]
);
}
}
2023-12-07 18:06:32 +00:00
$this -> dispatch ( 'success' , 'Docker compose file loaded.' );
2024-04-12 08:28:40 +00:00
$this -> dispatch ( 'compose_loaded' );
2024-04-17 09:32:35 +00:00
$this -> dispatch ( 'refresh_storages' );
2023-11-27 10:54:55 +00:00
} catch ( \Throwable $e ) {
$this -> application -> docker_compose_location = $this -> initialDockerComposeLocation ;
2023-11-27 14:50:22 +00:00
$this -> application -> docker_compose_pr_location = $this -> initialDockerComposePrLocation ;
2023-11-27 10:54:55 +00:00
$this -> application -> save ();
return handleError ( $e , $this );
2024-04-12 08:28:40 +00:00
} finally {
$this -> initLoadingCompose = false ;
2023-11-24 14:48:23 +00:00
}
2023-11-27 10:54:55 +00:00
}
public function generateDomain ( string $serviceName )
{
2024-04-08 10:15:44 +00:00
$uuid = new Cuid2 ( 7 );
$domain = generateFqdn ( $this -> application -> destination -> server , $uuid );
$this -> parsedServiceDomains [ $serviceName ][ 'domain' ] = $domain ;
$this -> application -> docker_compose_domains = json_encode ( $this -> parsedServiceDomains );
$this -> application -> save ();
$this -> dispatch ( 'success' , 'Domain generated.' );
2023-11-27 10:54:55 +00:00
return $domain ;
2023-11-24 14:48:23 +00:00
}
2024-04-08 10:15:44 +00:00
public function updatedApplicationBaseDirectory ()
{
2024-03-11 08:42:16 +00:00
if ( $this -> application -> build_pack === 'dockercompose' ) {
$this -> loadComposeFile ();
}
}
2024-04-15 17:47:17 +00:00
public function updatedApplicationFqdn ()
{
2024-04-16 07:43:42 +00:00
$this -> application -> fqdn = str ( $this -> application -> fqdn ) -> replaceEnd ( ',' , '' ) -> trim ();
$this -> application -> fqdn = str ( $this -> application -> fqdn ) -> replaceStart ( ',' , '' ) -> trim ();
$this -> application -> fqdn = str ( $this -> application -> fqdn ) -> trim () -> explode ( ',' ) -> map ( function ( $domain ) {
return str ( $domain ) -> trim () -> lower ();
});
$this -> application -> fqdn = $this -> application -> fqdn -> unique () -> implode ( ',' );
2024-04-10 06:21:06 +00:00
$this -> resetDefaultLabels ();
}
2023-10-18 08:32:08 +00:00
public function updatedApplicationBuildPack ()
{
2023-10-13 19:08:59 +00:00
if ( $this -> application -> build_pack !== 'nixpacks' ) {
2023-12-06 20:32:23 +00:00
$this -> application -> settings -> is_static = false ;
2023-10-13 19:08:59 +00:00
$this -> application -> settings -> save ();
2024-01-10 10:00:06 +00:00
} else {
$this -> application -> ports_exposes = $this -> ports_exposes = 3000 ;
$this -> resetDefaultLabels ( false );
2023-10-13 19:08:59 +00:00
}
2023-11-27 14:25:15 +00:00
if ( $this -> application -> build_pack === 'dockercompose' ) {
$this -> application -> fqdn = null ;
$this -> application -> settings -> save ();
}
2024-01-10 09:58:31 +00:00
if ( $this -> application -> build_pack === 'static' ) {
$this -> application -> ports_exposes = $this -> ports_exposes = 80 ;
$this -> resetDefaultLabels ( false );
}
2023-10-11 10:12:25 +00:00
$this -> submit ();
2024-03-01 09:36:32 +00:00
$this -> dispatch ( 'buildPackUpdated' );
2023-10-11 10:12:25 +00:00
}
2023-10-18 08:32:08 +00:00
public function getWildcardDomain ()
{
2023-09-30 13:39:40 +00:00
$server = data_get ( $this -> application , 'destination.server' );
if ( $server ) {
$fqdn = generateFqdn ( $server , $this -> application -> uuid );
$this -> application -> fqdn = $fqdn ;
$this -> application -> save ();
2024-04-10 06:21:06 +00:00
$this -> resetDefaultLabels ();
2024-04-08 10:15:44 +00:00
$this -> dispatch ( 'success' , 'Wildcard domain generated.' );
2023-09-30 13:39:40 +00:00
}
}
2024-04-08 10:15:44 +00:00
public function resetDefaultLabels ()
2023-04-19 10:42:15 +00:00
{
2024-04-10 06:21:06 +00:00
ray ( 'resetDefaultLabels' );
2024-01-15 11:30:49 +00:00
$this -> customLabels = str ( implode ( " | " , generateLabelsApplication ( $this -> application ))) -> replace ( " | " , " \n " );
2023-10-20 10:34:25 +00:00
$this -> ports_exposes = $this -> application -> ports_exposes ;
2024-04-08 10:15:44 +00:00
$this -> application -> custom_labels = base64_encode ( $this -> customLabels );
$this -> application -> save ();
2023-04-19 10:42:15 +00:00
}
2023-08-08 09:51:36 +00:00
2024-04-08 10:15:44 +00:00
public function checkFqdns ( $showToaster = true )
2023-10-18 08:32:08 +00:00
{
2024-04-08 10:15:44 +00:00
if ( data_get ( $this -> application , 'fqdn' )) {
$domains = str ( $this -> application -> fqdn ) -> trim () -> explode ( ',' );
if ( $this -> application -> additional_servers -> count () === 0 ) {
foreach ( $domains as $domain ) {
if ( ! validate_dns_entry ( $domain , $this -> application -> destination -> server )) {
$showToaster && $this -> dispatch ( 'error' , " Validating DNS ( $domain ) failed. " , " Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help. " );
}
}
}
check_domain_usage ( resource : $this -> application );
$this -> application -> fqdn = $domains -> implode ( ',' );
}
2023-10-18 08:32:08 +00:00
}
public function submit ( $showToaster = true )
2023-04-19 10:42:15 +00:00
{
2023-05-16 13:27:47 +00:00
try {
2024-04-08 10:15:44 +00:00
$this -> application -> fqdn = str ( $this -> application -> fqdn ) -> replaceEnd ( ',' , '' ) -> trim ();
$this -> application -> fqdn = str ( $this -> application -> fqdn ) -> replaceStart ( ',' , '' ) -> trim ();
$this -> application -> fqdn = str ( $this -> application -> fqdn ) -> trim () -> explode ( ',' ) -> map ( function ( $domain ) {
return str ( $domain ) -> trim () -> lower ();
});
$this -> application -> fqdn = $this -> application -> fqdn -> unique () -> implode ( ',' );
$this -> checkFqdns ();
$this -> application -> save ();
2024-03-11 14:08:05 +00:00
if ( ! $this -> customLabels && $this -> application -> destination -> server -> proxyType () !== 'NONE' ) {
2024-01-15 11:30:49 +00:00
$this -> customLabels = str ( implode ( " | " , generateLabelsApplication ( $this -> application ))) -> replace ( " | " , " \n " );
2024-01-02 16:14:52 +00:00
$this -> application -> custom_labels = base64_encode ( $this -> customLabels );
$this -> application -> save ();
}
2023-12-17 19:56:12 +00:00
if ( $this -> application -> build_pack === 'dockercompose' && $this -> initialDockerComposeLocation !== $this -> application -> docker_compose_location ) {
2023-11-27 10:54:55 +00:00
$this -> loadComposeFile ();
}
2023-09-20 13:42:41 +00:00
$this -> validate ();
2023-10-20 10:34:25 +00:00
if ( $this -> ports_exposes !== $this -> application -> ports_exposes ) {
2024-04-08 10:15:44 +00:00
$this -> resetDefaultLabels ();
2023-10-20 10:34:25 +00:00
}
2023-10-18 08:32:08 +00:00
if ( data_get ( $this -> application , 'build_pack' ) === 'dockerimage' ) {
2023-10-11 10:10:40 +00:00
$this -> validate ([
'application.docker_registry_image_name' => 'required' ,
]);
}
2024-04-08 10:15:44 +00:00
2024-01-29 15:07:00 +00:00
if ( data_get ( $this -> application , 'custom_docker_run_options' )) {
$this -> application -> custom_docker_run_options = str ( $this -> application -> custom_docker_run_options ) -> trim ();
}
2023-09-19 13:51:13 +00:00
if ( data_get ( $this -> application , 'dockerfile' )) {
2023-08-21 16:00:12 +00:00
$port = get_port_from_dockerfile ( $this -> application -> dockerfile );
2023-10-02 07:08:33 +00:00
if ( $port && ! $this -> application -> ports_exposes ) {
2023-08-21 16:00:12 +00:00
$this -> application -> ports_exposes = $port ;
}
2023-08-11 20:41:47 +00:00
}
2023-07-07 12:56:20 +00:00
if ( $this -> application -> base_directory && $this -> application -> base_directory !== '/' ) {
$this -> application -> base_directory = rtrim ( $this -> application -> base_directory , '/' );
}
if ( $this -> application -> publish_directory && $this -> application -> publish_directory !== '/' ) {
$this -> application -> publish_directory = rtrim ( $this -> application -> publish_directory , '/' );
}
2023-11-28 10:10:48 +00:00
if ( $this -> application -> build_pack === 'dockercompose' ) {
$this -> application -> docker_compose_domains = json_encode ( $this -> parsedServiceDomains );
2024-04-08 10:15:44 +00:00
foreach ( $this -> parsedServiceDomains as $serviceName => $service ) {
$domain = data_get ( $service , 'domain' );
if ( $domain ) {
if ( ! validate_dns_entry ( $domain , $this -> application -> destination -> server )) {
$showToaster && $this -> dispatch ( 'error' , " Validating DNS ( $domain ) failed. " , " Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/dns-configuration'>documentation</a> for further help. " );
}
check_domain_usage ( resource : $this -> application );
}
}
2023-11-28 10:10:48 +00:00
}
2023-12-12 15:34:05 +00:00
$this -> application -> custom_labels = base64_encode ( $this -> customLabels );
2023-05-16 13:27:47 +00:00
$this -> application -> save ();
2023-12-07 18:06:32 +00:00
$showToaster && $this -> dispatch ( 'success' , 'Application settings updated!' );
2023-09-11 15:36:30 +00:00
} catch ( \Throwable $e ) {
2023-09-15 13:34:25 +00:00
return handleError ( $e , $this );
2023-10-18 08:32:08 +00:00
} finally {
2024-04-12 10:44:49 +00:00
$this -> dispatch ( 'configurationChanged' );
2023-05-16 13:27:47 +00:00
}
2023-04-19 10:42:15 +00:00
}
}