feat: add custom docker container options to all databases

This commit is contained in:
Andras Bacsai 2024-08-16 13:56:47 +02:00
parent c15740aa57
commit f106e6e37b
26 changed files with 319 additions and 132 deletions

View file

@ -21,7 +21,7 @@ public function handle(StandaloneClickhouse $database)
$this->database = $database; $this->database = $database;
$container_name = $this->database->uuid; $container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->commands = [ $this->commands = [
"echo 'Starting {$database->name}.'", "echo 'Starting {$database->name}.'",
@ -75,7 +75,7 @@ public function handle(StandaloneClickhouse $database)
], ],
], ],
]; ];
if (! is_null($this->database->limits_cpuset)) { if (!is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
} }
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@ -102,6 +102,11 @@ public function handle(StandaloneClickhouse $database)
if (count($volume_names) > 0) { if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names; $docker_compose['volumes'] = $volume_names;
} }
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
@ -120,10 +125,10 @@ private function generate_local_persistent_volumes()
$local_persistent_volumes = []; $local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) { foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
} else { } else {
$volume_name = $persistentStorage->name; $volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
} }
} }
@ -154,11 +159,11 @@ private function generate_environment_variables()
$environment_variables->push("$env->key=$env->real_value"); $environment_variables->push("$env->key=$env->real_value");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_USER'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('CLICKHOUSE_ADMIN_USER'))->isEmpty()) {
$environment_variables->push("CLICKHOUSE_ADMIN_USER={$this->database->clickhouse_admin_user}"); $environment_variables->push("CLICKHOUSE_ADMIN_USER={$this->database->clickhouse_admin_user}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('CLICKHOUSE_ADMIN_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('CLICKHOUSE_ADMIN_PASSWORD'))->isEmpty()) {
$environment_variables->push("CLICKHOUSE_ADMIN_PASSWORD={$this->database->clickhouse_admin_password}"); $environment_variables->push("CLICKHOUSE_ADMIN_PASSWORD={$this->database->clickhouse_admin_password}");
} }

View file

@ -23,7 +23,7 @@ public function handle(StandaloneDragonfly $database)
$startCommand = "dragonfly --requirepass {$this->database->dragonfly_password}"; $startCommand = "dragonfly --requirepass {$this->database->dragonfly_password}";
$container_name = $this->database->uuid; $container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->commands = [ $this->commands = [
"echo 'Starting {$database->name}.'", "echo 'Starting {$database->name}.'",
@ -75,7 +75,7 @@ public function handle(StandaloneDragonfly $database)
], ],
], ],
]; ];
if (! is_null($this->database->limits_cpuset)) { if (!is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
} }
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@ -102,6 +102,11 @@ public function handle(StandaloneDragonfly $database)
if (count($volume_names) > 0) { if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names; $docker_compose['volumes'] = $volume_names;
} }
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
@ -120,10 +125,10 @@ private function generate_local_persistent_volumes()
$local_persistent_volumes = []; $local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) { foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
} else { } else {
$volume_name = $persistentStorage->name; $volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
} }
} }
@ -154,7 +159,7 @@ private function generate_environment_variables()
$environment_variables->push("$env->key=$env->real_value"); $environment_variables->push("$env->key=$env->real_value");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
$environment_variables->push("REDIS_PASSWORD={$this->database->dragonfly_password}"); $environment_variables->push("REDIS_PASSWORD={$this->database->dragonfly_password}");
} }

View file

@ -24,7 +24,7 @@ public function handle(StandaloneKeydb $database)
$startCommand = "keydb-server --requirepass {$this->database->keydb_password} --appendonly yes"; $startCommand = "keydb-server --requirepass {$this->database->keydb_password} --appendonly yes";
$container_name = $this->database->uuid; $container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->commands = [ $this->commands = [
"echo 'Starting {$database->name}.'", "echo 'Starting {$database->name}.'",
@ -74,7 +74,7 @@ public function handle(StandaloneKeydb $database)
], ],
], ],
]; ];
if (! is_null($this->database->limits_cpuset)) { if (!is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
} }
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@ -101,15 +101,19 @@ public function handle(StandaloneKeydb $database)
if (count($volume_names) > 0) { if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names; $docker_compose['volumes'] = $volume_names;
} }
if (! is_null($this->database->keydb_conf) || ! empty($this->database->keydb_conf)) { if (!is_null($this->database->keydb_conf) || !empty($this->database->keydb_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [ $docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind', 'type' => 'bind',
'source' => $this->configuration_dir.'/keydb.conf', 'source' => $this->configuration_dir . '/keydb.conf',
'target' => '/etc/keydb/keydb.conf', 'target' => '/etc/keydb/keydb.conf',
'read_only' => true, 'read_only' => true,
]; ];
$docker_compose['services'][$container_name]['command'] = "keydb-server /etc/keydb/keydb.conf --requirepass {$this->database->keydb_password} --appendonly yes"; $docker_compose['services'][$container_name]['command'] = "keydb-server /etc/keydb/keydb.conf --requirepass {$this->database->keydb_password} --appendonly yes";
} }
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
@ -128,10 +132,10 @@ private function generate_local_persistent_volumes()
$local_persistent_volumes = []; $local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) { foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
} else { } else {
$volume_name = $persistentStorage->name; $volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
} }
} }
@ -162,7 +166,7 @@ private function generate_environment_variables()
$environment_variables->push("$env->key=$env->real_value"); $environment_variables->push("$env->key=$env->real_value");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
$environment_variables->push("REDIS_PASSWORD={$this->database->keydb_password}"); $environment_variables->push("REDIS_PASSWORD={$this->database->keydb_password}");
} }

View file

