Merge branch 'next' into next
This commit is contained in:
@@ -157,7 +157,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
private ?string $coolify_variables = null;
|
private ?string $coolify_variables = null;
|
||||||
|
|
||||||
private bool $preserveRepository = true;
|
private bool $preserveRepository = false;
|
||||||
|
|
||||||
public $tries = 1;
|
public $tries = 1;
|
||||||
|
|
||||||
@@ -480,6 +480,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start compose file
|
// Start compose file
|
||||||
|
$server_workdir = $this->application->workdir();
|
||||||
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
||||||
if ($this->docker_compose_custom_start_command) {
|
if ($this->docker_compose_custom_start_command) {
|
||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
@@ -488,7 +489,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
$server_workdir = $this->application->workdir();
|
|
||||||
$this->docker_compose_location = '/docker-compose.yaml';
|
$this->docker_compose_location = '/docker-compose.yaml';
|
||||||
|
|
||||||
$command = "{$this->coolify_variables} docker compose";
|
$command = "{$this->coolify_variables} docker compose";
|
||||||
@@ -508,16 +508,27 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$command = "{$this->coolify_variables} docker compose";
|
$command = "{$this->coolify_variables} docker compose";
|
||||||
|
if ($this->preserveRepository) {
|
||||||
|
if ($this->env_filename) {
|
||||||
|
$command .= " --env-file {$server_workdir}/{$this->env_filename}";
|
||||||
|
}
|
||||||
|
$command .= " --project-name {$this->application->uuid} --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
|
||||||
|
$this->write_deployment_configurations();
|
||||||
|
|
||||||
|
$this->execute_remote_command(
|
||||||
|
['command' => $command, 'hidden' => true],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
if ($this->env_filename) {
|
if ($this->env_filename) {
|
||||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
||||||
}
|
}
|
||||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
||||||
|
|
||||||
$this->write_deployment_configurations();
|
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->application_deployment_queue->addLogEntry('New container started.');
|
$this->application_deployment_queue->addLogEntry('New container started.');
|
||||||
@@ -619,6 +630,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
$this->application->fileStorages()->each(function ($fileStorage) {
|
||||||
|
if (! $fileStorage->is_based_on_git && ! $fileStorage->is_directory) {
|
||||||
|
$fileStorage->saveStorageOnServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
$this->server = $this->build_server;
|
$this->server = $this->build_server;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Livewire\Project\Application;
|
namespace App\Livewire\Project\Application;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\LocalFileVolume;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
@@ -30,6 +29,8 @@ class General extends Component
|
|||||||
|
|
||||||
public ?string $ports_exposes = null;
|
public ?string $ports_exposes = null;
|
||||||
|
|
||||||
|
public bool $is_preserve_repository_enabled = false;
|
||||||
|
|
||||||
public bool $is_container_label_escape_enabled = true;
|
public bool $is_container_label_escape_enabled = true;
|
||||||
|
|
||||||
public $customLabels;
|
public $customLabels;
|
||||||
@@ -145,6 +146,7 @@ class General extends Component
|
|||||||
}
|
}
|
||||||
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
|
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
|
||||||
$this->ports_exposes = $this->application->ports_exposes;
|
$this->ports_exposes = $this->application->ports_exposes;
|
||||||
|
$this->is_preserve_repository_enabled = $this->application->settings->is_preserve_repository_enabled;
|
||||||
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
|
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
|
||||||
$this->customLabels = $this->application->parseContainerLabels();
|
$this->customLabels = $this->application->parseContainerLabels();
|
||||||
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
|
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
|
||||||
@@ -168,9 +170,21 @@ class General extends Component
|
|||||||
$this->application->settings->save();
|
$this->application->settings->save();
|
||||||
$this->dispatch('success', 'Settings saved.');
|
$this->dispatch('success', 'Settings saved.');
|
||||||
$this->application->refresh();
|
$this->application->refresh();
|
||||||
|
|
||||||
|
// If port_exposes changed, reset default labels
|
||||||
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
|
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
|
||||||
$this->resetDefaultLabels(false);
|
$this->resetDefaultLabels(false);
|
||||||
}
|
}
|
||||||
|
if ($this->is_preserve_repository_enabled !== $this->application->settings->is_preserve_repository_enabled) {
|
||||||
|
if ($this->application->settings->is_preserve_repository_enabled === false) {
|
||||||
|
$this->application->fileStorages->each(function ($storage) {
|
||||||
|
$storage->is_based_on_git = $this->application->settings->is_preserve_repository_enabled;
|
||||||
|
$storage->save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadComposeFile($isInit = false)
|
public function loadComposeFile($isInit = false)
|
||||||
@@ -179,6 +193,11 @@ class General extends Component
|
|||||||
if ($isInit && $this->application->docker_compose_raw) {
|
if ($isInit && $this->application->docker_compose_raw) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must reload the application to get the latest database changes
|
||||||
|
// Why? Not sure, but it works.
|
||||||
|
$this->application->refresh();
|
||||||
|
|
||||||
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit);
|
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit);
|
||||||
if (is_null($this->parsedServices)) {
|
if (is_null($this->parsedServices)) {
|
||||||
$this->dispatch('error', 'Failed to parse your docker-compose file. Please check the syntax and try again.');
|
$this->dispatch('error', 'Failed to parse your docker-compose file. Please check the syntax and try again.');
|
||||||
@@ -186,32 +205,6 @@ class General extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$compose = $this->application->parseCompose();
|
$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($volume)->before(':');
|
|
||||||
$target = str($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),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->dispatch('success', 'Docker compose file loaded.');
|
$this->dispatch('success', 'Docker compose file loaded.');
|
||||||
$this->dispatch('compose_loaded');
|
$this->dispatch('compose_loaded');
|
||||||
$this->dispatch('refreshStorages');
|
$this->dispatch('refreshStorages');
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class FileStorage extends Component
|
|||||||
'fileStorage.fs_path' => 'required',
|
'fileStorage.fs_path' => 'required',
|
||||||
'fileStorage.mount_path' => 'required',
|
'fileStorage.mount_path' => 'required',
|
||||||
'fileStorage.content' => 'nullable',
|
'fileStorage.content' => 'nullable',
|
||||||
|
'fileStorage.is_based_on_git' => 'required|boolean',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
@@ -45,6 +46,7 @@ class FileStorage extends Component
|
|||||||
$this->workdir = null;
|
$this->workdir = null;
|
||||||
$this->fs_path = $this->fileStorage->fs_path;
|
$this->fs_path = $this->fileStorage->fs_path;
|
||||||
}
|
}
|
||||||
|
$this->fileStorage->loadStorageOnServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function convertToDirectory()
|
public function convertToDirectory()
|
||||||
@@ -68,6 +70,9 @@ class FileStorage extends Component
|
|||||||
$this->fileStorage->deleteStorageOnServer();
|
$this->fileStorage->deleteStorageOnServer();
|
||||||
$this->fileStorage->is_directory = false;
|
$this->fileStorage->is_directory = false;
|
||||||
$this->fileStorage->content = null;
|
$this->fileStorage->content = null;
|
||||||
|
if (data_get($this->resource, 'settings.is_preserve_repository_enabled')) {
|
||||||
|
$this->fileStorage->is_based_on_git = true;
|
||||||
|
}
|
||||||
$this->fileStorage->save();
|
$this->fileStorage->save();
|
||||||
$this->fileStorage->saveStorageOnServer();
|
$this->fileStorage->saveStorageOnServer();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ class Show extends Component
|
|||||||
public string $type;
|
public string $type;
|
||||||
|
|
||||||
protected $listeners = [
|
protected $listeners = [
|
||||||
'refresh' => 'refresh',
|
'refreshEnvs' => 'refresh',
|
||||||
|
'refresh',
|
||||||
'compose_loaded' => '$refresh',
|
'compose_loaded' => '$refresh',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class Show extends Component
|
|||||||
|
|
||||||
public array $parameters;
|
public array $parameters;
|
||||||
|
|
||||||
protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey'];
|
protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey'];
|
||||||
|
|
||||||
public function saveKey($data)
|
public function saveKey($data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,32 @@ class LocalFileVolume extends BaseModel
|
|||||||
return $this->morphTo('resource');
|
return $this->morphTo('resource');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function loadStorageOnServer()
|
||||||
|
{
|
||||||
|
$this->load(['service']);
|
||||||
|
$isService = data_get($this->resource, 'service');
|
||||||
|
if ($isService) {
|
||||||
|
$workdir = $this->resource->service->workdir();
|
||||||
|
$server = $this->resource->service->server;
|
||||||
|
} else {
|
||||||
|
$workdir = $this->resource->workdir();
|
||||||
|
$server = $this->resource->destination->server;
|
||||||
|
}
|
||||||
|
$commands = collect([]);
|
||||||
|
$path = data_get_str($this, 'fs_path');
|
||||||
|
if ($path->startsWith('.')) {
|
||||||
|
$path = $path->after('.');
|
||||||
|
$path = $workdir.$path;
|
||||||
|
}
|
||||||
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
|
if ($isFile === 'OK') {
|
||||||
|
$content = instant_remote_process(["cat $path"], $server, false);
|
||||||
|
$this->content = $content;
|
||||||
|
$this->is_directory = false;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function deleteStorageOnServer()
|
public function deleteStorageOnServer()
|
||||||
{
|
{
|
||||||
$isService = data_get($this->resource, 'service');
|
$isService = data_get($this->resource, 'service');
|
||||||
@@ -35,17 +61,20 @@ class LocalFileVolume extends BaseModel
|
|||||||
$server = $this->resource->destination->server;
|
$server = $this->resource->destination->server;
|
||||||
}
|
}
|
||||||
$commands = collect([]);
|
$commands = collect([]);
|
||||||
$fs_path = data_get($this, 'fs_path');
|
$path = data_get_str($this, 'fs_path');
|
||||||
$isFile = instant_remote_process(["test -f $fs_path && echo OK || echo NOK"], $server);
|
if ($path->startsWith('.')) {
|
||||||
$isDir = instant_remote_process(["test -d $fs_path && echo OK || echo NOK"], $server);
|
$path = $path->after('.');
|
||||||
if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') {
|
$path = $workdir.$path;
|
||||||
ray($isFile, $isDir);
|
}
|
||||||
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
|
if ($path && $path != '/' && $path != '.' && $path != '..') {
|
||||||
if ($isFile === 'OK') {
|
if ($isFile === 'OK') {
|
||||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
|
||||||
|
|
||||||
} elseif ($isDir === 'OK') {
|
} elseif ($isDir === 'OK') {
|
||||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
|
||||||
$commands->push("rmdir $fs_path > /dev/null 2>&1 || true");
|
$commands->push("rmdir $path > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($commands->count() > 0) {
|
if ($commands->count() > 0) {
|
||||||
@@ -55,6 +84,7 @@ class LocalFileVolume extends BaseModel
|
|||||||
|
|
||||||
public function saveStorageOnServer()
|
public function saveStorageOnServer()
|
||||||
{
|
{
|
||||||
|
$this->load(['service']);
|
||||||
$isService = data_get($this->resource, 'service');
|
$isService = data_get($this->resource, 'service');
|
||||||
if ($isService) {
|
if ($isService) {
|
||||||
$workdir = $this->resource->service->workdir();
|
$workdir = $this->resource->service->workdir();
|
||||||
@@ -74,30 +104,36 @@ class LocalFileVolume extends BaseModel
|
|||||||
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fileVolume = $this;
|
$path = data_get_str($this, 'fs_path');
|
||||||
$path = str(data_get($fileVolume, 'fs_path'));
|
$content = data_get($this, 'content');
|
||||||
$content = data_get($fileVolume, 'content');
|
|
||||||
if ($path->startsWith('.')) {
|
if ($path->startsWith('.')) {
|
||||||
$path = $path->after('.');
|
$path = $path->after('.');
|
||||||
$path = $workdir.$path;
|
$path = $workdir.$path;
|
||||||
}
|
}
|
||||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
if ($isFile == 'OK' && $this->is_directory) {
|
||||||
$content = instant_remote_process(["cat $path"], $server, false);
|
$content = instant_remote_process(["cat $path"], $server, false);
|
||||||
$fileVolume->is_directory = false;
|
$this->is_directory = false;
|
||||||
$fileVolume->content = $content;
|
$this->content = $content;
|
||||||
$fileVolume->save();
|
$this->save();
|
||||||
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||||
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
||||||
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
} elseif ($isDir == 'OK' && ! $this->is_directory) {
|
||||||
$fileVolume->is_directory = true;
|
if ($path == '/' || $path == '.' || $path == '..' || $path == '' || str($path)->isEmpty() || is_null($path)) {
|
||||||
$fileVolume->save();
|
$this->is_directory = true;
|
||||||
|
$this->save();
|
||||||
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
||||||
}
|
}
|
||||||
if ($isDir == 'NOK' && ! $fileVolume->is_directory) {
|
instant_remote_process([
|
||||||
$chmod = data_get($fileVolume, 'chmod');
|
"rm -fr $path",
|
||||||
$chown = data_get($fileVolume, 'chown');
|
"touch $path",
|
||||||
|
], $server, false);
|
||||||
|
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||||
|
}
|
||||||
|
if ($isDir == 'NOK' && ! $this->is_directory) {
|
||||||
|
$chmod = data_get($this, 'chmod');
|
||||||
|
$chown = data_get($this, 'chown');
|
||||||
if ($content) {
|
if ($content) {
|
||||||
$content = base64_encode($content);
|
$content = base64_encode($content);
|
||||||
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
|
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
|
||||||
@@ -111,7 +147,7 @@ class LocalFileVolume extends BaseModel
|
|||||||
if ($chmod) {
|
if ($chmod) {
|
||||||
$commands->push("chmod $chmod $path");
|
$commands->push("chmod $chmod $path");
|
||||||
}
|
}
|
||||||
} elseif ($isDir == 'NOK' && $fileVolume->is_directory) {
|
} elseif ($isDir == 'NOK' && $this->is_directory) {
|
||||||
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,41 @@ class Service extends BaseModel
|
|||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
$image = str($application->image)->before(':')->value();
|
$image = str($application->image)->before(':')->value();
|
||||||
switch ($image) {
|
switch ($image) {
|
||||||
|
case str($image)?->contains('rabbitmq'):
|
||||||
|
$data = collect([]);
|
||||||
|
$host_port = $this->environment_variables()->where('key', 'PORT')->first();
|
||||||
|
$username = $this->environment_variables()->where('key', 'SERVICE_USER_RABBITMQ')->first();
|
||||||
|
$password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_RABBITMQ')->first();
|
||||||
|
if ($host_port) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Host Port Binding' => [
|
||||||
|
'key' => data_get($host_port, 'key'),
|
||||||
|
'value' => data_get($host_port, 'value'),
|
||||||
|
'rules' => 'required',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if ($username) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Username' => [
|
||||||
|
'key' => data_get($username, 'key'),
|
||||||
|
'value' => data_get($username, 'value'),
|
||||||
|
'rules' => 'required',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if ($password) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Password' => [
|
||||||
|
'key' => data_get($password, 'key'),
|
||||||
|
'value' => data_get($password, 'value'),
|
||||||
|
'rules' => 'required',
|
||||||
|
'isPassword' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$fields->put('RabbitMQ', $data->toArray());
|
||||||
|
break;
|
||||||
case str($image)?->contains('tolgee'):
|
case str($image)?->contains('tolgee'):
|
||||||
$data = collect([]);
|
$data = collect([]);
|
||||||
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_TOLGEE')->first();
|
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_TOLGEE')->first();
|
||||||
@@ -504,6 +539,9 @@ class Service extends BaseModel
|
|||||||
default:
|
default:
|
||||||
$data = collect([]);
|
$data = collect([]);
|
||||||
$admin_user = $this->environment_variables()->where('key', 'SERVICE_USER_ADMIN')->first();
|
$admin_user = $this->environment_variables()->where('key', 'SERVICE_USER_ADMIN')->first();
|
||||||
|
// Chaskiq
|
||||||
|
$admin_email = $this->environment_variables()->where('key', 'ADMIN_EMAIL')->first();
|
||||||
|
|
||||||
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ADMIN')->first();
|
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ADMIN')->first();
|
||||||
if ($admin_user) {
|
if ($admin_user) {
|
||||||
$data = $data->merge([
|
$data = $data->merge([
|
||||||
@@ -525,6 +563,15 @@ class Service extends BaseModel
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
if ($admin_email) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Email' => [
|
||||||
|
'key' => 'ADMIN_EMAIL',
|
||||||
|
'value' => data_get($admin_email, 'value'),
|
||||||
|
'rules' => 'required|email',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
$fields->put('Admin', $data->toArray());
|
$fields->put('Admin', $data->toArray());
|
||||||
break;
|
break;
|
||||||
case str($image)?->contains('vaultwarden'):
|
case str($image)?->contains('vaultwarden'):
|
||||||
|
|||||||
@@ -794,7 +794,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
$topLevelVolumes = collect($tempTopLevelVolumes);
|
$topLevelVolumes = collect($tempTopLevelVolumes);
|
||||||
}
|
}
|
||||||
$services = collect($services)->map(function ($service, $serviceName) use ($topLevelVolumes, $topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $allServices) {
|
$services = collect($services)->map(function ($service, $serviceName) use ($topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $allServices, $topLevelVolumes) {
|
||||||
// Workarounds for beta users.
|
// Workarounds for beta users.
|
||||||
if ($serviceName === 'registry') {
|
if ($serviceName === 'registry') {
|
||||||
$tempServiceName = 'docker-registry';
|
$tempServiceName = 'docker-registry';
|
||||||
@@ -963,102 +963,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
|
|
||||||
// Collect/create/update volumes
|
// Collect/create/update volumes
|
||||||
if ($serviceVolumes->count() > 0) {
|
if ($serviceVolumes->count() > 0) {
|
||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($savedService, $topLevelVolumes) {
|
$serviceVolumes = parseServiceVolumes($serviceVolumes, $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
|
|
||||||
ray('setting isDirectory to true');
|
|
||||||
$isDirectory = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($type?->value() === 'bind') {
|
|
||||||
if ($source->value() === '/var/run/docker.sock') {
|
|
||||||
return $volume;
|
|
||||||
}
|
|
||||||
if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
|
|
||||||
return $volume;
|
|
||||||
}
|
|
||||||
LocalFileVolume::updateOrCreate(
|
|
||||||
[
|
|
||||||
'mount_path' => $target,
|
|
||||||
'resource_id' => $savedService->id,
|
|
||||||
'resource_type' => get_class($savedService),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'fs_path' => $source,
|
|
||||||
'mount_path' => $target,
|
|
||||||
'content' => $content,
|
|
||||||
'is_directory' => $isDirectory,
|
|
||||||
'resource_id' => $savedService->id,
|
|
||||||
'resource_type' => get_class($savedService),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} 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());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1645,131 +1550,261 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
} elseif ($resource->compose_parsing_version === '2') {
|
} elseif ($resource->compose_parsing_version === '2') {
|
||||||
if (count($serviceVolumes) > 0) {
|
if (count($serviceVolumes) > 0) {
|
||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
$serviceVolumes = parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull_request_id);
|
||||||
if (is_string($volume)) {
|
ray($serviceVolumes);
|
||||||
$volume = str($volume);
|
|
||||||
if ($volume->contains(':') && ! $volume->startsWith('/')) {
|
|
||||||
$name = $volume->before(':');
|
|
||||||
$mount = $volume->after(':');
|
|
||||||
if ($name->startsWith('.') || $name->startsWith('~')) {
|
|
||||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
|
||||||
if ($name->startsWith('.')) {
|
|
||||||
$name = $name->replaceFirst('.', $dir);
|
|
||||||
}
|
|
||||||
if ($name->startsWith('~')) {
|
|
||||||
$name = $name->replaceFirst('~', $dir);
|
|
||||||
}
|
|
||||||
if ($pull_request_id !== 0) {
|
|
||||||
$name = $name."-pr-$pull_request_id";
|
|
||||||
}
|
|
||||||
$volume = str("$name:$mount");
|
|
||||||
} else {
|
|
||||||
if ($pull_request_id !== 0) {
|
|
||||||
$uuid = $resource->uuid;
|
|
||||||
$name = $uuid."-$name-pr-$pull_request_id";
|
|
||||||
$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;
|
|
||||||
$name = str($uuid."-$name");
|
|
||||||
$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) {
|
|
||||||
$name = $name."-pr-$pull_request_id";
|
|
||||||
}
|
|
||||||
$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('/'))) {
|
|
||||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
|
||||||
if (str($source, '.')) {
|
|
||||||
$source = str($source)->replaceFirst('.', $dir);
|
|
||||||
}
|
|
||||||
if (str($source, '~')) {
|
|
||||||
$source = str($source)->replaceFirst('~', $dir);
|
|
||||||
}
|
|
||||||
if ($read_only) {
|
|
||||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
|
||||||
} else {
|
|
||||||
data_set($volume, 'source', $source.':'.$target);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($pull_request_id === 0) {
|
|
||||||
$source = $uuid."-$source";
|
|
||||||
} else {
|
|
||||||
$source = $uuid."-$source-pr-$pull_request_id";
|
|
||||||
}
|
|
||||||
if ($read_only) {
|
|
||||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
|
||||||
} else {
|
|
||||||
data_set($volume, 'source', $source.':'.$target);
|
|
||||||
}
|
|
||||||
if (! str($source)->startsWith('/')) {
|
|
||||||
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());
|
||||||
});
|
// $serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
||||||
|
// if (is_string($volume)) {
|
||||||
|
// $volume = str($volume);
|
||||||
|
// if ($volume->contains(':')) {
|
||||||
|
// $name = $volume->before(':');
|
||||||
|
// $mount = $volume->after(':')->beforeLast(':');
|
||||||
|
// if ($name->startsWith('.') || $name->startsWith('~') || $name->startsWith('/')) {
|
||||||
|
// // File or dir mount from the host system
|
||||||
|
// $dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||||
|
// if ($name->startsWith('.')) {
|
||||||
|
// $name = $name->replaceFirst('.', $dir);
|
||||||
|
// }
|
||||||
|
// if ($name->startsWith('~')) {
|
||||||
|
// $name = $name->replaceFirst('~', $dir);
|
||||||
|
// }
|
||||||
|
// if ($pull_request_id !== 0) {
|
||||||
|
// $name = $name."-pr-$pull_request_id";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $volume = str("$name:$mount");
|
||||||
|
// LocalFileVolume::updateOrCreate(
|
||||||
|
// [
|
||||||
|
// 'mount_path' => $mount,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'fs_path' => $name,
|
||||||
|
// 'mount_path' => $mount,
|
||||||
|
// 'is_directory' => true,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// // Docker Volume part
|
||||||
|
// if ($pull_request_id == 0) {
|
||||||
|
// $uuid = $resource->uuid;
|
||||||
|
// $name = str($uuid."-$name");
|
||||||
|
// $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(),
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
// LocalPersistentVolume::updateOrCreate(
|
||||||
|
// [
|
||||||
|
// 'mount_path' => $mount,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'name' => $name,
|
||||||
|
// 'mount_path' => $mount,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// $uuid = $resource->uuid;
|
||||||
|
// $name = $uuid."-$name-pr-$pull_request_id";
|
||||||
|
// $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,
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
// LocalPersistentVolume::updateOrCreate(
|
||||||
|
// [
|
||||||
|
// 'mount_path' => $mount,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'name' => $name,
|
||||||
|
// 'mount_path' => $mount,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } elseif (is_array($volume)) {
|
||||||
|
// $source = data_get($volume, 'source');
|
||||||
|
// $target = data_get($volume, 'target');
|
||||||
|
// $type = data_get($volume, 'type');
|
||||||
|
// $read_only = data_get($volume, 'read_only');
|
||||||
|
// $content = data_get_str($volume, 'content');
|
||||||
|
// if ($source && $target) {
|
||||||
|
// if ($type?->value() === 'bind') {
|
||||||
|
// if ($source->value() === '/var/run/docker.sock') {
|
||||||
|
// return $volume;
|
||||||
|
// }
|
||||||
|
// if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
|
||||||
|
// return $volume;
|
||||||
|
// }
|
||||||
|
// LocalFileVolume::updateOrCreate(
|
||||||
|
// [
|
||||||
|
// 'mount_path' => $target,
|
||||||
|
// 'resource_id' => $savedService->id,
|
||||||
|
// 'resource_type' => get_class($savedService),
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'fs_path' => $source,
|
||||||
|
// 'mount_path' => $target,
|
||||||
|
// 'content' => $content,
|
||||||
|
// 'is_directory' => $isDirectory,
|
||||||
|
// 'resource_id' => $savedService->id,
|
||||||
|
// 'resource_type' => get_class($savedService),
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// } 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),
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $uuid = $resource->uuid;
|
||||||
|
// if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) {
|
||||||
|
// $dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||||
|
// if (str($source, '.')) {
|
||||||
|
// $source = str($source)->replaceFirst('.', $dir);
|
||||||
|
// }
|
||||||
|
// if (str($source, '~')) {
|
||||||
|
// $source = str($source)->replaceFirst('~', $dir);
|
||||||
|
// }
|
||||||
|
// if ($read_only) {
|
||||||
|
// data_set($volume, 'source', $source.':'.$target.':ro');
|
||||||
|
// } else {
|
||||||
|
// data_set($volume, 'source', $source.':'.$target);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if ($pull_request_id === 0) {
|
||||||
|
// $source = $uuid."-$source";
|
||||||
|
// } else {
|
||||||
|
// $source = $uuid."-$source-pr-$pull_request_id";
|
||||||
|
// }
|
||||||
|
// if ($read_only) {
|
||||||
|
// data_set($volume, 'source', $source.':'.$target.':ro');
|
||||||
|
// } else {
|
||||||
|
// data_set($volume, 'source', $source.':'.$target);
|
||||||
|
// }
|
||||||
|
// if (! str($source)->startsWith('/')) {
|
||||||
|
// 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 ($content->isNotEmpty()) {
|
||||||
|
// LocalFileVolume::updateOrCreate(
|
||||||
|
// [
|
||||||
|
// 'mount_path' => $target,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'fs_path' => $source,
|
||||||
|
// 'mount_path' => $target,
|
||||||
|
// 'content' => $content,
|
||||||
|
// 'is_directory' => false,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// LocalFileVolume::updateOrCreate(
|
||||||
|
// [
|
||||||
|
// 'mount_path' => $target,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'fs_path' => $source,
|
||||||
|
// 'mount_path' => $target,
|
||||||
|
// 'is_directory' => true,
|
||||||
|
// 'resource_id' => $resource->id,
|
||||||
|
// 'resource_type' => get_class($resource),
|
||||||
|
// ]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (is_array($volume)) {
|
||||||
|
// return data_get($volume, 'source');
|
||||||
|
// }
|
||||||
|
// dispatch(new ServerFilesFromServerJob($resource));
|
||||||
|
|
||||||
|
// return $volume->value();
|
||||||
|
// });
|
||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2662,3 +2697,124 @@ function customApiValidator(Collection|array $item, array $rules)
|
|||||||
'required' => 'This field is required.',
|
'required' => 'This field is required.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull_request_id = 0)
|
||||||
|
{
|
||||||
|
return $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
||||||
|
$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 = $resource->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) || ! $isDirectory) && is_null($content)) {
|
||||||
|
// if isDirectory is not set (or false) & content is also not set, we assume it is a directory
|
||||||
|
ray('setting isDirectory to true');
|
||||||
|
$isDirectory = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($type?->value() === 'bind') {
|
||||||
|
if ($source->value() === '/var/run/docker.sock') {
|
||||||
|
return $volume;
|
||||||
|
}
|
||||||
|
if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
|
||||||
|
return $volume;
|
||||||
|
}
|
||||||
|
if (get_class($resource) === "App\Models\Application") {
|
||||||
|
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||||
|
} else {
|
||||||
|
$dir = base_configuration_dir().'/services/'.$resource->service->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($source->startsWith('.')) {
|
||||||
|
$source = $source->replaceFirst('.', $dir);
|
||||||
|
}
|
||||||
|
if ($source->startsWith('~')) {
|
||||||
|
$source = $source->replaceFirst('~', $dir);
|
||||||
|
}
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$source = $source."-pr-$pull_request_id";
|
||||||
|
}
|
||||||
|
|
||||||
|
$volume = str("$source:$target");
|
||||||
|
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),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} 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, '-');
|
||||||
|
if (get_class($resource) === "App\Models\Application") {
|
||||||
|
$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));
|
||||||
|
|
||||||
|
return str($volume)->value();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.323',
|
'release' => '4.0.0-beta.324',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.323';
|
return '4.0.0-beta.324';
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?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('local_file_volumes', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_based_on_git')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('local_file_volumes', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_based_on_git');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
BIN
public/svgs/chaskiq.png
Normal file
BIN
public/svgs/chaskiq.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
1
public/svgs/rabbitmq.svg
Normal file
1
public/svgs/rabbitmq.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg height="271" preserveAspectRatio="xMidYMid" viewBox="0 0 256 271" width="256" xmlns="http://www.w3.org/2000/svg"><path d="m245.44 108.307692h-85.090462c-4.268307 0-7.734153-3.465846-7.734153-7.734154v-88.6793842c0-6.56738457-5.32677-11.8941538-11.889231-11.8941538h-30.375385c-6.567384 0-11.8892305 5.32676923-11.8892305 11.8941538v88.1427692c0 4.573539-3.6972308 8.290462-8.2707693 8.310154l-27.8843077.132923c-4.612923.024615-8.3593846-3.716923-8.3495384-8.324923l.1723077-88.2412308c.0147692-6.57723082-5.312-11.9138462-11.8892308-11.9138462h-30.3507692c-6.56738465 0-11.8892308 5.32676923-11.8892308 11.8941538v248.3150772c0 5.833846 4.72615385 10.56 10.5550769 10.56h234.8849231c5.833846 0 10.56-4.726154 10.56-10.56v-141.341539c0-5.833846-4.726154-10.56-10.56-10.56zm-39.901538 93.233231c0 7.645539-6.198154 13.843692-13.843693 13.843692h-24.004923c-7.645538 0-13.843692-6.198153-13.843692-13.843692v-24.004923c0-7.645538 6.198154-13.843692 13.843692-13.843692h24.004923c7.645539 0 13.843693 6.198154 13.843693 13.843692z" fill="#f60"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -10,6 +10,7 @@
|
|||||||
@endif
|
@endif
|
||||||
<div>{{ $workdir }}{{ $fs_path }} -> {{ $fileStorage->mount_path }}</div>
|
<div>{{ $workdir }}{{ $fs_path }} -> {{ $fileStorage->mount_path }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form wire:submit='submit' class="flex flex-col gap-2">
|
<form wire:submit='submit' class="flex flex-col gap-2">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@if ($fileStorage->is_directory)
|
@if ($fileStorage->is_directory)
|
||||||
@@ -26,6 +27,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</x-modal-confirmation>
|
</x-modal-confirmation>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@if (!$fileStorage->is_based_on_git)
|
||||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||||
<div class="px-2">This storage will be deleted. It is not reversible. <strong
|
<div class="px-2">This storage will be deleted. It is not reversible. <strong
|
||||||
class="text-error">Please
|
class="text-error">Please
|
||||||
@@ -40,11 +43,24 @@
|
|||||||
label="Permanently delete file from the server?"></x-forms.checkbox>
|
label="Permanently delete file from the server?"></x-forms.checkbox>
|
||||||
@endif
|
@endif
|
||||||
</x-modal-confirmation>
|
</x-modal-confirmation>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@if (!$fileStorage->is_directory)
|
@if (!$fileStorage->is_directory)
|
||||||
<x-forms.textarea label="Content" rows="20" id="fileStorage.content"></x-forms.textarea>
|
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
|
||||||
|
<div class="w-96">
|
||||||
|
<x-forms.checkbox instantSave label="Is this based on the Git repository?"
|
||||||
|
id="fileStorage.is_based_on_git"></x-forms.checkbox>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<x-forms.textarea
|
||||||
|
label="{{ $fileStorage->is_based_on_git ? 'Content (refreshed after a successful deployment)' : 'Content' }}"
|
||||||
|
rows="20" id="fileStorage.content"
|
||||||
|
readonly="{{ $fileStorage->is_based_on_git }}"></x-forms.textarea>
|
||||||
|
@if (!$fileStorage->is_based_on_git)
|
||||||
<x-forms.button class="w-full" type="submit">Save</x-forms.button>
|
<x-forms.button class="w-full" type="submit">Save</x-forms.button>
|
||||||
@endif
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
152
templates/compose/chaskiq.yaml
Normal file
152
templates/compose/chaskiq.yaml
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# documentation: https://chaskiq.io
|
||||||
|
# slogan: Chaskiq is an messaging platform for marketing, support & sales
|
||||||
|
# tags: chaskiq,messaging,chat,marketing,support,sales,open,source,rails,redis,postgresql,sidekiq
|
||||||
|
# logo: svgs/chaskiq.png
|
||||||
|
# port: 3000
|
||||||
|
|
||||||
|
services:
|
||||||
|
chaskiq:
|
||||||
|
image: chaskiq/chaskiq:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_CHASKIQ_3000
|
||||||
|
- REDIS_URL=redis://redis:6379/
|
||||||
|
- DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/${POSTGRES_DB:-chaskiq}
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- SERVICE_URL=${SERVICE_URL_CHASKIQ}
|
||||||
|
- HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- ASSET_HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- WS=wss://${SERVICE_URL_CHASKIQ}/cable
|
||||||
|
- SNS_CONFIGURATION_SET=metrics
|
||||||
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
|
||||||
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
|
||||||
|
- AWS_S3_BUCKET=${AWS_S3_BUCKET:-}
|
||||||
|
- AWS_S3_REGION=${AWS_S3_REGION:-}
|
||||||
|
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example}
|
||||||
|
- ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}
|
||||||
|
- DEFAULT_SENDER_EMAIL=${DEFAULT_SENDER_EMAIL:-admin@example}
|
||||||
|
- LOCAL_STORAGE_PATH=/data/storage
|
||||||
|
- ACTIVE_STORAGE_SERVICE=${ACTIVE_STORAGE_SERVICE:-local}
|
||||||
|
- SMTP_DELIVERY_METHOD=${SMTP_DELIVERY_METHOD:-}
|
||||||
|
- SMTP_ADDRESS=${SMTP_ADDRESS:-}
|
||||||
|
- SMTP_USERNAME=${SMTP_USERNAME:-}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASSWORD:-}
|
||||||
|
- CHASKIQ_APPSTORE_TOKEN=${CHASKIQ_APPSTORE_TOKEN:-}
|
||||||
|
- APP_ENV=production
|
||||||
|
- RAILS_ENV=production
|
||||||
|
- RACK_ENV=production
|
||||||
|
- RAILS_SERVE_STATIC_FILES=true
|
||||||
|
- SECRET_KEY_BASE=$SERVICE_PASSWORD_64_SECRET
|
||||||
|
- RAILS_LOG_TO_STDOUT=true
|
||||||
|
- ENABLED_AUDITS=true
|
||||||
|
- TZ=Europe/Madrid
|
||||||
|
entrypoint: ["/entrypoint.sh"]
|
||||||
|
depends_on:
|
||||||
|
postgresql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- chaskiq-storage:/data/storage
|
||||||
|
- type: bind
|
||||||
|
source: ./entrypoint.sh
|
||||||
|
target: /entrypoint.sh
|
||||||
|
content: |
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
rm -f /usr/src/app/tmp/pids/server.pid
|
||||||
|
exec "$@"
|
||||||
|
echo "Running database migrations..."
|
||||||
|
bundle exec rails db:setup || true
|
||||||
|
bundle exec rails db:migrate
|
||||||
|
echo "Finished running database migrations."
|
||||||
|
echo "Running packages update..."
|
||||||
|
bundle exec rails packages:update
|
||||||
|
echo "Finished packages update."
|
||||||
|
if [ ! -f /usr/src/app/admin_generated ]; then
|
||||||
|
echo "/usr/src/app/admin_generated not found, executing admin generation.."
|
||||||
|
bundle exec rake admin_generator
|
||||||
|
touch /usr/src/app/admin_generated
|
||||||
|
echo "Admin generation finished !"
|
||||||
|
fi
|
||||||
|
bundle exec rails s -b 0.0.0.0 -p 3000
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 15
|
||||||
|
sidekiq:
|
||||||
|
image: chaskiq/chaskiq:latest
|
||||||
|
environment:
|
||||||
|
- REDIS_URL=redis://redis:6379/
|
||||||
|
- DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/${POSTGRES_DB:-chaskiq}
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- ASSET_HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- WS=wss://${SERVICE_URL_CHASKIQ}/cable
|
||||||
|
- SNS_CONFIGURATION_SET=metrics
|
||||||
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
|
||||||
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
|
||||||
|
- AWS_S3_BUCKET=${AWS_S3_BUCKET:-}
|
||||||
|
- AWS_S3_REGION=${AWS_S3_REGION:-}
|
||||||
|
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example}
|
||||||
|
- ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}
|
||||||
|
- DEFAULT_SENDER_EMAIL=${DEFAULT_SENDER_EMAIL:-admin@example}
|
||||||
|
- LOCAL_STORAGE_PATH=/data/storage
|
||||||
|
- ACTIVE_STORAGE_SERVICE=${ACTIVE_STORAGE_SERVICE:-local}
|
||||||
|
- SMTP_DELIVERY_METHOD=${SMTP_DELIVERY_METHOD:-}
|
||||||
|
- SMTP_ADDRESS=${SMTP_ADDRESS:-}
|
||||||
|
- SMTP_USERNAME=${SMTP_USERNAME:-}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASSWORD:-}
|
||||||
|
- CHASKIQ_APPSTORE_TOKEN=${CHASKIQ_APPSTORE_TOKEN:-}
|
||||||
|
- APP_ENV=production
|
||||||
|
- RAILS_ENV=production
|
||||||
|
- RACK_ENV=production
|
||||||
|
- RAILS_SERVE_STATIC_FILES=true
|
||||||
|
- SECRET_KEY_BASE=$SERVICE_PASSWORD_64_SECRET
|
||||||
|
- RAILS_LOG_TO_STDOUT=true
|
||||||
|
- ENABLED_AUDITS=true
|
||||||
|
- TZ=Europe/Madrid
|
||||||
|
volumes:
|
||||||
|
- chaskiq-storage:/data/storage
|
||||||
|
depends_on:
|
||||||
|
postgresql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
chaskiq:
|
||||||
|
condition: service_healthy
|
||||||
|
command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"]
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
[
|
||||||
|
"CMD-SHELL",
|
||||||
|
"bundle exec rails runner 'puts Sidekiq.redis(&:info)' > /dev/null 2>&1",
|
||||||
|
]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
||||||
|
postgresql:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
volumes:
|
||||||
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB:-chaskiq}
|
||||||
|
- POSTGRES_INITDB_ARGS= --data-checksums
|
||||||
|
- PSQL_HISTFILE=/root/log/.psql_history
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
redis:
|
||||||
|
image: redis:6-alpine
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
# ignore: true
|
|
||||||
# documentation: https://www.rabbitmq.com/documentation.html
|
# documentation: https://www.rabbitmq.com/documentation.html
|
||||||
# slogan: With tens of thousands of users, RabbitMQ is one of the most popular open source message brokers.
|
# slogan: With tens of thousands of users, RabbitMQ is one of the most popular open source message brokers.
|
||||||
# tags: message broker, message queue, message-oriented middleware, MOM, AMQP, MQTT, STOMP, messaging
|
# tags: message broker, message queue, message-oriented middleware, MOM, AMQP, MQTT, STOMP, messaging
|
||||||
|
# logo: svgs/rabbitmq.svg
|
||||||
|
# port: 15672
|
||||||
|
|
||||||
services:
|
services:
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
image: rabbitmq:3
|
image: rabbitmq:3-management
|
||||||
environment:
|
environment:
|
||||||
- SERVICE_FQDN_RABBITMQ_5672
|
- SERVICE_FQDN_RABBITMQ_15672
|
||||||
- RABBITMQ_DEFAULT_USER=$SERVICE_USER_RABBITMQ
|
- RABBITMQ_DEFAULT_USER=$SERVICE_USER_RABBITMQ
|
||||||
- RABBITMQ_DEFAULT_PASS=$SERVICE_PASSWORD_RABBITMQ
|
- RABBITMQ_DEFAULT_PASS=$SERVICE_PASSWORD_RABBITMQ
|
||||||
|
- PORT=${PORT:-5672}
|
||||||
|
ports:
|
||||||
|
- ${PORT}:5672
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: rabbitmq-diagnostics -q ping
|
test: rabbitmq-diagnostics -q ping
|
||||||
interval: 30s
|
interval: 30s
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"coolify": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.323"
|
"version": "4.0.0-beta.324"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user