diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 725b8cbc0..798c46b2b 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -78,6 +78,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted private string $dockerConfigFileExists = 'NOK'; private int $customPort = 22; + private ?string $customRepository = null; private ?string $fullRepoUrl = null; private ?string $branch = null; @@ -193,7 +194,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $this->customPort = $matches[0]; $gitHost = str($this->application->git_repository)->before(':'); $gitRepo = str($this->application->git_repository)->after('/'); - $this->application->git_repository = "$gitHost:$gitRepo"; + $this->customRepository = "$gitHost:$gitRepo"; + } else { + $this->customRepository = $this->application->git_repository; } try { if ($this->restart_only) { @@ -258,7 +261,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted // executeInDocker($this->deployment_uuid, "echo '$dockercompose_base64' | base64 -d > $this->workdir/docker-compose.yaml") // ], // ); - // $this->build_image_name = Str::lower("{$this->application->git_repository}:build"); + // $this->build_image_name = Str::lower("{$this->customRepository}:build"); // $this->production_image_name = Str::lower("{$this->application->uuid}:latest"); // $this->save_environment_variables(); // $containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id); @@ -283,7 +286,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted private function generate_image_names() { if ($this->application->dockerfile) { - $this->build_image_name = Str::lower("{$this->application->git_repository}:build"); + $this->build_image_name = Str::lower("{$this->application->uuid}:build"); $this->production_image_name = Str::lower("{$this->application->uuid}:latest"); } else if ($this->application->build_pack === 'dockerimage') { $this->production_image_name = Str::lower("{$this->dockerImage}:{$this->dockerImageTag}"); @@ -295,7 +298,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if (strlen($tag) > 128) { $tag = $tag->substr(0, 128); } - $this->build_image_name = Str::lower("{$this->application->git_repository}:{$tag}-build"); + $this->build_image_name = Str::lower("{$this->application->uuid}:{$tag}-build"); $this->production_image_name = Str::lower("{$this->application->uuid}:{$tag}"); } } @@ -303,7 +306,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted { $this->execute_remote_command( [ - "echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}.'" + "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'" ], ); $this->prepare_builder_image(); @@ -380,7 +383,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted } $this->execute_remote_command( [ - "echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}.'" + "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'" ], ); $this->prepare_builder_image(); @@ -399,7 +402,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted { $this->execute_remote_command( [ - "echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}.'" + "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'" ], ); $this->prepare_builder_image(); @@ -501,7 +504,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted { $this->generate_image_names(); $this->execute_remote_command([ - "echo 'Starting pull request (#{$this->pull_request_id}) deployment of {$this->application->git_repository}:{$this->application->git_branch}.'", + "echo 'Starting pull request (#{$this->pull_request_id}) deployment of {$this->customRepository}:{$this->application->git_branch}.'", ]); $this->prepare_builder_image(); $this->clone_repository(); @@ -599,7 +602,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted $importCommands = $this->generate_git_import_commands(); $this->execute_remote_command( [ - "echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}. '" + "echo -n 'Importing {$this->customRepository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}. '" ], [ $importCommands, "hidden" => true @@ -624,15 +627,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted if ($this->source->getMorphClass() == 'App\Models\GithubApp') { if ($this->source->is_public) { - $this->fullRepoUrl = "{$this->source->html_url}/{$this->application->git_repository}"; - $git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->basedir}"; + $this->fullRepoUrl = "{$this->source->html_url}/{$this->customRepository}"; + $git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->customRepository} {$this->basedir}"; $git_clone_command = $this->set_git_import_settings($git_clone_command); $commands->push(executeInDocker($this->deployment_uuid, $git_clone_command)); } else { $github_access_token = generate_github_installation_token($this->source); - $commands->push(executeInDocker($this->deployment_uuid, "git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->basedir}")); - $this->fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git"; + $commands->push(executeInDocker($this->deployment_uuid, "git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->customRepository}.git {$this->basedir}")); + $this->fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->customRepository}.git"; } if ($this->pull_request_id !== 0) { $this->branch = "pull/{$this->pull_request_id}/head:$pr_branch_name"; @@ -642,13 +645,13 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted } } if ($this->application->deploymentType() === 'deploy_key') { - $this->fullRepoUrl = $this->application->git_repository; + $this->fullRepoUrl = $this->customRepository; $private_key = data_get($this->application, 'private_key.private_key'); if (is_null($private_key)) { throw new Exception('Private key not found. Please add a private key to the application and try again.'); } $private_key = base64_encode($private_key); - $git_clone_command = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_repository} {$this->basedir}"; + $git_clone_command = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->customRepository} {$this->basedir}"; $git_clone_command = $this->set_git_import_settings($git_clone_command); $commands = collect([ executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh"), @@ -659,8 +662,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted return $commands->implode(' && '); } if ($this->application->deploymentType() === 'other') { - $this->fullRepoUrl = $this->application->git_repository; - $git_clone_command = "{$git_clone_command} {$this->application->git_repository} {$this->basedir}"; + $this->fullRepoUrl = $this->customRepository; + $git_clone_command = "{$git_clone_command} {$this->customRepository} {$this->basedir}"; $git_clone_command = $this->set_git_import_settings($git_clone_command); $commands->push(executeInDocker($this->deployment_uuid, $git_clone_command)); return $commands->implode(' && '); diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 94e907834..dc596c65c 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -36,6 +36,7 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted public StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|ServiceDatabase $database; public ?string $container_name = null; + public ?string $directory_name = null; public ?ScheduledDatabaseBackupExecution $backup_log = null; public string $backup_status = 'failed'; public ?string $backup_location = null; @@ -88,27 +89,98 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted if (data_get($this->backup, 'database_type') === 'App\Models\ServiceDatabase') { $databaseType = $this->database->databaseType(); $serviceUuid = $this->database->service->uuid; + $serviceName = str($this->database->service->name)->slug(); if ($databaseType === 'standalone-postgresql') { - $this->container_name = "postgresql-$serviceUuid"; + $this->container_name = "{$this->database->name}-$serviceUuid"; + $this->directory_name = $serviceName . '-' . $this->container_name; $commands[] = "docker exec $this->container_name env | grep POSTGRES_"; $envs = instant_remote_process($commands, $this->server); - $databasesToBackup = Str::of($envs)->after('POSTGRES_DB=')->before("\n")->value(); - $this->database->postgres_user = Str::of($envs)->after('POSTGRES_USER=')->before("\n")->value(); + $envs = str($envs)->explode("\n"); + + $user = $envs->filter(function ($env) { + return str($env)->startsWith('POSTGRES_USER='); + })->first(); + if ($user) { + $this->database->postgres_user = str($user)->after('POSTGRES_USER=')->value(); + } else { + $this->database->postgres_user = 'postgres'; + } + + $db = $envs->filter(function ($env) { + return str($env)->startsWith('POSTGRES_DB='); + })->first(); + + if ($db) { + $databasesToBackup = str($db)->after('POSTGRES_DB=')->value(); + } else { + throw new \Exception('POSTGRES_DB not found'); + } } else if ($databaseType === 'standalone-mysql') { - $this->container_name = "mysql-$serviceUuid"; + $this->container_name = "{$this->database->name}-$serviceUuid"; + $this->directory_name = $serviceName . '-' . $this->container_name; $commands[] = "docker exec $this->container_name env | grep MYSQL_"; $envs = instant_remote_process($commands, $this->server); - $databasesToBackup = Str::of($envs)->after('MYSQL_DATABASE=')->before("\n")->value(); - $this->database->mysql_root_password = Str::of($envs)->after('MYSQL_ROOT_PASSWORD=')->before("\n")->value(); + $envs = str($envs)->explode("\n"); + + $rootPassword = $envs->filter(function ($env) { + return str($env)->startsWith('MYSQL_ROOT_PASSWORD='); + })->first(); + if ($rootPassword) { + $this->database->mysql_root_password = str($rootPassword)->after('MYSQL_ROOT_PASSWORD=')->value(); + } + + $db = $envs->filter(function ($env) { + return str($env)->startsWith('MYSQL_DATABASE='); + })->first(); + + if ($db) { + $databasesToBackup = str($db)->after('MYSQL_DATABASE=')->value(); + } else { + throw new \Exception('MYSQL_DATABASE not found'); + } } else if ($databaseType === 'standalone-mariadb') { - $this->container_name = "mariadb-$serviceUuid"; + $this->container_name = "{$this->database->name}-$serviceUuid"; + $this->directory_name = $serviceName . '-' . $this->container_name; $commands[] = "docker exec $this->container_name env | grep MARIADB_"; $envs = instant_remote_process($commands, $this->server); - $databasesToBackup = Str::of($envs)->after('MARIADB_DATABASE=')->before("\n")->value(); - $this->database->mysql_root_password = Str::of($envs)->after('MARIADB_ROOT_PASSWORD=')->before("\n")->value(); + $envs = str($envs)->explode("\n"); + + $rootPassword = $envs->filter(function ($env) { + return str($env)->startsWith('MARIADB_ROOT_PASSWORD='); + })->first(); + if ($rootPassword) { + $this->database->mysql_root_password = str($rootPassword)->after('MARIADB_ROOT_PASSWORD=')->value(); + } else { + $rootPassword = $envs->filter(function ($env) { + return str($env)->startsWith('MYSQL_ROOT_PASSWORD='); + })->first(); + if ($rootPassword) { + $this->database->mysql_root_password = str($rootPassword)->after('MYSQL_ROOT_PASSWORD=')->value(); + } + } + + $db = $envs->filter(function ($env) { + return str($env)->startsWith('MARIADB_DATABASE='); + })->first(); + + if ($db) { + $databasesToBackup = str($db)->after('MARIADB_DATABASE=')->value(); + } else { + $db = $envs->filter(function ($env) { + return str($env)->startsWith('MYSQL_DATABASE='); + })->first(); + + if ($db) { + $databasesToBackup = str($db)->after('MYSQL_DATABASE=')->value(); + } else { + throw new \Exception('MARIADB_DATABASE or MYSQL_DATABASE not found'); + } + } } } else { + $databaseName = str($this->database->name)->slug()->value(); $this->container_name = $this->database->uuid; + $this->directory_name = $databaseName . '-' . $this->container_name; $databaseType = $this->database->type(); $databasesToBackup = data_get($this->backup, 'databases_to_backup'); } @@ -147,11 +219,11 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted return; } } - $this->backup_dir = backup_dir() . "/databases/" . Str::of($this->team->name)->slug() . '-' . $this->team->id . '/' . $this->container_name; + $this->backup_dir = backup_dir() . "/databases/" . Str::of($this->team->name)->slug() . '-' . $this->team->id . '/' . $this->directory_name; if ($this->database->name === 'coolify-db') { $databasesToBackup = ['coolify']; - $this->container_name = "coolify-db"; + $this->directory_name = $this->container_name = "coolify-db"; $ip = Str::slug($this->server->ip); $this->backup_dir = backup_dir() . "/coolify" . "/coolify-db-$ip"; } diff --git a/config/sentry.php b/config/sentry.php index e6e07d06b..180d98f99 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -7,7 +7,7 @@ return [ // The release version of your application // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) - 'release' => '4.0.0-beta.113', + 'release' => '4.0.0-beta.114', // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index ef861eb3a..aee7423ea 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ Storages - Backups + @if ( + $serviceDatabase->databaseType() === 'standalone-mysql' || + $serviceDatabase->databaseType() === 'standalone-postgresql' || + $serviceDatabase->databaseType() === 'standalone-mariadb') + Backups + @endif @if (data_get($parameters, 'service_name')) diff --git a/versions.json b/versions.json index d2db97a80..7dcd59a4f 100644 --- a/versions.json +++ b/versions.json @@ -4,7 +4,7 @@ "version": "3.12.36" }, "v4": { - "version": "4.0.0-beta.113" + "version": "4.0.0-beta.114" } } }