@ -21,7 +21,7 @@ public function handle(StandaloneMariadb $database)
$this->database = $database; $this->database = $database;
$container_name = $this->database->uuid; $container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->commands = [ $this->commands = [
"echo 'Starting {$database->name}.'", "echo 'Starting {$database->name}.'",
@ -69,7 +69,7 @@ public function handle(StandaloneMariadb $database)
], ],
], ],
]; ];
if (! is_null($this->database->limits_cpuset)) { if (!is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
} }
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@ -96,14 +96,19 @@ public function handle(StandaloneMariadb $database)
if (count($volume_names) > 0) { if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names; $docker_compose['volumes'] = $volume_names;
} }
if (! is_null($this->database->mariadb_conf) || ! empty($this->database->mariadb_conf)) { if (!is_null($this->database->mariadb_conf) || !empty($this->database->mariadb_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [ $docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind', 'type' => 'bind',
'source' => $this->configuration_dir.'/custom-config.cnf', 'source' => $this->configuration_dir . '/custom-config.cnf',
'target' => '/etc/mysql/conf.d/custom-config.cnf', 'target' => '/etc/mysql/conf.d/custom-config.cnf',
'read_only' => true, 'read_only' => true,
]; ];
} }
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
@ -122,10 +127,10 @@ private function generate_local_persistent_volumes()
$local_persistent_volumes = []; $local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) { foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
} else { } else {
$volume_name = $persistentStorage->name; $volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
} }
} }
@ -156,18 +161,18 @@ private function generate_environment_variables()
$environment_variables->push("$env->key=$env->real_value"); $environment_variables->push("$env->key=$env->real_value");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_ROOT_PASSWORD'))->isEmpty()) {
$environment_variables->push("MARIADB_ROOT_PASSWORD={$this->database->mariadb_root_password}"); $environment_variables->push("MARIADB_ROOT_PASSWORD={$this->database->mariadb_root_password}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_DATABASE'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_DATABASE'))->isEmpty()) {
$environment_variables->push("MARIADB_DATABASE={$this->database->mariadb_database}"); $environment_variables->push("MARIADB_DATABASE={$this->database->mariadb_database}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_USER'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_USER'))->isEmpty()) {
$environment_variables->push("MARIADB_USER={$this->database->mariadb_user}"); $environment_variables->push("MARIADB_USER={$this->database->mariadb_user}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MARIADB_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MARIADB_PASSWORD'))->isEmpty()) {
$environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}"); $environment_variables->push("MARIADB_PASSWORD={$this->database->mariadb_password}");
} }

View file

@ -23,7 +23,7 @@ public function handle(StandaloneMongodb $database)
$startCommand = 'mongod'; $startCommand = 'mongod';
$container_name = $this->database->uuid; $container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->commands = [ $this->commands = [
"echo 'Starting {$database->name}.'", "echo 'Starting {$database->name}.'",
@ -77,7 +77,7 @@ public function handle(StandaloneMongodb $database)
], ],
], ],
]; ];
if (! is_null($this->database->limits_cpuset)) { if (!is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
} }
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@ -104,23 +104,27 @@ public function handle(StandaloneMongodb $database)
if (count($volume_names) > 0) { if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names; $docker_compose['volumes'] = $volume_names;
} }
if (! is_null($this->database->mongo_conf) || ! empty($this->database->mongo_conf)) { if (!is_null($this->database->mongo_conf) || !empty($this->database->mongo_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [ $docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind', 'type' => 'bind',
'source' => $this->configuration_dir.'/mongod.conf', 'source' => $this->configuration_dir . '/mongod.conf',
'target' => '/etc/mongo/mongod.conf', 'target' => '/etc/mongo/mongod.conf',
'read_only' => true, 'read_only' => true,
]; ];
$docker_compose['services'][$container_name]['command'] = $startCommand.' --config /etc/mongo/mongod.conf'; $docker_compose['services'][$container_name]['command'] = $startCommand . ' --config /etc/mongo/mongod.conf';
} }
$this->add_default_database(); $this->add_default_database();
$docker_compose['services'][$container_name]['volumes'][] = [ $docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind', 'type' => 'bind',
'source' => $this->configuration_dir.'/docker-entrypoint-initdb.d', 'source' => $this->configuration_dir . '/docker-entrypoint-initdb.d',
'target' => '/docker-entrypoint-initdb.d', 'target' => '/docker-entrypoint-initdb.d',
'read_only' => true, 'read_only' => true,
]; ];
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
@ -139,10 +143,10 @@ private function generate_local_persistent_volumes()
$local_persistent_volumes = []; $local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) { foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
} else { } else {
$volume_name = $persistentStorage->name; $volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
} }
} }
@ -173,15 +177,15 @@ private function generate_environment_variables()
$environment_variables->push("$env->key=$env->real_value"); $environment_variables->push("$env->key=$env->real_value");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MONGO_INITDB_ROOT_USERNAME'))->isEmpty()) {
$environment_variables->push("MONGO_INITDB_ROOT_USERNAME={$this->database->mongo_initdb_root_username}"); $environment_variables->push("MONGO_INITDB_ROOT_USERNAME={$this->database->mongo_initdb_root_username}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_ROOT_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MONGO_INITDB_ROOT_PASSWORD'))->isEmpty()) {
$environment_variables->push("MONGO_INITDB_ROOT_PASSWORD={$this->database->mongo_initdb_root_password}"); $environment_variables->push("MONGO_INITDB_ROOT_PASSWORD={$this->database->mongo_initdb_root_password}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MONGO_INITDB_DATABASE'))->isEmpty()) {
$environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}"); $environment_variables->push("MONGO_INITDB_DATABASE={$this->database->mongo_initdb_database}");
} }

View file

@ -21,7 +21,7 @@ public function handle(StandaloneMysql $database)
$this->database = $database; $this->database = $database;
$container_name = $this->database->uuid; $container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->commands = [ $this->commands = [
"echo 'Starting {$database->name}.'", "echo 'Starting {$database->name}.'",
@ -69,7 +69,7 @@ public function handle(StandaloneMysql $database)
], ],
], ],
]; ];
if (! is_null($this->database->limits_cpuset)) { if (!is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
} }
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@ -96,14 +96,19 @@ public function handle(StandaloneMysql $database)
if (count($volume_names) > 0) { if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names; $docker_compose['volumes'] = $volume_names;
} }
if (! is_null($this->database->mysql_conf) || ! empty($this->database->mysql_conf)) { if (!is_null($this->database->mysql_conf) || !empty($this->database->mysql_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [ $docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind', 'type' => 'bind',
'source' => $this->configuration_dir.'/custom-config.cnf', 'source' => $this->configuration_dir . '/custom-config.cnf',
'target' => '/etc/mysql/conf.d/custom-config.cnf', 'target' => '/etc/mysql/conf.d/custom-config.cnf',
'read_only' => true, 'read_only' => true,
]; ];
} }
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
@ -122,10 +127,10 @@ private function generate_local_persistent_volumes()
$local_persistent_volumes = []; $local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) { foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
} else { } else {
$volume_name = $persistentStorage->name; $volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
} }
} }
@ -156,18 +161,18 @@ private function generate_environment_variables()
$environment_variables->push("$env->key=$env->real_value"); $environment_variables->push("$env->key=$env->real_value");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_ROOT_PASSWORD'))->isEmpty()) {
$environment_variables->push("MYSQL_ROOT_PASSWORD={$this->database->mysql_root_password}"); $environment_variables->push("MYSQL_ROOT_PASSWORD={$this->database->mysql_root_password}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_DATABASE'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_DATABASE'))->isEmpty()) {
$environment_variables->push("MYSQL_DATABASE={$this->database->mysql_database}"); $environment_variables->push("MYSQL_DATABASE={$this->database->mysql_database}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_USER'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_USER'))->isEmpty()) {
$environment_variables->push("MYSQL_USER={$this->database->mysql_user}"); $environment_variables->push("MYSQL_USER={$this->database->mysql_user}");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('MYSQL_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('MYSQL_PASSWORD'))->isEmpty()) {
$environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}"); $environment_variables->push("MYSQL_PASSWORD={$this->database->mysql_password}");
} }

