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 @@ class StartClickhouse
$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 @@ class StartClickhouse
], ],
], ],
]; ];
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 @@ class StartClickhouse
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 @@ class StartClickhouse
$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 @@ class StartClickhouse
$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 @@ class StartDragonfly
$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 @@ class StartDragonfly
], ],
], ],
]; ];
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 @@ class StartDragonfly
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 @@ class StartDragonfly
$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 @@ class StartDragonfly
$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 @@ class StartKeydb
$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 @@ class StartKeydb
], ],
], ],
]; ];
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 @@ class StartKeydb
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 @@ class StartKeydb
$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 @@ class StartKeydb
$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 @@ class StartMariadb
$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 @@ class StartMariadb
], ],
], ],
]; ];
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 @@ class StartMariadb
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 @@ class StartMariadb
$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 @@ class StartMariadb
$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 @@ class StartMongodb
$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 @@ class StartMongodb
], ],
], ],
]; ];
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 @@ class StartMongodb
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 @@ class StartMongodb
$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 @@ class StartMongodb
$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 @@ class StartMysql
$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 @@ class StartMysql
], ],
], ],
]; ];
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 @@ class StartMysql
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 @@ class StartMysql
$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 @@ class StartMysql
$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 @@ class StartPostgresql
$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 @@ class StartPostgresql
'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 @@ class StartRedis
$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 @@ class StartRedis
], ],
], ],
]; ];
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 @@ class StartRedis
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 @@ class StartRedis
$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 @@ class StartRedis
$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 @@ class General extends Component
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ class General extends Component
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ class General extends Component
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ class General extends Component
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ class General extends Component
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ class General extends Component
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ 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 = [
@@ -65,6 +66,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()

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 @@ class General extends Component
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 @@ class General extends Component
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 @@ class General extends Component
$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 @@ use Visus\Cuid2\Cuid2;
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">