wip: services
This commit is contained in:
parent
145af41c82
commit
a86e971020
@ -7,12 +7,14 @@
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Spatie\Url\Url;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class General extends Component
|
||||
{
|
||||
public string $applicationId;
|
||||
|
||||
public Application $application;
|
||||
public ?array $services = null;
|
||||
public string $name;
|
||||
public string|null $fqdn;
|
||||
public string $git_repository;
|
||||
@ -31,6 +33,7 @@ class General extends Component
|
||||
public bool $is_auto_deploy_enabled;
|
||||
public bool $is_force_https_enabled;
|
||||
|
||||
|
||||
protected $rules = [
|
||||
'application.name' => 'required',
|
||||
'application.description' => 'nullable',
|
||||
@ -48,6 +51,9 @@ class General extends Component
|
||||
'application.ports_exposes' => 'required',
|
||||
'application.ports_mappings' => 'nullable',
|
||||
'application.dockerfile' => 'nullable',
|
||||
'application.dockercompose_raw' => 'nullable',
|
||||
'application.dockercompose' => 'nullable',
|
||||
'application.service_configurations.*' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'application.name' => 'name',
|
||||
@ -66,6 +72,9 @@ class General extends Component
|
||||
'application.ports_exposes' => 'Ports exposes',
|
||||
'application.ports_mappings' => 'Ports mappings',
|
||||
'application.dockerfile' => 'Dockerfile',
|
||||
'application.dockercompose_raw' => 'Docker Compose (raw)',
|
||||
'application.dockercompose' => 'Docker Compose',
|
||||
|
||||
];
|
||||
|
||||
public function instantSave()
|
||||
@ -108,6 +117,9 @@ public function mount()
|
||||
$this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled;
|
||||
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
|
||||
$this->checkWildCardDomain();
|
||||
if (data_get($this->application, 'dockercompose_raw')) {
|
||||
$this->services = data_get(Yaml::parse($this->application->dockercompose_raw), 'services');
|
||||
}
|
||||
}
|
||||
|
||||
public function generateGlobalRandomDomain()
|
||||
@ -136,16 +148,16 @@ public function generateServerRandomDomain()
|
||||
|
||||
public function submit()
|
||||
{
|
||||
ray($this->application);
|
||||
try {
|
||||
$this->validate();
|
||||
if (data_get($this->application,'fqdn')) {
|
||||
ray($this->application->service_configurations);
|
||||
// $this->validate();
|
||||
if (data_get($this->application, 'fqdn')) {
|
||||
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
||||
return Str::of($domain)->trim()->lower();
|
||||
});
|
||||
$this->application->fqdn = $domains->implode(',');
|
||||
}
|
||||
if ($this->application->dockerfile) {
|
||||
if (data_get($this->application, 'dockerfile')) {
|
||||
$port = get_port_from_dockerfile($this->application->dockerfile);
|
||||
if ($port) {
|
||||
$this->application->ports_exposes = $port;
|
||||
@ -157,6 +169,10 @@ public function submit()
|
||||
if ($this->application->publish_directory && $this->application->publish_directory !== '/') {
|
||||
$this->application->publish_directory = rtrim($this->application->publish_directory, '/');
|
||||
}
|
||||
if (data_get($this->application, 'dockercompose_raw')) {
|
||||
$details = generateServiceFromTemplate($this->application->dockercompose_raw, $this->application);
|
||||
$this->application->dockercompose = data_get($details, 'dockercompose');
|
||||
}
|
||||
$this->application->save();
|
||||
$this->emit('success', 'Application settings updated!');
|
||||
} catch (\Throwable $e) {
|
||||
|
@ -21,7 +21,7 @@ public function mount()
|
||||
|
||||
public function check_status()
|
||||
{
|
||||
dispatch_sync(new ContainerStatusJob($this->application->destination->server));
|
||||
dispatch(new ContainerStatusJob($this->application->destination->server));
|
||||
$this->application->refresh();
|
||||
$this->application->previews->each(function ($preview) {
|
||||
$preview->refresh();
|
||||
|
@ -72,7 +72,7 @@ protected function setDeploymentUuid()
|
||||
public function stop(int $pull_request_id)
|
||||
{
|
||||
try {
|
||||
$container_name = generateApplicationContainerName($this->application->uuid, $pull_request_id);
|
||||
$container_name = generateApplicationContainerName($this->application);
|
||||
ray('Stopping container: ' . $container_name);
|
||||
|
||||
instant_remote_process(["docker rm -f $container_name"], $this->application->destination->server, throwError: false);
|
||||
|
137
app/Http/Livewire/Project/New/DockerCompose.php
Normal file
137
app/Http/Livewire/Project/New/DockerCompose.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Livewire\Project\New;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\EnvironmentVariable;
|
||||
use App\Models\GithubApp;
|
||||
use App\Models\LocalPersistentVolume;
|
||||
use App\Models\Project;
|
||||
use App\Models\StandaloneDocker;
|
||||
use App\Models\SwarmDocker;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DockerCompose extends Component
|
||||
{
|
||||
public string $dockercompose = '';
|
||||
public array $parameters;
|
||||
public array $query;
|
||||
public function mount()
|
||||
{
|
||||
$this->parameters = get_route_parameters();
|
||||
$this->query = request()->query();
|
||||
if (isDev()) {
|
||||
$this->dockercompose = 'services:
|
||||
ghost:
|
||||
documentation: https://docs.ghost.org/docs/config
|
||||
image: ghost:5
|
||||
volumes:
|
||||
- ghost-content-data:/var/lib/ghost/content
|
||||
environment:
|
||||
- url=$SERVICE_FQDN_GHOST
|
||||
- database__client=mysql
|
||||
- database__connection__host=mysql
|
||||
- database__connection__user=$SERVICE_USER_MYSQL
|
||||
- database__connection__password=$SERVICE_PASSWORD_MYSQL
|
||||
- database__connection__database=${MYSQL_DATABASE-ghost}
|
||||
ports:
|
||||
- "2368"
|
||||
depends_on:
|
||||
- mysql
|
||||
mysql:
|
||||
documentation: https://hub.docker.com/_/mysql
|
||||
image: mysql:8.0
|
||||
volumes:
|
||||
- ghost-mysql-data:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
||||
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL_ROOT}
|
||||
';
|
||||
}
|
||||
}
|
||||
public function submit()
|
||||
{
|
||||
$this->validate([
|
||||
'dockercompose' => 'required'
|
||||
]);
|
||||
$destination_uuid = $this->query['destination'];
|
||||
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
||||
if (!$destination) {
|
||||
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
||||
}
|
||||
if (!$destination) {
|
||||
throw new \Exception('Destination not found. What?!');
|
||||
}
|
||||
$destination_class = $destination->getMorphClass();
|
||||
|
||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||
$application = Application::create([
|
||||
'name' => 'dockercompose-' . new Cuid2(7),
|
||||
'repository_project_id' => 0,
|
||||
'fqdn' => 'https://app.coolify.io',
|
||||
'git_repository' => "coollabsio/coolify",
|
||||
'git_branch' => 'main',
|
||||
'build_pack' => 'dockercompose',
|
||||
'ports_exposes' => '0',
|
||||
'dockercompose_raw' => $this->dockercompose,
|
||||
'environment_id' => $environment->id,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_type' => $destination_class,
|
||||
'source_id' => 0,
|
||||
'source_type' => GithubApp::class
|
||||
]);
|
||||
$fqdn = "http://{$application->uuid}.{$destination->server->ip}.sslip.io";
|
||||
if (isDev()) {
|
||||
$fqdn = "http://{$application->uuid}.127.0.0.1.sslip.io";
|
||||
}
|
||||
$application->update([
|
||||
'name' => 'dockercompose-' . $application->uuid,
|
||||
'fqdn' => $fqdn,
|
||||
]);
|
||||
|
||||
$details = generateServiceFromTemplate($this->dockercompose, $application);
|
||||
$envs = data_get($details, 'envs', []);
|
||||
if ($envs->count() > 0) {
|
||||
foreach ($envs as $env) {
|
||||
$key = Str::of($env)->before('=');
|
||||
$value = Str::of($env)->after('=');
|
||||
EnvironmentVariable::create([
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
'is_build_time' => false,
|
||||
'application_id' => $application->id,
|
||||
'is_preview' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$volumes = data_get($details, 'volumes', []);
|
||||
if ($volumes->count() > 0) {
|
||||
foreach ($volumes as $volume => $mount_path) {
|
||||
LocalPersistentVolume::create([
|
||||
'name' => $volume,
|
||||
'mount_path' => $mount_path,
|
||||
'resource_id' => $application->id,
|
||||
'resource_type' => $application->getMorphClass(),
|
||||
'is_readonly' => false
|
||||
]);
|
||||
}
|
||||
}
|
||||
$dockercompose_coolified = data_get($details, 'dockercompose', '');
|
||||
$application->update([
|
||||
'dockercompose' => $dockercompose_coolified,
|
||||
'ports_exposes' => data_get($details, 'ports', 0)->implode(','),
|
||||
]);
|
||||
|
||||
|
||||
redirect()->route('project.application.configuration', [
|
||||
'application_uuid' => $application->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
'project_uuid' => $project->uuid,
|
||||
]);
|
||||
}
|
||||
}
|
@ -9,8 +9,8 @@
|
||||
use App\Models\SwarmDocker;
|
||||
use App\Traits\SaveFromRedirect;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Livewire\Component;
|
||||
use Route;
|
||||
|
||||
class GithubPrivateRepository extends Component
|
||||
{
|
||||
@ -40,21 +40,6 @@ class GithubPrivateRepository extends Component
|
||||
public string|null $publish_directory = null;
|
||||
protected int $page = 1;
|
||||
|
||||
// public function saveFromRedirect(string $route, ?Collection $parameters = null){
|
||||
// session()->forget('from');
|
||||
// if (!$parameters || $parameters->count() === 0) {
|
||||
// $parameters = $this->parameters;
|
||||
// }
|
||||
// $parameters = collect($parameters) ?? collect([]);
|
||||
// $queries = collect($this->query) ?? collect([]);
|
||||
// $parameters = $parameters->merge($queries);
|
||||
// session(['from'=> [
|
||||
// 'back'=> $this->currentRoute,
|
||||
// 'route' => $route,
|
||||
// 'parameters' => $parameters
|
||||
// ]]);
|
||||
// return redirect()->route($route);
|
||||
// }
|
||||
|
||||
public function mount()
|
||||
{
|
||||
@ -159,6 +144,13 @@ public function submit()
|
||||
$application->settings->is_static = $this->is_static;
|
||||
$application->settings->save();
|
||||
|
||||
$application->fqdn = "http://{$application->uuid}.{$destination->server->ip}.sslip.io";
|
||||
if (isDev()) {
|
||||
$application->fqdn = "http://{$application->uuid}.127.0.0.1.sslip.io";
|
||||
}
|
||||
$application->name = generate_application_name($this->selected_repository_owner . '/' . $this->selected_repository_repo, $this->selected_branch_name, $application->uuid);
|
||||
$application->save();
|
||||
|
||||
redirect()->route('project.application.configuration', [
|
||||
'application_uuid' => $application->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
|
@ -112,6 +112,13 @@ public function submit()
|
||||
$application->settings->is_static = $this->is_static;
|
||||
$application->settings->save();
|
||||
|
||||
$application->fqdn = "http://{$application->uuid}.{$destination->server->ip}.sslip.io";
|
||||
if (isDev()) {
|
||||
$application->fqdn = "http://{$application->uuid}.127.0.0.1.sslip.io";
|
||||
}
|
||||
$application->name = generate_random_name($application->uuid);
|
||||
$application->save();
|
||||
|
||||
return redirect()->route('project.application.configuration', [
|
||||
'project_uuid' => $project->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
|
@ -69,12 +69,12 @@ public function load_branch()
|
||||
{
|
||||
try {
|
||||
$this->branch_found = false;
|
||||
$this->validate([
|
||||
'repository_url' => 'required|url'
|
||||
]);
|
||||
$this->get_git_source();
|
||||
$this->get_branch();
|
||||
$this->selected_branch = $this->git_branch;
|
||||
$this->validate([
|
||||
'repository_url' => 'required|url'
|
||||
]);
|
||||
$this->get_git_source();
|
||||
$this->get_branch();
|
||||
$this->selected_branch = $this->git_branch;
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@ -137,7 +137,6 @@ public function submit()
|
||||
$project = Project::where('uuid', $project_uuid)->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', $environment_name)->first();
|
||||
|
||||
|
||||
$application_init = [
|
||||
'name' => generate_application_name($this->git_repository, $this->git_branch),
|
||||
'git_repository' => $this->git_repository,
|
||||
@ -153,9 +152,17 @@ public function submit()
|
||||
];
|
||||
|
||||
$application = Application::create($application_init);
|
||||
|
||||
$application->settings->is_static = $this->is_static;
|
||||
$application->settings->save();
|
||||
|
||||
$application->fqdn = "http://{$application->uuid}.{$destination->server->ip}.sslip.io";
|
||||
if (isDev()) {
|
||||
$application->fqdn = "http://{$application->uuid}.127.0.0.1.sslip.io";
|
||||
}
|
||||
$application->name = generate_application_name($this->git_repository, $this->git_branch, $application->uuid);
|
||||
$application->save();
|
||||
|
||||
return redirect()->route('project.application.configuration', [
|
||||
'project_uuid' => $project->uuid,
|
||||
'environment_name' => $environment->name,
|
||||
|
@ -59,8 +59,14 @@ public function submit()
|
||||
'source_id' => 0,
|
||||
'source_type' => GithubApp::class
|
||||
]);
|
||||
|
||||
$fqdn = "http://{$application->uuid}.{$destination->server->ip}.sslip.io";
|
||||
if (isDev()) {
|
||||
$fqdn = "http://{$application->uuid}.127.0.0.1.sslip.io";
|
||||
}
|
||||
$application->update([
|
||||
'name' => 'dockerfile-' . $application->id
|
||||
'name' => 'dockerfile-' . $application->uuid,
|
||||
'fqdn' => $fqdn
|
||||
]);
|
||||
|
||||
redirect()->route('project.application.configuration', [
|
||||
|
@ -88,7 +88,7 @@ public function __construct(int $application_deployment_queue_id)
|
||||
$this->build_workdir = "{$this->workdir}" . rtrim($this->application->base_directory, '/');
|
||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
||||
|
||||
$this->container_name = generateApplicationContainerName($this->application->uuid, $this->pull_request_id);
|
||||
$this->container_name = generateApplicationContainerName($this->application);
|
||||
savePrivateKeyToFs($this->server);
|
||||
$this->saved_outputs = collect();
|
||||
|
||||
@ -128,6 +128,8 @@ public function handle(): void
|
||||
try {
|
||||
if ($this->application->dockerfile) {
|
||||
$this->deploy_simple_dockerfile();
|
||||
} else if($this->application->dockercompose) {
|
||||
$this->deploy_docker_compose();
|
||||
} else {
|
||||
if ($this->pull_request_id !== 0) {
|
||||
$this->deploy_pull_request();
|
||||
@ -166,6 +168,37 @@ public function handle(): void
|
||||
);
|
||||
}
|
||||
}
|
||||
private function deploy_docker_compose() {
|
||||
$dockercompose_base64 = base64_encode($this->application->dockercompose);
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo 'Starting deployment of {$this->application->name}.'"
|
||||
],
|
||||
);
|
||||
$this->prepare_builder_image();
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
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->production_image_name = Str::lower("{$this->application->uuid}:latest");
|
||||
$this->save_environment_variables();
|
||||
$this->start_by_compose_file();
|
||||
}
|
||||
private function save_environment_variables() {
|
||||
$envs = collect([]);
|
||||
foreach ($this->application->environment_variables as $env) {
|
||||
$envs->push($env->key . '=' . $env->value);
|
||||
}
|
||||
$envs_base64 = base64_encode($envs->implode("\n"));
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d > $this->workdir/.env")
|
||||
],
|
||||
);
|
||||
|
||||
}
|
||||
private function deploy_simple_dockerfile()
|
||||
{
|
||||
$dockerfile_base64 = base64_encode($this->application->dockerfile);
|
||||
@ -475,7 +508,7 @@ private function generate_compose_file()
|
||||
'container_name' => $this->container_name,
|
||||
'restart' => RESTART_MODE,
|
||||
'environment' => $environment_variables,
|
||||
'labels' => $this->set_labels_for_applications(),
|
||||
'labels' => generateLabelsApplication($this->application, $this->preview),
|
||||
'expose' => $ports,
|
||||
'networks' => [
|
||||
$this->destination->network,
|
||||
|
@ -8,7 +8,6 @@
|
||||
use App\Notifications\Container\ContainerRestarted;
|
||||
use App\Notifications\Container\ContainerStopped;
|
||||
use App\Notifications\Server\Unreachable;
|
||||
use Arr;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
@ -17,6 +16,7 @@
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
||||
|
@ -226,7 +226,7 @@ public function could_set_build_commands(): bool
|
||||
}
|
||||
public function git_based(): bool
|
||||
{
|
||||
if ($this->dockerfile || $this->build_pack === 'dockerfile') {
|
||||
if ($this->dockerfile || $this->build_pack === 'dockerfile' || $this->dockercompose || $this->build_pack === 'dockercompose') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1,11 +1,15 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\ProxyTypes;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Url\Url;
|
||||
|
||||
function getCurrentApplicationContainerStatus(Server $server, int $id): Collection {
|
||||
function getCurrentApplicationContainerStatus(Server $server, int $id): Collection
|
||||
{
|
||||
$containers = instant_remote_process(["docker ps -a --filter='label=coolify.applicationId={$id}' --format '{{json .}}' "], $server);
|
||||
if (!$containers) {
|
||||
return collect([]);
|
||||
@ -26,7 +30,7 @@ function format_docker_command_output_to_json($rawOutput): Collection
|
||||
->map(fn ($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR));
|
||||
}
|
||||
|
||||
function format_docker_labels_to_json(string|Array $rawOutput): Collection
|
||||
function format_docker_labels_to_json(string|array $rawOutput): Collection
|
||||
{
|
||||
if (is_array($rawOutput)) {
|
||||
return collect($rawOutput);
|
||||
@ -59,7 +63,8 @@ function format_docker_envs_to_json($rawOutput)
|
||||
return collect([]);
|
||||
}
|
||||
}
|
||||
function checkMinimumDockerEngineVersion($dockerVersion) {
|
||||
function checkMinimumDockerEngineVersion($dockerVersion)
|
||||
{
|
||||
$majorDockerVersion = Str::of($dockerVersion)->before('.')->value();
|
||||
if ($majorDockerVersion <= 22) {
|
||||
$dockerVersion = null;
|
||||
@ -72,8 +77,9 @@ function executeInDocker(string $containerId, string $command)
|
||||
// return "docker exec {$this->deployment_uuid} bash -c '{$command} |& tee -a /proc/1/fd/1; [ \$PIPESTATUS -eq 0 ] || exit \$PIPESTATUS'";
|
||||
}
|
||||
|
||||
function getApplicationContainerStatus(Application $application) {
|
||||
$server = data_get($application,'destination.server');
|
||||
function getApplicationContainerStatus(Application $application)
|
||||
{
|
||||
$server = data_get($application, 'destination.server');
|
||||
$id = $application->id;
|
||||
if (!$server) {
|
||||
return 'exited';
|
||||
@ -98,13 +104,13 @@ function getContainerStatus(Server $server, string $container_id, bool $all_data
|
||||
return data_get($container[0], 'State.Status', 'exited');
|
||||
}
|
||||
|
||||
function generateApplicationContainerName(string $uuid, int $pull_request_id = 0)
|
||||
function generateApplicationContainerName(Application $application)
|
||||
{
|
||||
$now = now()->format('Hisu');
|
||||
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
||||
return $uuid . '-pr-' . $pull_request_id;
|
||||
if ($application->pull_request_id !== 0 && $application->pull_request_id !== null) {
|
||||
return $application->uuid . '-pr-' . $application->pull_request_id;
|
||||
} else {
|
||||
return $uuid . '-' . $now;
|
||||
return $application->uuid . '-' . $now;
|
||||
}
|
||||
}
|
||||
function get_port_from_dockerfile($dockerfile): int
|
||||
@ -123,3 +129,74 @@ function get_port_from_dockerfile($dockerfile): int
|
||||
}
|
||||
return 80;
|
||||
}
|
||||
|
||||
function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null)
|
||||
{
|
||||
|
||||
$pull_request_id = data_get($preview, 'pull_request_id', 0);
|
||||
$container_name = generateApplicationContainerName($application);
|
||||
$appId = $application->id;
|
||||
if ($pull_request_id !== 0) {
|
||||
$appId = $appId . '-pr-' . $application->pull_request_id;
|
||||
}
|
||||
$labels = [];
|
||||
$labels[] = 'coolify.managed=true';
|
||||
$labels[] = 'coolify.version=' . config('version');
|
||||
$labels[] = 'coolify.applicationId=' . $appId;
|
||||
$labels[] = 'coolify.type=application';
|
||||
$labels[] = 'coolify.name=' . $application->name;
|
||||
if ($pull_request_id !== 0) {
|
||||
$labels[] = 'coolify.pullRequestId=' . $pull_request_id;
|
||||
}
|
||||
if ($application->fqdn) {
|
||||
if ($pull_request_id !== 0) {
|
||||
$domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
|
||||
} else {
|
||||
$domains = Str::of(data_get($application, 'fqdn'))->explode(',');
|
||||
}
|
||||
if ($application->destination->server->proxy->type === ProxyTypes::TRAEFIK_V2->value) {
|
||||
$labels[] = 'traefik.enable=true';
|
||||
foreach ($domains as $domain) {
|
||||
$url = Url::fromString($domain);
|
||||
$host = $url->getHost();
|
||||
$path = $url->getPath();
|
||||
$schema = $url->getScheme();
|
||||
$slug = Str::slug($host . $path);
|
||||
|
||||
$http_label = "{$container_name}-{$slug}-http";
|
||||
$https_label = "{$container_name}-{$slug}-https";
|
||||
|
||||
if ($schema === 'https') {
|
||||
// Set labels for https
|
||||
$labels[] = "traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)";
|
||||
$labels[] = "traefik.http.routers.{$https_label}.entryPoints=https";
|
||||
$labels[] = "traefik.http.routers.{$https_label}.middlewares=gzip";
|
||||
if ($path !== '/') {
|
||||
$labels[] = "traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix";
|
||||
$labels[] = "traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}";
|
||||
}
|
||||
|
||||
$labels[] = "traefik.http.routers.{$https_label}.tls=true";
|
||||
$labels[] = "traefik.http.routers.{$https_label}.tls.certresolver=letsencrypt";
|
||||
|
||||
// Set labels for http (redirect to https)
|
||||
$labels[] = "traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)";
|
||||
$labels[] = "traefik.http.routers.{$http_label}.entryPoints=http";
|
||||
if ($application->settings->is_force_https_enabled) {
|
||||
$labels[] = "traefik.http.routers.{$http_label}.middlewares=redirect-to-https";
|
||||
}
|
||||
} else {
|
||||
// Set labels for http
|
||||
$labels[] = "traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)";
|
||||
$labels[] = "traefik.http.routers.{$http_label}.entryPoints=http";
|
||||
$labels[] = "traefik.http.routers.{$http_label}.middlewares=gzip";
|
||||
if ($path !== '/') {
|
||||
$labels[] = "traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix";
|
||||
$labels[] = "traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $labels;
|
||||
}
|
||||
|
185
bootstrap/helpers/services.php
Normal file
185
bootstrap/helpers/services.php
Normal file
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Application;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
# Application generated variables
|
||||
# SERVICE_FQDN_*: FQDN coming from your application (https://coolify.io)
|
||||
# SERVICE_URL_*: URL coming from your application (coolify.io)
|
||||
# SERVICE_USER_*: Generated by your application, username (not encrypted)
|
||||
# SERVICE_PASSWORD_*: Generated by your application, password (encrypted)
|
||||
|
||||
function generateServiceFromTemplate(string $template, Application $application)
|
||||
{
|
||||
// ray()->clearAll();
|
||||
|
||||
$template = Str::of($template);
|
||||
$network = data_get($application, 'destination.network');
|
||||
$yaml = Yaml::parse($template);
|
||||
$services = data_get($yaml, 'services');
|
||||
$volumes = collect(data_get($yaml, 'volumes', []));
|
||||
$composeVolumes = collect([]);
|
||||
$env = collect([]);
|
||||
$ports = collect([]);
|
||||
|
||||
foreach ($services as $serviceName => $service) {
|
||||
// Some default things
|
||||
data_set($service, 'restart', RESTART_MODE);
|
||||
data_set($service, 'container_name', generateApplicationContainerName($application));
|
||||
$healthcheck = data_get($service, 'healthcheck', []);
|
||||
if (is_null($healthcheck)) {
|
||||
$healthcheck = [
|
||||
'test' => [
|
||||
'CMD-SHELL',
|
||||
'exit 0'
|
||||
],
|
||||
'interval' => $application->health_check_interval . 's',
|
||||
'timeout' => $application->health_check_timeout . 's',
|
||||
'retries' => $application->health_check_retries,
|
||||
'start_period' => $application->health_check_start_period . 's'
|
||||
];
|
||||
data_set($service, 'healthcheck', $healthcheck);
|
||||
}
|
||||
|
||||
// Add volumes to the volumes collection if they don't already exist
|
||||
$serviceVolumes = collect(data_get($service, 'volumes', []));
|
||||
if ($serviceVolumes->count() > 0) {
|
||||
foreach ($serviceVolumes as $volume) {
|
||||
$volumeName = Str::before($volume, ':');
|
||||
$volumePath = Str::after($volume, ':');
|
||||
if (Str::startsWith($volumeName, '/')) {
|
||||
continue;
|
||||
}
|
||||
$volumeExists = $volumes->contains(function ($_, $key) use ($volumeName) {
|
||||
return $key == $volumeName;
|
||||
});
|
||||
if ($volumeExists) {
|
||||
ray('Volume already exists');
|
||||
} else {
|
||||
$composeVolumes->put($volumeName, null);
|
||||
$volumes->put($volumeName, $volumePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add networks to the networks collection if they don't already exist
|
||||
$serviceNetworks = collect(data_get($service, 'networks', []));
|
||||
$networkExists = $serviceNetworks->contains(function ($_, $key) use ($network) {
|
||||
return $key == $network;
|
||||
});
|
||||
if (is_null($networkExists) || !$networkExists) {
|
||||
$serviceNetworks->push($network);
|
||||
}
|
||||
data_set($service, 'networks', $serviceNetworks->toArray());
|
||||
data_set($yaml, "services.{$serviceName}", $service);
|
||||
|
||||
// Get variables from the service that does not start with SERVICE_*
|
||||
$serviceVariables = collect(data_get($service, 'environment', []));
|
||||
foreach ($serviceVariables as $variable) {
|
||||
$key = Str::before($variable, '=');
|
||||
$value = Str::after($variable, '=');
|
||||
if (!Str::startsWith($value, '$SERVICE_') && !Str::startsWith($value, '${SERVICE_') && Str::startsWith($value, '$')) {
|
||||
if (Str::of($value)->contains(':')) {
|
||||
$nakedName = replaceVariables(Str::of($value)->before(':'));
|
||||
$nakedValue = replaceVariables(Str::of($value)->after(':'));
|
||||
}
|
||||
if (Str::of($value)->contains('-')) {
|
||||
$nakedName = replaceVariables(Str::of($value)->before('-'));
|
||||
$nakedValue = replaceVariables(Str::of($value)->after('-'));
|
||||
}
|
||||
if (Str::of($value)->contains('+')) {
|
||||
$nakedName = replaceVariables(Str::of($value)->before('+'));
|
||||
$nakedValue = replaceVariables(Str::of($value)->after('+'));
|
||||
}
|
||||
if ($nakedValue->startsWith('-')) {
|
||||
$nakedValue = Str::of($nakedValue)->after('-');
|
||||
}
|
||||
if ($nakedValue->startsWith('+')) {
|
||||
$nakedValue = Str::of($nakedValue)->after('+');
|
||||
}
|
||||
if (!$env->contains("{$nakedName->value()}={$nakedValue->value()}")) {
|
||||
$env->push("$nakedName=$nakedValue");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get ports from the service
|
||||
$servicePorts = collect(data_get($service, 'ports', []));
|
||||
foreach ($servicePorts as $port) {
|
||||
$port = Str::of($port)->before(':');
|
||||
$ports->push($port);
|
||||
}
|
||||
}
|
||||
data_set($yaml, 'networks', [
|
||||
$network => [
|
||||
'name'=> $network
|
||||
],
|
||||
]);
|
||||
data_set($yaml, 'volumes', $composeVolumes->toArray());
|
||||
$compose = Str::of(Yaml::dump($yaml, 10, 2));
|
||||
|
||||
// Replace SERVICE_FQDN_* with the actual FQDN
|
||||
preg_match_all(collectRegex('SERVICE_FQDN_'), $compose, $fqdns);
|
||||
$fqdns = collect($fqdns)->flatten()->unique()->values();
|
||||
$generatedFqdns = collect([]);
|
||||
foreach ($fqdns as $fqdn) {
|
||||
$generatedFqdns->put("$fqdn", data_get($application, 'fqdn'));
|
||||
}
|
||||
|
||||
// Replace SERVICE_URL_*
|
||||
preg_match_all(collectRegex('SERVICE_URL_'), $compose, $urls);
|
||||
$urls = collect($urls)->flatten()->unique()->values();
|
||||
$generatedUrls = collect([]);
|
||||
foreach ($urls as $url) {
|
||||
$generatedUrls->put("$url", data_get($application, 'url'));
|
||||
}
|
||||
|
||||
// Generate SERVICE_USER_*
|
||||
preg_match_all(collectRegex('SERVICE_USER_'), $compose, $users);
|
||||
$users = collect($users)->flatten()->unique()->values();
|
||||
$generatedUsers = collect([]);
|
||||
foreach ($users as $user) {
|
||||
$generatedUsers->put("$user", Str::random(10));
|
||||
}
|
||||
|
||||
// Generate SERVICE_PASSWORD_*
|
||||
preg_match_all(collectRegex('SERVICE_PASSWORD_'), $compose, $passwords);
|
||||
$passwords = collect($passwords)->flatten()->unique()->values();
|
||||
$generatedPasswords = collect([]);
|
||||
foreach ($passwords as $password) {
|
||||
$generatedPasswords->put("$password", Str::password(symbols: false));
|
||||
}
|
||||
|
||||
// Save .env file
|
||||
foreach ($generatedFqdns as $key => $value) {
|
||||
$env->push("$key=$value");
|
||||
}
|
||||
foreach ($generatedUrls as $key => $value) {
|
||||
$env->push("$key=$value");
|
||||
}
|
||||
foreach ($generatedUsers as $key => $value) {
|
||||
$env->push("$key=$value");
|
||||
}
|
||||
foreach ($generatedPasswords as $key => $value) {
|
||||
$env->push("$key=$value");
|
||||
}
|
||||
return [
|
||||
'dockercompose' => $compose,
|
||||
'yaml' => Yaml::parse($compose),
|
||||
'envs' => $env,
|
||||
'volumes' => $volumes,
|
||||
'ports' => $ports->values(),
|
||||
];
|
||||
}
|
||||
|
||||
function replaceRegex(?string $name = null)
|
||||
{
|
||||
return "/\\\${?{$name}[^}]*}?|\\\${$name}\w+/";
|
||||
}
|
||||
function collectRegex(string $name)
|
||||
{
|
||||
return "/{$name}\w+/";
|
||||
}
|
||||
function replaceVariables($variable)
|
||||
{
|
||||
return $variable->replaceFirst('$', '')->replaceFirst('{', '')->replaceLast('}', '');
|
||||
}
|
@ -151,10 +151,12 @@ function get_latest_version_of_coolify(): string
|
||||
}
|
||||
}
|
||||
|
||||
function generate_random_name(): string
|
||||
function generate_random_name(?string $cuid = null): string
|
||||
{
|
||||
$generator = All::create();
|
||||
$cuid = new Cuid2(7);
|
||||
if (is_null($cuid)) {
|
||||
$cuid = new Cuid2(7);
|
||||
}
|
||||
return Str::kebab("{$generator->getName()}-$cuid");
|
||||
}
|
||||
function generateSSHKey()
|
||||
@ -173,9 +175,11 @@ function formatPrivateKey(string $privateKey)
|
||||
}
|
||||
return $privateKey;
|
||||
}
|
||||
function generate_application_name(string $git_repository, string $git_branch): string
|
||||
function generate_application_name(string $git_repository, string $git_branch, ?string $cuid = null): string
|
||||
{
|
||||
$cuid = new Cuid2(7);
|
||||
if (is_null($cuid)) {
|
||||
$cuid = new Cuid2(7);
|
||||
}
|
||||
return Str::kebab("$git_repository:$git_branch-$cuid");
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->longText('dockercompose_raw')->nullable();
|
||||
$table->longText('dockercompose')->nullable();
|
||||
$table->json('service_configurations')->nullable();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->dropColumn('dockercompose_raw');
|
||||
$table->dropColumn('dockercompose');
|
||||
$table->dropColumn('service_configurations');
|
||||
});
|
||||
}
|
||||
};
|
@ -1,41 +1,21 @@
|
||||
<div class="form-control">
|
||||
@if ($label)
|
||||
<label class="flex items-center gap-1 mb-1 text-sm font-medium">
|
||||
<span>
|
||||
@if ($label)
|
||||
{{ $label }}
|
||||
@else
|
||||
{{ $id }}
|
||||
@endif
|
||||
@if ($required)
|
||||
<x-highlighted text="*" />
|
||||
@endif
|
||||
@if ($helper)
|
||||
<div class="group">
|
||||
<div class="cursor-pointer text-warning">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
class="w-4 h-4 stroke-current">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="absolute hidden text-xs group-hover:block border-coolgray-400 bg-coolgray-500">
|
||||
<div class="p-4 card-body">
|
||||
{!! $helper !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</span>
|
||||
<label for="small-input" class="flex items-center gap-1 mb-1 text-sm font-medium">{{ $label }}
|
||||
@if ($required)
|
||||
<x-highlighted text="*" />
|
||||
@endif
|
||||
@if ($helper)
|
||||
<x-helper :helper="$helper" />
|
||||
@endif
|
||||
</label>
|
||||
@endif
|
||||
<textarea placeholder="{{ $placeholder }}" {{ $attributes->merge(['class' => $defaultClass]) }}
|
||||
@if ($realtimeValidation) wire:model.debounce.200ms="{{ $id }}"
|
||||
@else
|
||||
wire:model.defer={{ $value ?? $id }}
|
||||
wire:dirty.class="input-warning"@endif
|
||||
wire:dirty.class="input-warning" @endif
|
||||
@disabled($disabled) @readonly($readonly) @required($required) id="{{ $id }}" name="{{ $name }}"
|
||||
name={{ $id }} ></textarea>
|
||||
name={{ $id }}></textarea>
|
||||
@error($id)
|
||||
<label class="label">
|
||||
<span class="text-red-500 label-text-alt">{{ $message }}</span>
|
||||
|
@ -7,14 +7,14 @@
|
||||
<p class="mt-6 text-base leading-7 text-neutral-300">There has been an error, we are working on it.
|
||||
</p>
|
||||
@if ($exception->getMessage() !== '')
|
||||
<p class="mt-6 text-base leading-7 text-red-500">Error: {{ $exception->getMessage() }}
|
||||
<p class="mt-6 text-xs leading-7 text-left text-red-500">Error: {{ $exception->getMessage() }}
|
||||
</p>
|
||||
@endif
|
||||
<div class="flex items-center justify-center mt-10 gap-x-6">
|
||||
<a href="/">
|
||||
<x-forms.button>Go back home</x-forms.button>
|
||||
</a>
|
||||
<a href="https://docs.coollabs.io/contact.html" class="font-semibold text-white ">Contact
|
||||
<a href="https://docs.coollabs.io/contact.html" class="font-semibold text-white">Contact
|
||||
support
|
||||
<span aria-hidden="true">→</span></a>
|
||||
</div>
|
||||
|
@ -35,5 +35,6 @@
|
||||
<div class="stat-value">{{ $s3s }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- <x-forms.button wire:click='getIptables'>Get IPTABLES</x-forms.button> --}}
|
||||
</div>
|
||||
|
@ -27,11 +27,22 @@
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.select id="application.build_pack" label="Build Pack" required>
|
||||
<option value="nixpacks">Nixpacks</option>
|
||||
<option value="dockerfile">Dockerfile</option>
|
||||
<option disabled value="compose">Compose</option>
|
||||
</x-forms.select>
|
||||
@if ($application->build_pack === 'dockerfile')
|
||||
<x-forms.select disabled id="application.build_pack" label="Build Pack" required>
|
||||
<option value="dockerfile">Dockerfile</option>
|
||||
</x-forms.select>
|
||||
@elseif ($application->build_pack === 'dockercompose')
|
||||
<x-forms.select disabled id="application.build_pack" label="Build Pack" required>
|
||||
<option selected value="dockercompose">Docker Compose</option>
|
||||
</x-forms.select>
|
||||
@else
|
||||
<x-forms.select id="application.build_pack" label="Build Pack" required>
|
||||
<option value="nixpacks">Nixpacks</option>
|
||||
<option value="dockerfile">Dockerfile</option>
|
||||
<option disabled value="dockercompose">Docker Compose</option>
|
||||
</x-forms.select>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@if ($application->settings->is_static)
|
||||
<x-forms.select id="application.static_image" label="Static Image" required>
|
||||
@ -47,7 +58,6 @@
|
||||
<x-forms.input placeholder="pnpm build" id="application.build_command" label="Build Command" />
|
||||
<x-forms.input placeholder="pnpm start" id="application.start_command" label="Start Command" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
|
||||
helper="Directory to use as root. Useful for monorepos. WIP" disabled />
|
||||
@ -62,6 +72,19 @@
|
||||
@if ($application->dockerfile)
|
||||
<x-forms.textarea label="Dockerfile" id="application.dockerfile" rows="6"> </x-forms.textarea>
|
||||
@endif
|
||||
@if ($application->dockercompose_raw)
|
||||
<h3>Services </h3>
|
||||
@foreach ($services as $serviceName => $service)
|
||||
<x-forms.input id="application.service_configurations.{{$serviceName}}.fqdn" label="{{ $serviceName }} FQDN">
|
||||
</x-forms.input>
|
||||
@endforeach
|
||||
{{-- <x-forms.textarea label="Docker Compose (Raw)" id="application.dockercompose_raw" rows="16">
|
||||
</x-forms.textarea> --}}
|
||||
{{-- <x-forms.textarea readonly helper="Added all required fields" label="Docker Compose (Coolified)"
|
||||
id="application.dockercompose" rows="6">
|
||||
</x-forms.textarea> --}}
|
||||
|
||||
@endif
|
||||
|
||||
<h3>Network</h3>
|
||||
<div class="flex flex-col gap-2 xl:flex-row">
|
||||
|
@ -0,0 +1,49 @@
|
||||
<div>
|
||||
<h1>Create a new Application</h1>
|
||||
<div class="pb-4">You can deploy complex application easily with Docker Compose.</div>
|
||||
<form wire:submit.prevent="submit">
|
||||
<div class="flex gap-2 pb-1">
|
||||
<h2>Docker Compose</h2>
|
||||
|
||||
|
||||
<x-forms.button type="submit">Save</x-forms.button>
|
||||
</div>
|
||||
<pre>
|
||||
# Application generated variables
|
||||
# You can use these variables in your docker-compose.yml file and Coolify will create default values or replace them with the values you set in the application creation form.
|
||||
# SERVICE_FQDN_*: FQDN coming from your application (https://coolify.io)
|
||||
# SERVICE_URL_*: URL coming from your application (coolify.io)
|
||||
# SERVICE_USER_*: Generated by your application, username (not encrypted)
|
||||
# SERVICE_PASSWORD_*: Generated by your application, password (encrypted)
|
||||
</pre>
|
||||
<x-forms.textarea rows="20" id="dockercompose"
|
||||
placeholder='services:
|
||||
ghost:
|
||||
documentation: https://docs.ghost.org/docs/config
|
||||
image: ghost:5
|
||||
volumes:
|
||||
- ghost-content-data:/var/lib/ghost/content
|
||||
environment:
|
||||
- url=$SERVICE_FQDN_GHOST
|
||||
- database__client=mysql
|
||||
- database__connection__host=mysql
|
||||
- database__connection__user=$SERVICE_USER_MYSQL
|
||||
- database__connection__password=$SERVICE_PASSWORD_MYSQL
|
||||
- database__connection__database=${MYSQL_DATABASE-ghost}
|
||||
ports:
|
||||
- "2368"
|
||||
depends_on:
|
||||
- mysql
|
||||
mysql:
|
||||
documentation: https://hub.docker.com/_/mysql
|
||||
image: mysql:8.0
|
||||
volumes:
|
||||
- ghost-mysql-data:/var/lib/mysql
|
||||
environment:
|
||||
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
||||
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL_ROOT}
|
||||
'></x-forms.textarea>
|
||||
</form>
|
||||
</div>
|
@ -52,6 +52,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (isDev())
|
||||
<div class="box group" wire:click="setType('dockercompose')">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="group-hover:text-white">
|
||||
Based on a Docker Compose
|
||||
</div>
|
||||
<div class="text-xs group-hover:text-white">
|
||||
You can deploy complex application easily with Docker Compose.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<h2 class="py-4">Databases</h2>
|
||||
<div class="grid justify-start grid-cols-1 gap-2 text-left xl:grid-cols-3">
|
||||
|
@ -7,6 +7,8 @@
|
||||
<livewire:project.new.github-private-repository-deploy-key :type="$type" />
|
||||
@elseif ($type === 'dockerfile')
|
||||
<livewire:project.new.simple-dockerfile :type="$type" />
|
||||
@elseif ($type === 'dockercompose')
|
||||
<livewire:project.new.docker-compose :type="$type" />
|
||||
@else
|
||||
<livewire:project.new.select />
|
||||
@endif
|
||||
|
@ -7,12 +7,11 @@
|
||||
use App\Http\Controllers\ProjectController;
|
||||
use App\Http\Controllers\ServerController;
|
||||
use App\Http\Livewire\Boarding\Index;
|
||||
use App\Http\Livewire\Boarding\Server as BoardingServer;
|
||||
use App\Http\Livewire\Dashboard;
|
||||
use App\Http\Livewire\Help;
|
||||
use App\Http\Livewire\Server\All;
|
||||
use App\Http\Livewire\Server\Show;
|
||||
use App\Http\Livewire\Waitlist\Index as WaitlistIndex;
|
||||
use App\Models\Application;
|
||||
use App\Models\GithubApp;
|
||||
use App\Models\GitlabApp;
|
||||
use App\Models\InstanceSettings;
|
||||
@ -23,11 +22,16 @@
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Fortify\Contracts\FailedPasswordResetLinkRequestResponse;
|
||||
use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse;
|
||||
use Laravel\Fortify\Fortify;
|
||||
|
||||
Route::get('/test', function () {
|
||||
$template = Storage::get('templates/docker-compose.yaml');
|
||||
return generateServiceFromTemplate($template, Application::find(1));
|
||||
});
|
||||
Route::post('/forgot-password', function (Request $request) {
|
||||
if (is_transactional_emails_active()) {
|
||||
$arrayOfRequest = $request->only(Fortify::email());
|
||||
|
@ -168,7 +168,7 @@
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if ($found) {
|
||||
$found->delete();
|
||||
$container_name = generateApplicationContainerName($application->uuid, $pull_request_id);
|
||||
$container_name = generateApplicationContainerName($application);
|
||||
ray('Stopping container: ' . $container_name);
|
||||
remote_process(["docker rm -f $container_name"], $application->destination->server);
|
||||
return response('Preview Deployment closed.');
|
||||
|
Loading…
Reference in New Issue
Block a user