View file

@ -37,6 +37,7 @@ public function handle(StandalonePostgresql $database)
$this->generate_init_scripts(); $this->generate_init_scripts();
$this->add_custom_conf(); $this->add_custom_conf();
$docker_compose = [ $docker_compose = [
'services' => [ 'services' => [
$container_name => [ $container_name => [
@ -126,6 +127,10 @@ public function handle(StandalonePostgresql $database)
'config_file=/etc/postgresql/postgresql.conf', 'config_file=/etc/postgresql/postgresql.conf',
]; ];
} }
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";

View file

@ -24,7 +24,7 @@ public function handle(StandaloneRedis $database)
$startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes"; $startCommand = "redis-server --requirepass {$this->database->redis_password} --appendonly yes";
$container_name = $this->database->uuid; $container_name = $this->database->uuid;
$this->configuration_dir = database_configuration_dir().'/'.$container_name; $this->configuration_dir = database_configuration_dir() . '/' . $container_name;
$this->commands = [ $this->commands = [
"echo 'Starting {$database->name}.'", "echo 'Starting {$database->name}.'",
@ -78,7 +78,7 @@ public function handle(StandaloneRedis $database)
], ],
], ],
]; ];
if (! is_null($this->database->limits_cpuset)) { if (!is_null($this->database->limits_cpuset)) {
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset); data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
} }
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
@ -105,15 +105,20 @@ public function handle(StandaloneRedis $database)
if (count($volume_names) > 0) { if (count($volume_names) > 0) {
$docker_compose['volumes'] = $volume_names; $docker_compose['volumes'] = $volume_names;
} }
if (! is_null($this->database->redis_conf) || ! empty($this->database->redis_conf)) { if (!is_null($this->database->redis_conf) || !empty($this->database->redis_conf)) {
$docker_compose['services'][$container_name]['volumes'][] = [ $docker_compose['services'][$container_name]['volumes'][] = [
'type' => 'bind', 'type' => 'bind',
'source' => $this->configuration_dir.'/redis.conf', 'source' => $this->configuration_dir . '/redis.conf',
'target' => '/usr/local/etc/redis/redis.conf', 'target' => '/usr/local/etc/redis/redis.conf',
'read_only' => true, 'read_only' => true,
]; ];
$docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes"; $docker_compose['services'][$container_name]['command'] = "redis-server /usr/local/etc/redis/redis.conf --requirepass {$this->database->redis_password} --appendonly yes";
} }
// Add custom docker run options
$docker_run_options = convert_docker_run_to_compose($this->database->custom_docker_run_options);
$docker_compose = generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $this->database->destination->network);
$docker_compose = Yaml::dump($docker_compose, 10); $docker_compose = Yaml::dump($docker_compose, 10);
$docker_compose_base64 = base64_encode($docker_compose); $docker_compose_base64 = base64_encode($docker_compose);
$this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null"; $this->commands[] = "echo '{$docker_compose_base64}' | base64 -d | tee $this->configuration_dir/docker-compose.yml > /dev/null";
@ -132,10 +137,10 @@ private function generate_local_persistent_volumes()
$local_persistent_volumes = []; $local_persistent_volumes = [];
foreach ($this->database->persistentStorages as $persistentStorage) { foreach ($this->database->persistentStorages as $persistentStorage) {
if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) { if ($persistentStorage->host_path !== '' && $persistentStorage->host_path !== null) {
$local_persistent_volumes[] = $persistentStorage->host_path.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $persistentStorage->host_path . ':' . $persistentStorage->mount_path;
} else { } else {
$volume_name = $persistentStorage->name; $volume_name = $persistentStorage->name;
$local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
} }
} }
@ -166,7 +171,7 @@ private function generate_environment_variables()
$environment_variables->push("$env->key=$env->real_value"); $environment_variables->push("$env->key=$env->real_value");
} }
if ($environment_variables->filter(fn ($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) { if ($environment_variables->filter(fn($env) => str($env)->contains('REDIS_PASSWORD'))->isEmpty()) {
$environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}"); $environment_variables->push("REDIS_PASSWORD={$this->database->redis_password}");
} }

View file

@ -31,6 +31,7 @@ class General extends Component
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -42,6 +43,7 @@ class General extends Component
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Run Options',
]; ];
public function mount() public function mount()
@ -54,7 +56,7 @@ public function mount()
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
if (! $this->server->isLogDrainEnabled()) { if (!$this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@ -71,14 +73,14 @@ public function instantSaveAdvanced()
public function instantSave() public function instantSave()
{ {
try { try {
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && !$this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
return; return;
} }
if ($this->database->is_public) { if ($this->database->is_public) {
if (! str($this->database->status)->startsWith('running')) { if (!str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.'); $this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false; $this->database->is_public = false;
@ -93,7 +95,7 @@ public function instantSave()
$this->db_url_public = $this->database->external_db_url; $this->db_url_public = $this->database->external_db_url;
$this->database->save(); $this->database->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->database->is_public = ! $this->database->is_public; $this->database->is_public = !$this->database->is_public;
return handleError($e, $this); return handleError($e, $this);
} }

View file

@ -30,6 +30,7 @@ class General extends Component
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -40,6 +41,7 @@ class General extends Component
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Run Options',
]; ];
public function mount() public function mount()
@ -52,7 +54,7 @@ public function mount()
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
if (! $this->server->isLogDrainEnabled()) { if (!$this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@ -86,14 +88,14 @@ public function submit()
public function instantSave() public function instantSave()
{ {
try { try {
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && !$this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
return; return;
} }
if ($this->database->is_public) { if ($this->database->is_public) {
if (! str($this->database->status)->startsWith('running')) { if (!str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.'); $this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false; $this->database->is_public = false;
@ -108,7 +110,7 @@ public function instantSave()
$this->db_url_public = $this->database->external_db_url; $this->db_url_public = $this->database->external_db_url;
$this->database->save(); $this->database->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->database->is_public = ! $this->database->is_public; $this->database->is_public = !$this->database->is_public;
return handleError($e, $this); return handleError($e, $this);
} }

View file

@ -31,6 +31,7 @@ class General extends Component
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -42,6 +43,7 @@ class General extends Component
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Run Options',
]; ];
public function mount() public function mount()
@ -55,7 +57,7 @@ public function mount()
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
if (! $this->server->isLogDrainEnabled()) { if (!$this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@ -92,14 +94,14 @@ public function submit()
public function instantSave() public function instantSave()
{ {
try { try {
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && !$this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
return; return;
} }
if ($this->database->is_public) { if ($this->database->is_public) {
if (! str($this->database->status)->startsWith('running')) { if (!str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.'); $this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false; $this->database->is_public = false;
@ -114,7 +116,7 @@ public function instantSave()
$this->db_url_public = $this->database->external_db_url; $this->db_url_public = $this->database->external_db_url;
$this->database->save(); $this->database->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->database->is_public = ! $this->database->is_public; $this->database->is_public = !$this->database->is_public;
return handleError($e, $this); return handleError($e, $this);
} }

View file

@ -34,6 +34,7 @@ class General extends Component
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -48,6 +49,7 @@ class General extends Component
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Options',
]; ];
public function mount() public function mount()
@ -61,7 +63,7 @@ public function mount()
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
if (! $this->server->isLogDrainEnabled()) { if (!$this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@ -98,14 +100,14 @@ public function submit()
public function instantSave() public function instantSave()
{ {
try { try {
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && !$this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
return; return;
} }
if ($this->database->is_public) { if ($this->database->is_public) {
if (! str($this->database->status)->startsWith('running')) { if (!str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.'); $this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false; $this->database->is_public = false;
@ -120,7 +122,7 @@ public function instantSave()
$this->db_url_public = $this->database->external_db_url; $this->db_url_public = $this->database->external_db_url;
$this->database->save(); $this->database->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->database->is_public = ! $this->database->is_public; $this->database->is_public = !$this->database->is_public;
return handleError($e, $this); return handleError($e, $this);
} }

View file

@ -33,6 +33,7 @@ class General extends Component
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -46,6 +47,7 @@ class General extends Component
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Run Options',
]; ];
public function mount() public function mount()
@ -59,7 +61,7 @@ public function mount()
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
if (! $this->server->isLogDrainEnabled()) { if (!$this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@ -99,14 +101,14 @@ public function submit()
public function instantSave() public function instantSave()
{ {
try { try {
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && !$this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
return; return;
} }
if ($this->database->is_public) { if ($this->database->is_public) {
if (! str($this->database->status)->startsWith('running')) { if (!str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.'); $this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false; $this->database->is_public = false;
@ -121,7 +123,7 @@ public function instantSave()
$this->db_url_public = $this->database->external_db_url; $this->db_url_public = $this->database->external_db_url;
$this->database->save(); $this->database->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->database->is_public = ! $this->database->is_public; $this->database->is_public = !$this->database->is_public;
return handleError($e, $this); return handleError($e, $this);
} }

View file

@ -34,6 +34,7 @@ class General extends Component
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -48,6 +49,7 @@ class General extends Component
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Run Options',
]; ];
public function mount() public function mount()
@ -60,7 +62,7 @@ public function mount()
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
if (! $this->server->isLogDrainEnabled()) { if (!$this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@ -97,14 +99,14 @@ public function submit()
public function instantSave() public function instantSave()
{ {
try { try {
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && !$this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
return; return;
} }
if ($this->database->is_public) { if ($this->database->is_public) {
if (! str($this->database->status)->startsWith('running')) { if (!str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.'); $this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false; $this->database->is_public = false;
@ -119,7 +121,7 @@ public function instantSave()
$this->db_url_public = $this->database->external_db_url; $this->db_url_public = $this->database->external_db_url;
$this->database->save(); $this->database->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->database->is_public = ! $this->database->is_public; $this->database->is_public = !$this->database->is_public;
return handleError($e, $this); return handleError($e, $this);
} }

View file

@ -49,6 +49,7 @@ public function getListeners()
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -65,6 +66,7 @@ public function getListeners()
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Run Options',
]; ];
public function mount() public function mount()

View file

@ -31,6 +31,7 @@ class General extends Component
'database.is_public' => 'nullable|boolean', 'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer', 'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean', 'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
]; ];
protected $validationAttributes = [ protected $validationAttributes = [
@ -42,6 +43,7 @@ class General extends Component
'database.ports_mappings' => 'Port Mapping', 'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public', 'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port', 'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Options',
]; ];
public function mount() public function mount()
@ -55,7 +57,7 @@ public function mount()
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
if (! $this->server->isLogDrainEnabled()) { if (!$this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@ -86,14 +88,14 @@ public function submit()
public function instantSave() public function instantSave()
{ {
try { try {
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && !$this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
return; return;
} }
if ($this->database->is_public) { if ($this->database->is_public) {
if (! str($this->database->status)->startsWith('running')) { if (!str($this->database->status)->startsWith('running')) {
$this->dispatch('error', 'Database must be started to be publicly accessible.'); $this->dispatch('error', 'Database must be started to be publicly accessible.');
$this->database->is_public = false; $this->database->is_public = false;
@ -108,7 +110,7 @@ public function instantSave()
$this->db_url_public = $this->database->external_db_url; $this->db_url_public = $this->database->external_db_url;
$this->database->save(); $this->database->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
$this->database->is_public = ! $this->database->is_public; $this->database->is_public = !$this->database->is_public;
return handleError($e, $this); return handleError($e, $this);
} }

View file

@ -13,13 +13,13 @@
function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pullRequestId = null, ?bool $includePullrequests = false): Collection function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pullRequestId = null, ?bool $includePullrequests = false): Collection
{ {
$containers = collect([]); $containers = collect([]);
if (! $server->isSwarm()) { if (!$server->isSwarm()) {
$containers = instant_remote_process(["docker ps -a --filter='label=coolify.applicationId={$id}' --format '{{json .}}' "], $server); $containers = instant_remote_process(["docker ps -a --filter='label=coolify.applicationId={$id}' --format '{{json .}}' "], $server);
$containers = format_docker_command_output_to_json($containers); $containers = format_docker_command_output_to_json($containers);
$containers = $containers->map(function ($container) use ($pullRequestId, $includePullrequests) { $containers = $containers->map(function ($container) use ($pullRequestId, $includePullrequests) {
$labels = data_get($container, 'Labels'); $labels = data_get($container, 'Labels');
if (! str($labels)->contains('coolify.pullRequestId=')) { if (!str($labels)->contains('coolify.pullRequestId=')) {
data_set($container, 'Labels', $labels.",coolify.pullRequestId={$pullRequestId}"); data_set($container, 'Labels', $labels . ",coolify.pullRequestId={$pullRequestId}");
return $container; return $container;
} }
@ -51,14 +51,14 @@ function format_docker_command_output_to_json($rawOutput): Collection
try { try {
return $outputLines return $outputLines
->reject(fn ($line) => empty($line)) ->reject(fn($line) => empty($line))
->map(fn ($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR)); ->map(fn($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR));
} catch (\Throwable $e) { } catch (\Throwable $e) {
return collect([]); return collect([]);
} }
} }
function format_docker_labels_to_json(string|array $rawOutput): Collection function format_docker_labels_to_json(string | array $rawOutput): Collection
{ {
if (is_array($rawOutput)) { if (is_array($rawOutput)) {
return collect($rawOutput); return collect($rawOutput);
@ -66,7 +66,7 @@ function format_docker_labels_to_json(string|array $rawOutput): Collection
$outputLines = explode(PHP_EOL, $rawOutput); $outputLines = explode(PHP_EOL, $rawOutput);
return collect($outputLines) return collect($outputLines)
->reject(fn ($line) => empty($line)) ->reject(fn($line) => empty($line))
->map(function ($outputLine) { ->map(function ($outputLine) {
$outputArray = explode(',', $outputLine); $outputArray = explode(',', $outputLine);
@ -116,7 +116,7 @@ function getContainerStatus(Server $server, string $container_id, bool $all_data
} else { } else {
$container = instant_remote_process(["docker inspect --format '{{json .}}' {$container_id}"], $server, $throwError); $container = instant_remote_process(["docker inspect --format '{{json .}}' {$container_id}"], $server, $throwError);
} }
if (! $container) { if (!$container) {
return 'exited'; return 'exited';
} }
$container = format_docker_command_output_to_json($container); $container = format_docker_command_output_to_json($container);
@ -143,13 +143,13 @@ function generateApplicationContainerName(Application $application, $pull_reques
$consistent_container_name = $application->settings->is_consistent_container_name_enabled; $consistent_container_name = $application->settings->is_consistent_container_name_enabled;
$now = now()->format('Hisu'); $now = now()->format('Hisu');
if ($pull_request_id !== 0 && $pull_request_id !== null) { if ($pull_request_id !== 0 && $pull_request_id !== null) {
return $application->uuid.'-pr-'.$pull_request_id; return $application->uuid . '-pr-' . $pull_request_id;
} else { } else {
if ($consistent_container_name) { if ($consistent_container_name) {
return $application->uuid; return $application->uuid;
} }
return $application->uuid.'-'.$now; return $application->uuid . '-' . $now;
} }
} }
function get_port_from_dockerfile($dockerfile): ?int function get_port_from_dockerfile($dockerfile): ?int
@ -174,19 +174,19 @@ function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'applica
{ {
$labels = collect([]); $labels = collect([]);
$labels->push('coolify.managed=true'); $labels->push('coolify.managed=true');
$labels->push('coolify.version='.config('version')); $labels->push('coolify.version=' . config('version'));
$labels->push('coolify.'.$type.'Id='.$id); $labels->push('coolify.' . $type . 'Id=' . $id);
$labels->push("coolify.type=$type"); $labels->push("coolify.type=$type");
$labels->push('coolify.name='.$name); $labels->push('coolify.name=' . $name);
$labels->push('coolify.pullRequestId='.$pull_request_id); $labels->push('coolify.pullRequestId=' . $pull_request_id);
if ($type === 'service') { if ($type === 'service') {
$subId && $labels->push('coolify.service.subId='.$subId); $subId && $labels->push('coolify.service.subId=' . $subId);
$subType && $labels->push('coolify.service.subType='.$subType); $subType && $labels->push('coolify.service.subType=' . $subType);
} }
return $labels; return $labels;
} }
function generateServiceSpecificFqdns(ServiceApplication|Application $resource) function generateServiceSpecificFqdns(ServiceApplication | Application $resource)
{ {
if ($resource->getMorphClass() === 'App\Models\ServiceApplication') { if ($resource->getMorphClass() === 'App\Models\ServiceApplication') {
$uuid = data_get($resource, 'uuid'); $uuid = data_get($resource, 'uuid');
@ -213,17 +213,17 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource)
} }
if (is_null($MINIO_BROWSER_REDIRECT_URL?->value)) { if (is_null($MINIO_BROWSER_REDIRECT_URL?->value)) {
$MINIO_BROWSER_REDIRECT_URL?->update([ $MINIO_BROWSER_REDIRECT_URL?->update([
'value' => generateFqdn($server, 'console-'.$uuid), 'value' => generateFqdn($server, 'console-' . $uuid),
]); ]);
} }
if (is_null($MINIO_SERVER_URL?->value)) { if (is_null($MINIO_SERVER_URL?->value)) {
$MINIO_SERVER_URL?->update([ $MINIO_SERVER_URL?->update([
'value' => generateFqdn($server, 'minio-'.$uuid), 'value' => generateFqdn($server, 'minio-' . $uuid),
]); ]);
} }
$payload = collect([ $payload = collect([
$MINIO_BROWSER_REDIRECT_URL->value.':9001', $MINIO_BROWSER_REDIRECT_URL->value . ':9001',
$MINIO_SERVER_URL->value.':9000', $MINIO_SERVER_URL->value . ':9000',
]); ]);
break; break;
case $type?->contains('logto'): case $type?->contains('logto'):
@ -234,17 +234,17 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource)
} }
if (is_null($LOGTO_ENDPOINT?->value)) { if (is_null($LOGTO_ENDPOINT?->value)) {
$LOGTO_ENDPOINT?->update([ $LOGTO_ENDPOINT?->update([
'value' => generateFqdn($server, 'logto-'.$uuid), 'value' => generateFqdn($server, 'logto-' . $uuid),
]); ]);
} }
if (is_null($LOGTO_ADMIN_ENDPOINT?->value)) { if (is_null($LOGTO_ADMIN_ENDPOINT?->value)) {
$LOGTO_ADMIN_ENDPOINT?->update([ $LOGTO_ADMIN_ENDPOINT?->update([
'value' => generateFqdn($server, 'logto-admin-'.$uuid), 'value' => generateFqdn($server, 'logto-admin-' . $uuid),
]); ]);
} }
$payload = collect([ $payload = collect([
$LOGTO_ENDPOINT->value.':3001', $LOGTO_ENDPOINT->value . ':3001',
$LOGTO_ADMIN_ENDPOINT->value.':3002', $LOGTO_ADMIN_ENDPOINT->value . ':3002',
]); ]);
break; break;
} }
@ -267,7 +267,7 @@ function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains,
$host_without_www = str($host)->replace('www.', ''); $host_without_www = str($host)->replace('www.', '');
$schema = $url->getScheme(); $schema = $url->getScheme();
$port = $url->getPort(); $port = $url->getPort();
if (is_null($port) && ! is_null($onlyPort)) { if (is_null($port) && !is_null($onlyPort)) {
$port = $onlyPort; $port = $onlyPort;
} }
$labels->push("caddy_{$loop}={$schema}://{$host}"); $labels->push("caddy_{$loop}={$schema}://{$host}");
@ -283,7 +283,7 @@ function fqdnLabelsForCaddy(string $network, string $uuid, Collection $domains,
if ($is_gzip_enabled) { if ($is_gzip_enabled) {
$labels->push("caddy_{$loop}.encode=zstd gzip"); $labels->push("caddy_{$loop}.encode=zstd gzip");
} }
if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) { if ($redirect_direction === 'www' && !str($host)->startsWith('www.')) {
$labels->push("caddy_{$loop}.redir={$schema}://www.{$host}{uri}"); $labels->push("caddy_{$loop}.redir={$schema}://www.{$host}{uri}");
} }
if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) { if ($redirect_direction === 'non-www' && str($host)->startsWith('www.')) {
@ -347,7 +347,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$path = $url->getPath(); $path = $url->getPath();
$schema = $url->getScheme(); $schema = $url->getScheme();
$port = $url->getPort(); $port = $url->getPort();
if (is_null($port) && ! is_null($onlyPort)) { if (is_null($port) && !is_null($onlyPort)) {
$port = $onlyPort; $port = $onlyPort;
} }
$http_label = "http-{$loop}-{$uuid}"; $http_label = "http-{$loop}-{$uuid}";
@ -383,7 +383,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
} }
if ($path !== '/') { if ($path !== '/') {
$middlewares = collect([]); $middlewares = collect([]);
if ($is_stripprefix_enabled && ! str($image)->contains('ghost')) { if ($is_stripprefix_enabled && !str($image)->contains('ghost')) {
$labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}"); $labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}");
$middlewares->push("{$https_label}-stripprefix"); $middlewares->push("{$https_label}-stripprefix");
} }
@ -403,7 +403,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$labels = $labels->merge($redirect_to_non_www); $labels = $labels->merge($redirect_to_non_www);
$middlewares->push($to_non_www_name); $middlewares->push($to_non_www_name);
} }
if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) { if ($redirect_direction === 'www' && !str($host)->startsWith('www.')) {
$labels = $labels->merge($redirect_to_www); $labels = $labels->merge($redirect_to_www);
$middlewares->push($to_www_name); $middlewares->push($to_www_name);
} }
@ -429,7 +429,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$labels = $labels->merge($redirect_to_non_www); $labels = $labels->merge($redirect_to_non_www);
$middlewares->push($to_non_www_name); $middlewares->push($to_non_www_name);
} }
if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) { if ($redirect_direction === 'www' && !str($host)->startsWith('www.')) {
$labels = $labels->merge($redirect_to_www); $labels = $labels->merge($redirect_to_www);
$middlewares->push($to_www_name); $middlewares->push($to_www_name);
} }
@ -461,7 +461,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
} }
if ($path !== '/') { if ($path !== '/') {
$middlewares = collect([]); $middlewares = collect([]);
if ($is_stripprefix_enabled && ! str($image)->contains('ghost')) { if ($is_stripprefix_enabled && !str($image)->contains('ghost')) {
$labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}"); $labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}");
$middlewares->push("{$http_label}-stripprefix"); $middlewares->push("{$http_label}-stripprefix");
} }
@ -481,7 +481,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$labels = $labels->merge($redirect_to_non_www); $labels = $labels->merge($redirect_to_non_www);
$middlewares->push($to_non_www_name); $middlewares->push($to_non_www_name);
} }
if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) { if ($redirect_direction === 'www' && !str($host)->startsWith('www.')) {
$labels = $labels->merge($redirect_to_www); $labels = $labels->merge($redirect_to_www);
$middlewares->push($to_www_name); $middlewares->push($to_www_name);
} }
@ -507,7 +507,7 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
$labels = $labels->merge($redirect_to_non_www); $labels = $labels->merge($redirect_to_non_www);
$middlewares->push($to_non_www_name); $middlewares->push($to_non_www_name);
} }
if ($redirect_direction === 'www' && ! str($host)->startsWith('www.')) { if ($redirect_direction === 'www' && !str($host)->startsWith('www.')) {
$labels = $labels->merge($redirect_to_www); $labels = $labels->merge($redirect_to_www);
$middlewares->push($to_www_name); $middlewares->push($to_www_name);
} }
@ -534,7 +534,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
$pull_request_id = data_get($preview, 'pull_request_id', 0); $pull_request_id = data_get($preview, 'pull_request_id', 0);
$appUuid = $application->uuid; $appUuid = $application->uuid;
if ($pull_request_id !== 0) { if ($pull_request_id !== 0) {
$appUuid = $appUuid.'-pr-'.$pull_request_id; $appUuid = $appUuid . '-pr-' . $pull_request_id;
} }
$labels = collect([]); $labels = collect([]);
if ($pull_request_id === 0) { if ($pull_request_id === 0) {
@ -706,7 +706,7 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
// Easily get mappings from https://github.com/composerize/composerize/blob/master/packages/composerize/src/mappings.js // Easily get mappings from https://github.com/composerize/composerize/blob/master/packages/composerize/src/mappings.js
foreach ($options as $option => $value) { foreach ($options as $option => $value) {
// ray($option,$value); // ray($option,$value);
if (! data_get($mapping, $option)) { if (!data_get($mapping, $option)) {
continue; continue;
} }
if ($option === '--ulimit') { if ($option === '--ulimit') {
@ -737,7 +737,7 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
} else { } else {
if ($list_options->contains($option)) { if ($list_options->contains($option)) {
if ($compose_options->has($mapping[$option])) { if ($compose_options->has($mapping[$option])) {
$compose_options->put($mapping[$option], $options->get($mapping[$option]).','.$value); $compose_options->put($mapping[$option], $options->get($mapping[$option]) . ',' . $value);
} else { } else {
$compose_options->put($mapping[$option], $value); $compose_options->put($mapping[$option], $value);
} }
@ -755,7 +755,26 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
return $compose_options->toArray(); return $compose_options->toArray();
} }
function validateComposeFile(string $compose, int $server_id): string|Throwable function generate_custom_docker_run_options_for_databases($docker_run_options, $docker_compose, $container_name, $network)
{
$ipv4 = data_get($docker_run_options, 'ip.0');
$ipv6 = data_get($docker_run_options, 'ip6.0');
data_forget($docker_run_options, 'ip');
data_forget($docker_run_options, 'ip6');
if ($ipv4 || $ipv6) {
data_forget($docker_compose['services'][$container_name], 'networks');
}
if ($ipv4) {
$docker_compose['services'][$container_name]['networks'][$network]['ipv4_address'] = $ipv4;
}
if ($ipv6) {
$docker_compose['services'][$container_name]['networks'][$network]['ipv6_address'] = $ipv6;
}
$docker_compose['services'][$container_name] = array_merge_recursive($docker_compose['services'][$container_name], $docker_run_options);
return $docker_compose;
}
function validateComposeFile(string $compose, int $server_id): string | Throwable
{ {
return 'OK'; return 'OK';
try { try {

View file

@ -0,0 +1,70 @@
<?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('standalone_postgresqls', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
Schema::table('standalone_mysqls', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
Schema::table('standalone_mariadbs', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
Schema::table('standalone_redis', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
Schema::table('standalone_clickhouses', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
Schema::table('standalone_dragonflies', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
Schema::table('standalone_keydbs', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
Schema::table('standalone_mongodbs', function (Blueprint $table) {
$table->text('custom_docker_run_options')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('standalone_postgresqls', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
Schema::table('standalone_mysqls', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
Schema::table('standalone_mariadbs', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
Schema::table('standalone_redis', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
Schema::table('standalone_clickhouses', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
Schema::table('standalone_dragonflies', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
Schema::table('standalone_keydbs', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
Schema::table('standalone_mongodbs', function (Blueprint $table) {
$table->dropColumn('custom_docker_run_options');
});
}
};

View file

@ -21,14 +21,18 @@
readonly helper="You can only change this in the database." /> readonly helper="You can only change this in the database." />
</div> </div>
@else @else
<div class="pt-8 dark:text-warning">Please verify these values. You can only modify them before the initial <div class=" dark:text-warning">Please verify these values. You can only modify them before the initial
start. After that, you need to modify it in the database. start. After that, you need to modify it in the database.
</div> </div>
<div class="flex gap-2 pb-8"> <div class="flex gap-2">
<x-forms.input label="Username" id="database.clickhouse_admin_user" required /> <x-forms.input label="Username" id="database.clickhouse_admin_user" required />
<x-forms.input label="Password" id="database.clickhouse_admin_password" type="password" required /> <x-forms.input label="Password" id="database.clickhouse_admin_password" type="password" required />
</div> </div>
@endif @endif
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">

View file

@ -11,6 +11,10 @@
<x-forms.input label="Description" id="database.description" /> <x-forms.input label="Description" id="database.description" />
<x-forms.input label="Image" id="database.image" required /> <x-forms.input label="Image" id="database.image" required />
</div> </div>
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">

View file

@ -12,6 +12,10 @@
<x-forms.input label="Image" id="database.image" required <x-forms.input label="Image" id="database.image" required
helper="For all available images, check here:<br><br><a target='_blank' href=https://hub.docker.com/r/eqalpha/keydb'>https://hub.docker.com/r/eqalpha/keydb</a>" /> helper="For all available images, check here:<br><br><a target='_blank' href=https://hub.docker.com/r/eqalpha/keydb'>https://hub.docker.com/r/eqalpha/keydb</a>" />
</div> </div>
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">

View file

@ -16,30 +16,40 @@
automations (like backups) won't work. automations (like backups) won't work.
</div> </div>
@if ($database->started_at) @if ($database->started_at)
<div class="flex flex-col gap-2"> <div class="flex xl:flex-row flex-col gap-2">
<x-forms.input label="Root Password" id="database.mariadb_root_password" type="password" required <x-forms.input label="Root Password" id="database.mariadb_root_password" type="password" required
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
<x-forms.input label="Normal User" id="database.mariadb_user" required <x-forms.input label="Normal User" id="database.mariadb_user" required
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
<x-forms.input label="Normal User Password" id="database.mariadb_password" type="password" required <x-forms.input label="Normal User Password" id="database.mariadb_password" type="password" required
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
</div>
<div class="flex flex-col gap-2">
<x-forms.input label="Initial Database" id="database.mariadb_database" <x-forms.input label="Initial Database" id="database.mariadb_database"
placeholder="If empty, it will be the same as Username." readonly placeholder="If empty, it will be the same as Username." readonly
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div> </div>
@else @else
<div class="flex flex-col gap-2 pb-2"> <div class="flex xl:flex-row flex-col gap-2 pb-2">
<x-forms.input label="Root Password" id="database.mariadb_root_password" type="password" <x-forms.input label="Root Password" id="database.mariadb_root_password" type="password"
helper="You can only change this in the database." /> helper="You can only change this in the database." />
<x-forms.input label="Normal User" id="database.mariadb_user" required <x-forms.input label="Normal User" id="database.mariadb_user" required
helper="You can only change this in the database." /> helper="You can only change this in the database." />
<x-forms.input label="Normal User Password" id="database.mariadb_password" type="password" required <x-forms.input label="Normal User Password" id="database.mariadb_password" type="password" required
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div>
<div class="flex flex-col gap-2">
<x-forms.input label="Initial Database" id="database.mariadb_database" <x-forms.input label="Initial Database" id="database.mariadb_database"
placeholder="If empty, it will be the same as Username." placeholder="If empty, it will be the same as Username."
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div> </div>
@endif @endif
<div class="pt-2">
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
</div>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">

View file

@ -16,7 +16,7 @@
automations (like backups) won't work. automations (like backups) won't work.
</div> </div>
@if ($database->started_at) @if ($database->started_at)
<div class="flex flex-col gap-2"> <div class="flex xl:flex-row flex-col gap-2">
<x-forms.input label="Initial Username" id="database.mongo_initdb_root_username" <x-forms.input label="Initial Username" id="database.mongo_initdb_root_username"
placeholder="If empty: postgres" placeholder="If empty: postgres"
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
@ -28,7 +28,7 @@
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div> </div>
@else @else
<div class="flex flex-col gap-2 pb-2"> <div class="flex xl:flex-row flex-col gap-2 pb-2">
<x-forms.input required label="Username" id="database.mongo_initdb_root_username" <x-forms.input required label="Username" id="database.mongo_initdb_root_username"
placeholder="If empty: postgres" /> placeholder="If empty: postgres" />
<x-forms.input label="Password" id="database.mongo_initdb_root_password" type="password" required /> <x-forms.input label="Password" id="database.mongo_initdb_root_password" type="password" required />
@ -36,6 +36,10 @@
placeholder="If empty, it will be the same as Username." /> placeholder="If empty, it will be the same as Username." />
</div> </div>
@endif @endif
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">

View file

@ -16,30 +16,40 @@
automations (like backups) won't work. automations (like backups) won't work.
</div> </div>
@if ($database->started_at) @if ($database->started_at)
<div class="flex flex-col gap-2"> <div class="flex xl:flex-row flex-col gap-2">
<x-forms.input label="Root Password" id="database.mysql_root_password" type="password" required <x-forms.input label="Root Password" id="database.mysql_root_password" type="password" required
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
<x-forms.input label="Normal User" id="database.mysql_user" required <x-forms.input label="Normal User" id="database.mysql_user" required
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
<x-forms.input label="Normal User Password" id="database.mysql_password" type="password" required <x-forms.input label="Normal User Password" id="database.mysql_password" type="password" required
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
</div>
<div class="flex flex-col gap-2">
<x-forms.input label="Initial Database" id="database.mysql_database" <x-forms.input label="Initial Database" id="database.mysql_database"
placeholder="If empty, it will be the same as Username." readonly placeholder="If empty, it will be the same as Username." readonly
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div> </div>
@else @else
<div class="flex flex-col gap-4 pb-2"> <div class="flex xl:flex-row flex-col gap-4 pb-2">
<x-forms.input label="Root Password" id="database.mysql_root_password" type="password" <x-forms.input label="Root Password" id="database.mysql_root_password" type="password"
helper="You can only change this in the database." /> helper="You can only change this in the database." />
<x-forms.input label="Normal User" id="database.mysql_user" required <x-forms.input label="Normal User" id="database.mysql_user" required
helper="You can only change this in the database." /> helper="You can only change this in the database." />
<x-forms.input label="Normal User Password" id="database.mysql_password" type="password" required <x-forms.input label="Normal User Password" id="database.mysql_password" type="password" required
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div>
<div class="flex flex-col gap-2">
<x-forms.input label="Initial Database" id="database.mysql_database" <x-forms.input label="Initial Database" id="database.mysql_database"
placeholder="If empty, it will be the same as Username." placeholder="If empty, it will be the same as Username."
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div> </div>
@endif @endif
<div class="pt-2">
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
</div>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">

View file

@ -30,7 +30,7 @@
automations (like backups) won't work. automations (like backups) won't work.
</div> </div>
@if ($database->started_at) @if ($database->started_at)
<div class="flex flex-col gap-2"> <div class="flex xl:flex-row flex-col gap-2">
<x-forms.input label="Username" id="database.postgres_user" placeholder="If empty: postgres" <x-forms.input label="Username" id="database.postgres_user" placeholder="If empty: postgres"
helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." /> helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." />
<x-forms.input label="Password" id="database.postgres_password" type="password" required <x-forms.input label="Password" id="database.postgres_password" type="password" required
@ -40,7 +40,7 @@
helper="You can only change this in the database." /> helper="You can only change this in the database." />
</div> </div>
@else @else
<div class="flex flex-col gap-2 pb-2"> <div class="flex xl:flex-row flex-col gap-2 pb-2">
<x-forms.input label="Username" id="database.postgres_user" placeholder="If empty: postgres" /> <x-forms.input label="Username" id="database.postgres_user" placeholder="If empty: postgres" />
<x-forms.input label="Password" id="database.postgres_password" type="password" required /> <x-forms.input label="Password" id="database.postgres_password" type="password" required />
<x-forms.input label="Initial Database" id="database.postgres_db" <x-forms.input label="Initial Database" id="database.postgres_db"
@ -53,6 +53,10 @@
<x-forms.input label="Host Auth Method" id="database.postgres_host_auth_method" <x-forms.input label="Host Auth Method" id="database.postgres_host_auth_method"
placeholder="If empty, use default. See in docker docs." /> placeholder="If empty, use default. See in docker docs." />
</div> </div>
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">

View file

@ -12,6 +12,10 @@
<x-forms.input label="Image" id="database.image" required <x-forms.input label="Image" id="database.image" required
helper="For all available images, check here:<br><br><a target='_blank' href='https://hub.docker.com/_/redis'>https://hub.docker.com/_/redis</a>" /> helper="For all available images, check here:<br><br><a target='_blank' href='https://hub.docker.com/_/redis'>https://hub.docker.com/_/redis</a>" />
</div> </div>
<x-forms.input
helper="You can add custom docker run options that will be used when your container is started.<br>Note: Not all options are supported, as they could mess up Coolify's automation and could cause bad experience for users.<br><br>Check the <a class='underline dark:text-white' href='https://coolify.io/docs/knowledge-base/docker/custom-commands'>docs.</a>"
placeholder="--cap-add SYS_ADMIN --device=/dev/fuse --security-opt apparmor:unconfined --ulimit nofile=1024:1024 --tmpfs /run:rw,noexec,nosuid,size=65536k"
id="database.custom_docker_run_options" label="Custom Docker Options" />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<h3 class="py-2">Network</h3> <h3 class="py-2">Network</h3>
<div class="flex items-end gap-2"> <div class="flex items-end gap-2">