Merge branch 'next' into main
This commit is contained in:
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
app/Console/Commands/OpenApi.php
Normal file
26
app/Console/Commands/OpenApi.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Process;
|
||||||
|
|
||||||
|
class OpenApi extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'openapi';
|
||||||
|
|
||||||
|
protected $description = 'Generate OpenApi file.';
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// Generate OpenAPI documentation
|
||||||
|
echo "Generating OpenAPI documentation.\n";
|
||||||
|
$process = Process::run(['/var/www/html/vendor/bin/openapi', 'app', '-o', 'openapi.yaml']);
|
||||||
|
$error = $process->errorOutput();
|
||||||
|
$error = preg_replace('/^.*an object literal,.*$/m', '', $error);
|
||||||
|
$error = preg_replace('/^\h*\v+/m', '', $error);
|
||||||
|
echo $error;
|
||||||
|
echo $process->output();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -201,7 +201,7 @@ class ApplicationsController extends Controller
|
|||||||
#[OA\Post(
|
#[OA\Post(
|
||||||
summary: 'Create (Private - GH App)',
|
summary: 'Create (Private - GH App)',
|
||||||
description: 'Create new application based on a private repository through a Github App.',
|
description: 'Create new application based on a private repository through a Github App.',
|
||||||
path: '/applications/private-gh-app',
|
path: '/applications/private-github-app',
|
||||||
security: [
|
security: [
|
||||||
['bearerAuth' => []],
|
['bearerAuth' => []],
|
||||||
],
|
],
|
||||||
@@ -1450,7 +1450,7 @@ class ApplicationsController extends Controller
|
|||||||
], 404);
|
], 404);
|
||||||
}
|
}
|
||||||
$server = $application->destination->server;
|
$server = $application->destination->server;
|
||||||
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect'];
|
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy'];
|
||||||
|
|
||||||
$validator = customApiValidator($request->all(), [
|
$validator = customApiValidator($request->all(), [
|
||||||
sharedDataApplications(),
|
sharedDataApplications(),
|
||||||
@@ -1526,6 +1526,10 @@ class ApplicationsController extends Controller
|
|||||||
}
|
}
|
||||||
$request->offsetUnset('docker_compose_domains');
|
$request->offsetUnset('docker_compose_domains');
|
||||||
}
|
}
|
||||||
|
$instantDeploy = $request->instant_deploy;
|
||||||
|
|
||||||
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
|
|
||||||
$data = $request->all();
|
$data = $request->all();
|
||||||
data_set($data, 'fqdn', $domains);
|
data_set($data, 'fqdn', $domains);
|
||||||
if ($dockerComposeDomainsJson->count() > 0) {
|
if ($dockerComposeDomainsJson->count() > 0) {
|
||||||
@@ -1534,6 +1538,16 @@ class ApplicationsController extends Controller
|
|||||||
$application->fill($data);
|
$application->fill($data);
|
||||||
$application->save();
|
$application->save();
|
||||||
|
|
||||||
|
if ($instantDeploy) {
|
||||||
|
$deployment_uuid = new Cuid2;
|
||||||
|
|
||||||
|
queue_application_deployment(
|
||||||
|
application: $application,
|
||||||
|
deployment_uuid: $deployment_uuid,
|
||||||
|
is_api: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'uuid' => $application->uuid,
|
'uuid' => $application->uuid,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\EnvironmentVariable;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class EnvironmentVariablesController extends Controller
|
|
||||||
{
|
|
||||||
public function delete_env_by_uuid(Request $request)
|
|
||||||
{
|
|
||||||
$teamId = getTeamIdFromToken();
|
|
||||||
if (is_null($teamId)) {
|
|
||||||
return invalidTokenResponse();
|
|
||||||
}
|
|
||||||
$env = EnvironmentVariable::where('uuid', $request->env_uuid)->first();
|
|
||||||
if (! $env) {
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Environment variable not found.',
|
|
||||||
], 404);
|
|
||||||
}
|
|
||||||
$found_app = $env->resource()->whereRelation('environment.project.team', 'id', $teamId)->first();
|
|
||||||
if (! $found_app) {
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Environment variable not found.',
|
|
||||||
], 404);
|
|
||||||
}
|
|
||||||
$env->delete();
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Environment variable deleted.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -157,7 +157,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
private ?string $coolify_variables = null;
|
private ?string $coolify_variables = null;
|
||||||
|
|
||||||
private bool $preserveRepository = true;
|
private bool $preserveRepository = false;
|
||||||
|
|
||||||
public $tries = 1;
|
public $tries = 1;
|
||||||
|
|
||||||
@@ -198,7 +198,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
$this->container_name = generateApplicationContainerName($this->application, $this->pull_request_id);
|
$this->container_name = generateApplicationContainerName($this->application, $this->pull_request_id);
|
||||||
if ($this->application->settings->custom_internal_name && ! $this->application->settings->is_consistent_container_name_enabled) {
|
if ($this->application->settings->custom_internal_name && ! $this->application->settings->is_consistent_container_name_enabled) {
|
||||||
$this->container_name = $this->application->settings->custom_internal_name;
|
if ($this->pull_request_id === 0) {
|
||||||
|
$this->container_name = $this->application->settings->custom_internal_name;
|
||||||
|
} else {
|
||||||
|
$this->container_name = "{$this->application->settings->custom_internal_name}-pr-{$this->pull_request_id}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ray('New container name: ', $this->container_name);
|
ray('New container name: ', $this->container_name);
|
||||||
|
|
||||||
@@ -276,6 +280,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$this->original_server = $this->server;
|
$this->original_server = $this->server;
|
||||||
} else {
|
} else {
|
||||||
$this->build_server = $buildServers->random();
|
$this->build_server = $buildServers->random();
|
||||||
|
$this->application_deployment_queue->build_server_id = $this->build_server->id;
|
||||||
$this->application_deployment_queue->addLogEntry("Found a suitable build server ({$this->build_server->name}).");
|
$this->application_deployment_queue->addLogEntry("Found a suitable build server ({$this->build_server->name}).");
|
||||||
$this->original_server = $this->server;
|
$this->original_server = $this->server;
|
||||||
$this->use_build_server = true;
|
$this->use_build_server = true;
|
||||||
@@ -480,6 +485,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start compose file
|
// Start compose file
|
||||||
|
$server_workdir = $this->application->workdir();
|
||||||
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
||||||
if ($this->docker_compose_custom_start_command) {
|
if ($this->docker_compose_custom_start_command) {
|
||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
@@ -488,7 +494,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
$server_workdir = $this->application->workdir();
|
|
||||||
$this->docker_compose_location = '/docker-compose.yaml';
|
$this->docker_compose_location = '/docker-compose.yaml';
|
||||||
|
|
||||||
$command = "{$this->coolify_variables} docker compose";
|
$command = "{$this->coolify_variables} docker compose";
|
||||||
@@ -508,15 +513,26 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$command = "{$this->coolify_variables} docker compose";
|
$command = "{$this->coolify_variables} docker compose";
|
||||||
if ($this->env_filename) {
|
if ($this->preserveRepository) {
|
||||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
if ($this->env_filename) {
|
||||||
}
|
$command .= " --env-file {$server_workdir}/{$this->env_filename}";
|
||||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
}
|
||||||
|
$command .= " --project-name {$this->application->uuid} --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
|
||||||
|
$this->write_deployment_configurations();
|
||||||
|
|
||||||
|
$this->execute_remote_command(
|
||||||
|
['command' => $command, 'hidden' => true],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if ($this->env_filename) {
|
||||||
|
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
||||||
|
}
|
||||||
|
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->write_deployment_configurations();
|
|
||||||
$this->execute_remote_command(
|
|
||||||
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,6 +635,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
$this->application->fileStorages()->each(function ($fileStorage) {
|
||||||
|
if (! $fileStorage->is_based_on_git && ! $fileStorage->is_directory) {
|
||||||
|
$fileStorage->saveStorageOnServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
if ($this->use_build_server) {
|
if ($this->use_build_server) {
|
||||||
$this->server = $this->build_server;
|
$this->server = $this->build_server;
|
||||||
}
|
}
|
||||||
@@ -1708,13 +1729,20 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) {
|
if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) {
|
||||||
$docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array;
|
$docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($persistent_storages) > 0) {
|
if (count($persistent_storages) > 0) {
|
||||||
$docker_compose['services'][$this->container_name]['volumes'] = $persistent_storages;
|
if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) {
|
||||||
|
$docker_compose['services'][$this->container_name]['volumes'] = [];
|
||||||
|
}
|
||||||
|
$docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_storages);
|
||||||
}
|
}
|
||||||
if (count($persistent_file_volumes) > 0) {
|
if (count($persistent_file_volumes) > 0) {
|
||||||
$docker_compose['services'][$this->container_name]['volumes'] = $persistent_file_volumes->map(function ($item) {
|
if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) {
|
||||||
|
$docker_compose['services'][$this->container_name]['volumes'] = [];
|
||||||
|
}
|
||||||
|
$docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_file_volumes->map(function ($item) {
|
||||||
return "$item->fs_path:$item->mount_path";
|
return "$item->fs_path:$item->mount_path";
|
||||||
})->toArray();
|
})->toArray());
|
||||||
}
|
}
|
||||||
if (count($volume_names) > 0) {
|
if (count($volume_names) > 0) {
|
||||||
$docker_compose['volumes'] = $volume_names;
|
$docker_compose['volumes'] = $volume_names;
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
public ?string $backup_output = null;
|
public ?string $backup_output = null;
|
||||||
|
|
||||||
|
public ?string $postgres_password = null;
|
||||||
|
|
||||||
public ?S3Storage $s3 = null;
|
public ?S3Storage $s3 = null;
|
||||||
|
|
||||||
public function __construct($backup)
|
public function __construct($backup)
|
||||||
@@ -134,6 +136,13 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
} else {
|
} else {
|
||||||
$databasesToBackup = $this->database->postgres_user;
|
$databasesToBackup = $this->database->postgres_user;
|
||||||
}
|
}
|
||||||
|
$this->postgres_password = $envs->filter(function ($env) {
|
||||||
|
return str($env)->startsWith('POSTGRES_PASSWORD=');
|
||||||
|
})->first();
|
||||||
|
if ($this->postgres_password) {
|
||||||
|
$this->postgres_password = str($this->postgres_password)->after('POSTGRES_PASSWORD=')->value();
|
||||||
|
}
|
||||||
|
|
||||||
} elseif (str($databaseType)->contains('mysql')) {
|
} elseif (str($databaseType)->contains('mysql')) {
|
||||||
$this->container_name = "{$this->database->name}-$serviceUuid";
|
$this->container_name = "{$this->database->name}-$serviceUuid";
|
||||||
$this->directory_name = $serviceName.'-'.$this->container_name;
|
$this->directory_name = $serviceName.'-'.$this->container_name;
|
||||||
@@ -336,7 +345,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$url = $this->database->internal_db_url;
|
$url = $this->database->internal_db_url;
|
||||||
if ($databaseWithCollections === 'all') {
|
if ($databaseWithCollections === 'all') {
|
||||||
$commands[] = 'mkdir -p '.$this->backup_dir;
|
$commands[] = 'mkdir -p '.$this->backup_dir;
|
||||||
if (str($this->database->image)->startsWith('mongo:4.0')) {
|
if (str($this->database->image)->startsWith('mongo:4')) {
|
||||||
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location";
|
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location";
|
||||||
} else {
|
} else {
|
||||||
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --gzip --archive > $this->backup_location";
|
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --gzip --archive > $this->backup_location";
|
||||||
@@ -351,13 +360,13 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
}
|
}
|
||||||
$commands[] = 'mkdir -p '.$this->backup_dir;
|
$commands[] = 'mkdir -p '.$this->backup_dir;
|
||||||
if ($collectionsToExclude->count() === 0) {
|
if ($collectionsToExclude->count() === 0) {
|
||||||
if (str($this->database->image)->startsWith('mongo:4.0')) {
|
if (str($this->database->image)->startsWith('mongo:4')) {
|
||||||
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location";
|
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --archive > $this->backup_location";
|
||||||
} else {
|
} else {
|
||||||
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --archive > $this->backup_location";
|
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --archive > $this->backup_location";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (str($this->database->image)->startsWith('mongo:4.0')) {
|
if (str($this->database->image)->startsWith('mongo:4')) {
|
||||||
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location";
|
$commands[] = "docker exec $this->container_name mongodump --uri=$url --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location";
|
||||||
} else {
|
} else {
|
||||||
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location";
|
$commands[] = "docker exec $this->container_name mongodump --authenticationDatabase=admin --uri=$url --db $databaseName --gzip --excludeCollection ".$collectionsToExclude->implode(' --excludeCollection ')." --archive > $this->backup_location";
|
||||||
@@ -381,7 +390,13 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$commands[] = 'mkdir -p '.$this->backup_dir;
|
$commands[] = 'mkdir -p '.$this->backup_dir;
|
||||||
$commands[] = "docker exec $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location";
|
$backupCommand = "docker exec";
|
||||||
|
if ($this->postgres_password) {
|
||||||
|
$backupCommand .= " -e PGPASSWORD=$this->postgres_password";
|
||||||
|
}
|
||||||
|
$backupCommand .= " $this->container_name pg_dump --format=custom --no-acl --no-owner --username {$this->database->postgres_user} $database > $this->backup_location";
|
||||||
|
|
||||||
|
$commands[] = $backupCommand;
|
||||||
$this->backup_output = instant_remote_process($commands, $this->server);
|
$this->backup_output = instant_remote_process($commands, $this->server);
|
||||||
$this->backup_output = trim($this->backup_output);
|
$this->backup_output = trim($this->backup_output);
|
||||||
if ($this->backup_output === '') {
|
if ($this->backup_output === '') {
|
||||||
|
|||||||
@@ -96,6 +96,12 @@ class Advanced extends Component
|
|||||||
} else {
|
} else {
|
||||||
$this->application->settings->custom_internal_name = null;
|
$this->application->settings->custom_internal_name = null;
|
||||||
}
|
}
|
||||||
|
if (is_null($this->application->settings->custom_internal_name)) {
|
||||||
|
$this->application->settings->save();
|
||||||
|
$this->dispatch('success', 'Custom name saved.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
$customInternalName = $this->application->settings->custom_internal_name;
|
$customInternalName = $this->application->settings->custom_internal_name;
|
||||||
$server = $this->application->destination->server;
|
$server = $this->application->destination->server;
|
||||||
$allApplications = $server->applications();
|
$allApplications = $server->applications();
|
||||||
|
|||||||
@@ -55,9 +55,14 @@ class DeploymentNavbar extends Component
|
|||||||
public function cancel()
|
public function cancel()
|
||||||
{
|
{
|
||||||
$kill_command = "docker rm -f {$this->application_deployment_queue->deployment_uuid}";
|
$kill_command = "docker rm -f {$this->application_deployment_queue->deployment_uuid}";
|
||||||
|
$build_server_id = $this->application_deployment_queue->build_server_id;
|
||||||
$server_id = $this->application_deployment_queue->server_id ?? $this->application->destination->server_id;
|
$server_id = $this->application_deployment_queue->server_id ?? $this->application->destination->server_id;
|
||||||
try {
|
try {
|
||||||
$server = Server::find($server_id);
|
if ($this->application->settings->is_build_server_enabled) {
|
||||||
|
$server = Server::find($build_server_id);
|
||||||
|
} else {
|
||||||
|
$server = Server::find($server_id);
|
||||||
|
}
|
||||||
if ($this->application_deployment_queue->logs) {
|
if ($this->application_deployment_queue->logs) {
|
||||||
$previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR);
|
$previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Livewire\Project\Application;
|
namespace App\Livewire\Project\Application;
|
||||||
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\LocalFileVolume;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
@@ -30,6 +29,8 @@ class General extends Component
|
|||||||
|
|
||||||
public ?string $ports_exposes = null;
|
public ?string $ports_exposes = null;
|
||||||
|
|
||||||
|
public bool $is_preserve_repository_enabled = false;
|
||||||
|
|
||||||
public bool $is_container_label_escape_enabled = true;
|
public bool $is_container_label_escape_enabled = true;
|
||||||
|
|
||||||
public $customLabels;
|
public $customLabels;
|
||||||
@@ -145,6 +146,7 @@ class General extends Component
|
|||||||
}
|
}
|
||||||
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
|
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
|
||||||
$this->ports_exposes = $this->application->ports_exposes;
|
$this->ports_exposes = $this->application->ports_exposes;
|
||||||
|
$this->is_preserve_repository_enabled = $this->application->settings->is_preserve_repository_enabled;
|
||||||
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
|
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
|
||||||
$this->customLabels = $this->application->parseContainerLabels();
|
$this->customLabels = $this->application->parseContainerLabels();
|
||||||
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
|
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
|
||||||
@@ -168,9 +170,21 @@ class General extends Component
|
|||||||
$this->application->settings->save();
|
$this->application->settings->save();
|
||||||
$this->dispatch('success', 'Settings saved.');
|
$this->dispatch('success', 'Settings saved.');
|
||||||
$this->application->refresh();
|
$this->application->refresh();
|
||||||
|
|
||||||
|
// If port_exposes changed, reset default labels
|
||||||
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
|
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
|
||||||
$this->resetDefaultLabels(false);
|
$this->resetDefaultLabels(false);
|
||||||
}
|
}
|
||||||
|
if ($this->is_preserve_repository_enabled !== $this->application->settings->is_preserve_repository_enabled) {
|
||||||
|
if ($this->application->settings->is_preserve_repository_enabled === false) {
|
||||||
|
$this->application->fileStorages->each(function ($storage) {
|
||||||
|
$storage->is_based_on_git = $this->application->settings->is_preserve_repository_enabled;
|
||||||
|
$storage->save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadComposeFile($isInit = false)
|
public function loadComposeFile($isInit = false)
|
||||||
@@ -179,6 +193,11 @@ class General extends Component
|
|||||||
if ($isInit && $this->application->docker_compose_raw) {
|
if ($isInit && $this->application->docker_compose_raw) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must reload the application to get the latest database changes
|
||||||
|
// Why? Not sure, but it works.
|
||||||
|
$this->application->refresh();
|
||||||
|
|
||||||
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit);
|
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit);
|
||||||
if (is_null($this->parsedServices)) {
|
if (is_null($this->parsedServices)) {
|
||||||
$this->dispatch('error', 'Failed to parse your docker-compose file. Please check the syntax and try again.');
|
$this->dispatch('error', 'Failed to parse your docker-compose file. Please check the syntax and try again.');
|
||||||
@@ -186,32 +205,6 @@ class General extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$compose = $this->application->parseCompose();
|
$compose = $this->application->parseCompose();
|
||||||
$services = data_get($compose, 'services');
|
|
||||||
if ($services) {
|
|
||||||
$volumes = collect($services)->map(function ($service) {
|
|
||||||
return data_get($service, 'volumes');
|
|
||||||
})->flatten()->filter(function ($volume) {
|
|
||||||
return str($volume)->startsWith('/data/coolify');
|
|
||||||
})->unique()->values();
|
|
||||||
foreach ($volumes as $volume) {
|
|
||||||
$source = str($volume)->before(':');
|
|
||||||
$target = str($volume)->after(':')->beforeLast(':');
|
|
||||||
|
|
||||||
LocalFileVolume::updateOrCreate(
|
|
||||||
[
|
|
||||||
'mount_path' => $target,
|
|
||||||
'resource_id' => $this->application->id,
|
|
||||||
'resource_type' => get_class($this->application),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'fs_path' => $source,
|
|
||||||
'mount_path' => $target,
|
|
||||||
'resource_id' => $this->application->id,
|
|
||||||
'resource_type' => get_class($this->application),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->dispatch('success', 'Docker compose file loaded.');
|
$this->dispatch('success', 'Docker compose file loaded.');
|
||||||
$this->dispatch('compose_loaded');
|
$this->dispatch('compose_loaded');
|
||||||
$this->dispatch('refreshStorages');
|
$this->dispatch('refreshStorages');
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace App\Livewire\Project\New;
|
|||||||
use App\Models\EnvironmentVariable;
|
use App\Models\EnvironmentVariable;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use App\Models\StandaloneDocker;
|
||||||
|
use App\Models\SwarmDocker;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
@@ -58,12 +60,26 @@ class DockerCompose extends Component
|
|||||||
|
|
||||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||||
|
|
||||||
|
$destination_uuid = $this->query['destination'];
|
||||||
|
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
||||||
|
if (! $destination) {
|
||||||
|
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
||||||
|
}
|
||||||
|
if (! $destination) {
|
||||||
|
throw new \Exception('Destination not found. What?!');
|
||||||
|
}
|
||||||
|
$destination_class = $destination->getMorphClass();
|
||||||
|
|
||||||
$service = Service::create([
|
$service = Service::create([
|
||||||
'name' => 'service'.Str::random(10),
|
'name' => 'service'.Str::random(10),
|
||||||
'docker_compose_raw' => $this->dockerComposeRaw,
|
'docker_compose_raw' => $this->dockerComposeRaw,
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $environment->id,
|
||||||
'server_id' => (int) $server_id,
|
'server_id' => (int) $server_id,
|
||||||
|
'destination_id' => $destination->id,
|
||||||
|
'destination_type' => $destination_class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$variables = parseEnvFormatToArray($this->envFile);
|
$variables = parseEnvFormatToArray($this->envFile);
|
||||||
foreach ($variables as $key => $variable) {
|
foreach ($variables as $key => $variable) {
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ class Select extends Component
|
|||||||
|
|
||||||
public ?string $selectedEnvironment = null;
|
public ?string $selectedEnvironment = null;
|
||||||
|
|
||||||
|
public string $postgresql_type = 'postgres:16-alpine';
|
||||||
|
|
||||||
public ?string $existingPostgresqlUrl = null;
|
public ?string $existingPostgresqlUrl = null;
|
||||||
|
|
||||||
public ?string $search = null;
|
public ?string $search = null;
|
||||||
@@ -202,6 +204,8 @@ class Select extends Component
|
|||||||
$docker = $this->standaloneDockers->first() ?? $this->swarmDockers->first();
|
$docker = $this->standaloneDockers->first() ?? $this->swarmDockers->first();
|
||||||
if ($docker) {
|
if ($docker) {
|
||||||
$this->setDestination($docker->uuid);
|
$this->setDestination($docker->uuid);
|
||||||
|
|
||||||
|
return $this->whatToDoNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->current_step = 'destinations';
|
$this->current_step = 'destinations';
|
||||||
@@ -211,15 +215,38 @@ class Select extends Component
|
|||||||
{
|
{
|
||||||
$this->destination_uuid = $destination_uuid;
|
$this->destination_uuid = $destination_uuid;
|
||||||
|
|
||||||
|
return $this->whatToDoNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPostgresqlType(string $type)
|
||||||
|
{
|
||||||
|
$this->postgresql_type = $type;
|
||||||
|
|
||||||
return redirect()->route('project.resource.create', [
|
return redirect()->route('project.resource.create', [
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
'project_uuid' => $this->parameters['project_uuid'],
|
||||||
'environment_name' => $this->parameters['environment_name'],
|
'environment_name' => $this->parameters['environment_name'],
|
||||||
'type' => $this->type,
|
'type' => $this->type,
|
||||||
'destination' => $this->destination_uuid,
|
'destination' => $this->destination_uuid,
|
||||||
'server_id' => $this->server_id,
|
'server_id' => $this->server_id,
|
||||||
|
'database_image' => $this->postgresql_type,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function whatToDoNext()
|
||||||
|
{
|
||||||
|
if ($this->type === 'postgresql') {
|
||||||
|
$this->current_step = 'select-postgresql-type';
|
||||||
|
} else {
|
||||||
|
return redirect()->route('project.resource.create', [
|
||||||
|
'project_uuid' => $this->parameters['project_uuid'],
|
||||||
|
'environment_name' => $this->parameters['environment_name'],
|
||||||
|
'type' => $this->type,
|
||||||
|
'destination' => $this->destination_uuid,
|
||||||
|
'server_id' => $this->server_id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function loadServers()
|
public function loadServers()
|
||||||
{
|
{
|
||||||
$this->servers = Server::isUsable()->get();
|
$this->servers = Server::isUsable()->get();
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ class Create extends Component
|
|||||||
$type = str(request()->query('type'));
|
$type = str(request()->query('type'));
|
||||||
$destination_uuid = request()->query('destination');
|
$destination_uuid = request()->query('destination');
|
||||||
$server_id = request()->query('server_id');
|
$server_id = request()->query('server_id');
|
||||||
|
$database_image = request()->query('database_image');
|
||||||
|
ray($database_image);
|
||||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||||
if (! $project) {
|
if (! $project) {
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
@@ -33,7 +34,11 @@ class Create extends Component
|
|||||||
|
|
||||||
if (in_array($type, DATABASE_TYPES)) {
|
if (in_array($type, DATABASE_TYPES)) {
|
||||||
if ($type->value() === 'postgresql') {
|
if ($type->value() === 'postgresql') {
|
||||||
$database = create_standalone_postgresql($environment->id, $destination_uuid);
|
$database = create_standalone_postgresql(
|
||||||
|
environmentId: $environment->id,
|
||||||
|
destinationUuid: $destination_uuid,
|
||||||
|
databaseImage: $database_image
|
||||||
|
);
|
||||||
} elseif ($type->value() === 'redis') {
|
} elseif ($type->value() === 'redis') {
|
||||||
$database = create_standalone_redis($environment->id, $destination_uuid);
|
$database = create_standalone_redis($environment->id, $destination_uuid);
|
||||||
} elseif ($type->value() === 'mongodb') {
|
} elseif ($type->value() === 'mongodb') {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class Configuration extends Component
|
|||||||
return [
|
return [
|
||||||
"echo-private:user.{$userId},ServiceStatusChanged" => 'check_status',
|
"echo-private:user.{$userId},ServiceStatusChanged" => 'check_status',
|
||||||
'check_status',
|
'check_status',
|
||||||
|
'refresh' => '$refresh',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ class EditCompose extends Component
|
|||||||
|
|
||||||
public $serviceId;
|
public $serviceId;
|
||||||
|
|
||||||
protected $listeners = ['refreshEnvs', 'envsUpdated'];
|
protected $listeners = [
|
||||||
|
'refreshEnvs',
|
||||||
|
'envsUpdated',
|
||||||
|
'refresh' => 'envsUpdated',
|
||||||
|
];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'service.docker_compose_raw' => 'required',
|
'service.docker_compose_raw' => 'required',
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class FileStorage extends Component
|
|||||||
'fileStorage.fs_path' => 'required',
|
'fileStorage.fs_path' => 'required',
|
||||||
'fileStorage.mount_path' => 'required',
|
'fileStorage.mount_path' => 'required',
|
||||||
'fileStorage.content' => 'nullable',
|
'fileStorage.content' => 'nullable',
|
||||||
|
'fileStorage.is_based_on_git' => 'required|boolean',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
@@ -45,6 +46,7 @@ class FileStorage extends Component
|
|||||||
$this->workdir = null;
|
$this->workdir = null;
|
||||||
$this->fs_path = $this->fileStorage->fs_path;
|
$this->fs_path = $this->fileStorage->fs_path;
|
||||||
}
|
}
|
||||||
|
$this->fileStorage->loadStorageOnServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function convertToDirectory()
|
public function convertToDirectory()
|
||||||
@@ -68,6 +70,9 @@ class FileStorage extends Component
|
|||||||
$this->fileStorage->deleteStorageOnServer();
|
$this->fileStorage->deleteStorageOnServer();
|
||||||
$this->fileStorage->is_directory = false;
|
$this->fileStorage->is_directory = false;
|
||||||
$this->fileStorage->content = null;
|
$this->fileStorage->content = null;
|
||||||
|
if (data_get($this->resource, 'settings.is_preserve_repository_enabled')) {
|
||||||
|
$this->fileStorage->is_based_on_git = true;
|
||||||
|
}
|
||||||
$this->fileStorage->save();
|
$this->fileStorage->save();
|
||||||
$this->fileStorage->saveStorageOnServer();
|
$this->fileStorage->saveStorageOnServer();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class StackForm extends Component
|
|||||||
public function saveCompose($raw)
|
public function saveCompose($raw)
|
||||||
{
|
{
|
||||||
$this->service->docker_compose_raw = $raw;
|
$this->service->docker_compose_raw = $raw;
|
||||||
$this->submit();
|
$this->submit(notify: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
@@ -62,7 +62,7 @@ class StackForm extends Component
|
|||||||
$this->dispatch('success', 'Service settings saved.');
|
$this->dispatch('success', 'Service settings saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit()
|
public function submit($notify = true)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
@@ -76,7 +76,7 @@ class StackForm extends Component
|
|||||||
$this->service->refresh();
|
$this->service->refresh();
|
||||||
$this->service->saveComposeConfigs();
|
$this->service->saveComposeConfigs();
|
||||||
$this->dispatch('refreshEnvs');
|
$this->dispatch('refreshEnvs');
|
||||||
$this->dispatch('success', 'Service saved.');
|
$notify && $this->dispatch('success', 'Service saved.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ class All extends Component
|
|||||||
public string $view = 'normal';
|
public string $view = 'normal';
|
||||||
|
|
||||||
protected $listeners = [
|
protected $listeners = [
|
||||||
'refreshEnvs',
|
|
||||||
'saveKey' => 'submit',
|
'saveKey' => 'submit',
|
||||||
|
'environmentVariableDeleted' => 'refreshEnvs',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
@@ -40,220 +40,240 @@ class All extends Component
|
|||||||
$this->showPreview = true;
|
$this->showPreview = true;
|
||||||
}
|
}
|
||||||
$this->modalId = new Cuid2;
|
$this->modalId = new Cuid2;
|
||||||
$this->sortMe();
|
$this->sortEnvironmentVariables();
|
||||||
$this->getDevView();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function sortMe()
|
|
||||||
{
|
|
||||||
if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') {
|
|
||||||
if ($this->resource->settings->is_env_sorting_enabled) {
|
|
||||||
$this->resource->environment_variables = $this->resource->environment_variables->sortBy('key');
|
|
||||||
$this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('key');
|
|
||||||
} else {
|
|
||||||
$this->resource->environment_variables = $this->resource->environment_variables->sortBy('id');
|
|
||||||
$this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->getDevView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') {
|
$this->resource->settings->save();
|
||||||
$this->resource->settings->save();
|
$this->sortEnvironmentVariables();
|
||||||
$this->dispatch('success', 'Environment variable settings updated.');
|
$this->dispatch('success', 'Environment variable settings updated.');
|
||||||
$this->sortMe();
|
}
|
||||||
|
|
||||||
|
public function sortEnvironmentVariables()
|
||||||
|
{
|
||||||
|
if ($this->resource->type() === 'application') {
|
||||||
|
$this->resource->load(['environment_variables', 'environment_variables_preview']);
|
||||||
|
} else {
|
||||||
|
$this->resource->load(['environment_variables']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sortBy = data_get($this->resource, 'settings.is_env_sorting_enabled') ? 'key' : 'order';
|
||||||
|
|
||||||
|
$sortFunction = function ($variables) use ($sortBy) {
|
||||||
|
if (!$variables) {
|
||||||
|
return $variables;
|
||||||
|
}
|
||||||
|
if ($sortBy === 'key') {
|
||||||
|
return $variables->sortBy(function ($item) {
|
||||||
|
return strtolower($item->key);
|
||||||
|
}, SORT_NATURAL | SORT_FLAG_CASE)->values();
|
||||||
|
} else {
|
||||||
|
return $variables->sortBy('order')->values();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->resource->environment_variables = $sortFunction($this->resource->environment_variables);
|
||||||
|
$this->resource->environment_variables_preview = $sortFunction($this->resource->environment_variables_preview);
|
||||||
|
|
||||||
|
$this->getDevView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDevView()
|
public function getDevView()
|
||||||
{
|
{
|
||||||
$this->variables = $this->resource->environment_variables->map(function ($item) {
|
$this->variables = $this->formatEnvironmentVariables($this->resource->environment_variables);
|
||||||
|
if ($this->showPreview) {
|
||||||
|
$this->variablesPreview = $this->formatEnvironmentVariables($this->resource->environment_variables_preview);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formatEnvironmentVariables($variables)
|
||||||
|
{
|
||||||
|
return $variables->map(function ($item) {
|
||||||
if ($item->is_shown_once) {
|
if ($item->is_shown_once) {
|
||||||
return "$item->key=(locked secret)";
|
return "$item->key=(Locked Secret, delete and add again to change)";
|
||||||
}
|
}
|
||||||
if ($item->is_multiline) {
|
if ($item->is_multiline) {
|
||||||
return "$item->key=(multiline, edit in normal view)";
|
return "$item->key=(Multiline environment variable, edit in normal view)";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "$item->key=$item->value";
|
return "$item->key=$item->value";
|
||||||
})->join('
|
})->join("\n");
|
||||||
');
|
|
||||||
if ($this->showPreview) {
|
|
||||||
$this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) {
|
|
||||||
if ($item->is_shown_once) {
|
|
||||||
return "$item->key=(locked secret)";
|
|
||||||
}
|
|
||||||
if ($item->is_multiline) {
|
|
||||||
return "$item->key=(multiline, edit in normal view)";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "$item->key=$item->value";
|
|
||||||
})->join('
|
|
||||||
');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function switch()
|
public function switch()
|
||||||
{
|
{
|
||||||
if ($this->view === 'normal') {
|
$this->view = $this->view === 'normal' ? 'dev' : 'normal';
|
||||||
$this->view = 'dev';
|
$this->sortEnvironmentVariables();
|
||||||
} else {
|
|
||||||
$this->view = 'normal';
|
|
||||||
}
|
|
||||||
$this->sortMe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveVariables($isPreview)
|
public function submit($data = null)
|
||||||
{
|
{
|
||||||
if ($isPreview) {
|
try {
|
||||||
$variables = parseEnvFormatToArray($this->variablesPreview);
|
if ($data === null) {
|
||||||
$this->resource->environment_variables_preview()->whereNotIn('key', array_keys($variables))->delete();
|
$this->handleBulkSubmit();
|
||||||
} else {
|
|
||||||
$variables = parseEnvFormatToArray($this->variables);
|
|
||||||
$this->resource->environment_variables()->whereNotIn('key', array_keys($variables))->delete();
|
|
||||||
}
|
|
||||||
foreach ($variables as $key => $variable) {
|
|
||||||
if ($isPreview) {
|
|
||||||
$found = $this->resource->environment_variables_preview()->where('key', $key)->first();
|
|
||||||
} else {
|
} else {
|
||||||
$found = $this->resource->environment_variables()->where('key', $key)->first();
|
$this->handleSingleSubmit($data);
|
||||||
}
|
}
|
||||||
if ($found) {
|
|
||||||
if ($found->is_shown_once || $found->is_multiline) {
|
$this->updateOrder();
|
||||||
continue;
|
$this->sortEnvironmentVariables();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateOrder()
|
||||||
|
{
|
||||||
|
$variables = parseEnvFormatToArray($this->variables);
|
||||||
|
$order = 1;
|
||||||
|
foreach ($variables as $key => $value) {
|
||||||
|
$env = $this->resource->environment_variables()->where('key', $key)->first();
|
||||||
|
if ($env) {
|
||||||
|
$env->order = $order;
|
||||||
|
$env->save();
|
||||||
|
}
|
||||||
|
$order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->showPreview) {
|
||||||
|
$previewVariables = parseEnvFormatToArray($this->variablesPreview);
|
||||||
|
$order = 1;
|
||||||
|
foreach ($previewVariables as $key => $value) {
|
||||||
|
$env = $this->resource->environment_variables_preview()->where('key', $key)->first();
|
||||||
|
if ($env) {
|
||||||
|
$env->order = $order;
|
||||||
|
$env->save();
|
||||||
}
|
}
|
||||||
$found->value = $variable;
|
$order++;
|
||||||
// if (str($found->value)->startsWith('{{') && str($found->value)->endsWith('}}')) {
|
}
|
||||||
// $type = str($found->value)->after('{{')->before('.')->value;
|
}
|
||||||
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
}
|
||||||
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
|
||||||
|
|
||||||
// return;
|
private function handleBulkSubmit()
|
||||||
// }
|
{
|
||||||
// }
|
$variables = parseEnvFormatToArray($this->variables);
|
||||||
$found->save();
|
$this->deleteRemovedVariables(false, $variables);
|
||||||
|
$this->updateOrCreateVariables(false, $variables);
|
||||||
|
|
||||||
continue;
|
if ($this->showPreview) {
|
||||||
|
$previewVariables = parseEnvFormatToArray($this->variablesPreview);
|
||||||
|
$this->deleteRemovedVariables(true, $previewVariables);
|
||||||
|
$this->updateOrCreateVariables(true, $previewVariables);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dispatch('success', 'Environment variables updated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleSingleSubmit($data)
|
||||||
|
{
|
||||||
|
$found = $this->resource->environment_variables()->where('key', $data['key'])->first();
|
||||||
|
if ($found) {
|
||||||
|
$this->dispatch('error', 'Environment variable already exists.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxOrder = $this->resource->environment_variables()->max('order') ?? 0;
|
||||||
|
$environment = $this->createEnvironmentVariable($data);
|
||||||
|
$environment->order = $maxOrder + 1;
|
||||||
|
$environment->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createEnvironmentVariable($data)
|
||||||
|
{
|
||||||
|
$environment = new EnvironmentVariable;
|
||||||
|
$environment->key = $data['key'];
|
||||||
|
$environment->value = $data['value'];
|
||||||
|
$environment->is_build_time = $data['is_build_time'] ?? false;
|
||||||
|
$environment->is_multiline = $data['is_multiline'] ?? false;
|
||||||
|
$environment->is_literal = $data['is_literal'] ?? false;
|
||||||
|
$environment->is_preview = $data['is_preview'] ?? false;
|
||||||
|
|
||||||
|
$resourceType = $this->resource->type();
|
||||||
|
$resourceIdField = $this->getResourceIdField($resourceType);
|
||||||
|
|
||||||
|
if ($resourceIdField) {
|
||||||
|
$environment->$resourceIdField = $this->resource->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getResourceIdField($resourceType)
|
||||||
|
{
|
||||||
|
$resourceTypes = [
|
||||||
|
'application' => 'application_id',
|
||||||
|
'standalone-postgresql' => 'standalone_postgresql_id',
|
||||||
|
'standalone-redis' => 'standalone_redis_id',
|
||||||
|
'standalone-mongodb' => 'standalone_mongodb_id',
|
||||||
|
'standalone-mysql' => 'standalone_mysql_id',
|
||||||
|
'standalone-mariadb' => 'standalone_mariadb_id',
|
||||||
|
'standalone-keydb' => 'standalone_keydb_id',
|
||||||
|
'standalone-dragonfly' => 'standalone_dragonfly_id',
|
||||||
|
'standalone-clickhouse' => 'standalone_clickhouse_id',
|
||||||
|
'service' => 'service_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $resourceTypes[$resourceType] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deleteRemovedVariables($isPreview, $variables)
|
||||||
|
{
|
||||||
|
$method = $isPreview ? 'environment_variables_preview' : 'environment_variables';
|
||||||
|
$this->resource->$method()->whereNotIn('key', array_keys($variables))->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateOrCreateVariables($isPreview, $variables)
|
||||||
|
{
|
||||||
|
foreach ($variables as $key => $value) {
|
||||||
|
$method = $isPreview ? 'environment_variables_preview' : 'environment_variables';
|
||||||
|
$found = $this->resource->$method()->where('key', $key)->first();
|
||||||
|
|
||||||
|
if ($found) {
|
||||||
|
if (! $found->is_shown_once && ! $found->is_multiline) {
|
||||||
|
$found->value = $value;
|
||||||
|
$found->save();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$environment = new EnvironmentVariable;
|
$environment = new EnvironmentVariable;
|
||||||
$environment->key = $key;
|
$environment->key = $key;
|
||||||
$environment->value = $variable;
|
$environment->value = $value;
|
||||||
// if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) {
|
|
||||||
// $type = str($environment->value)->after('{{')->before('.')->value;
|
|
||||||
// if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
|
||||||
// $this->dispatch('error', 'Invalid shared variable type.', 'Valid types are: team, project, environment.');
|
|
||||||
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
$environment->is_build_time = false;
|
$environment->is_build_time = false;
|
||||||
$environment->is_multiline = false;
|
$environment->is_multiline = false;
|
||||||
$environment->is_preview = $isPreview ? true : false;
|
$environment->is_preview = $isPreview;
|
||||||
switch ($this->resource->type()) {
|
|
||||||
case 'application':
|
$this->setEnvironmentResourceId($environment);
|
||||||
$environment->application_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-postgresql':
|
|
||||||
$environment->standalone_postgresql_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-redis':
|
|
||||||
$environment->standalone_redis_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-mongodb':
|
|
||||||
$environment->standalone_mongodb_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-mysql':
|
|
||||||
$environment->standalone_mysql_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-mariadb':
|
|
||||||
$environment->standalone_mariadb_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-keydb':
|
|
||||||
$environment->standalone_keydb_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-dragonfly':
|
|
||||||
$environment->standalone_dragonfly_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-clickhouse':
|
|
||||||
$environment->standalone_clickhouse_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'service':
|
|
||||||
$environment->service_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$environment->save();
|
$environment->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($isPreview) {
|
}
|
||||||
$this->dispatch('success', 'Preview environment variables updated.');
|
|
||||||
} else {
|
private function setEnvironmentResourceId($environment)
|
||||||
$this->dispatch('success', 'Environment variables updated.');
|
{
|
||||||
|
$resourceTypes = [
|
||||||
|
'application' => 'application_id',
|
||||||
|
'standalone-postgresql' => 'standalone_postgresql_id',
|
||||||
|
'standalone-redis' => 'standalone_redis_id',
|
||||||
|
'standalone-mongodb' => 'standalone_mongodb_id',
|
||||||
|
'standalone-mysql' => 'standalone_mysql_id',
|
||||||
|
'standalone-mariadb' => 'standalone_mariadb_id',
|
||||||
|
'standalone-keydb' => 'standalone_keydb_id',
|
||||||
|
'standalone-dragonfly' => 'standalone_dragonfly_id',
|
||||||
|
'standalone-clickhouse' => 'standalone_clickhouse_id',
|
||||||
|
'service' => 'service_id',
|
||||||
|
];
|
||||||
|
|
||||||
|
$resourceType = $this->resource->type();
|
||||||
|
if (isset($resourceTypes[$resourceType])) {
|
||||||
|
$environment->{$resourceTypes[$resourceType]} = $this->resource->id;
|
||||||
}
|
}
|
||||||
$this->refreshEnvs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function refreshEnvs()
|
public function refreshEnvs()
|
||||||
{
|
{
|
||||||
$this->resource->refresh();
|
$this->resource->refresh();
|
||||||
|
$this->sortEnvironmentVariables();
|
||||||
$this->getDevView();
|
$this->getDevView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit($data)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$found = $this->resource->environment_variables()->where('key', $data['key'])->first();
|
|
||||||
if ($found) {
|
|
||||||
$this->dispatch('error', 'Environment variable already exists.');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$environment = new EnvironmentVariable;
|
|
||||||
$environment->key = $data['key'];
|
|
||||||
$environment->value = $data['value'];
|
|
||||||
$environment->is_build_time = $data['is_build_time'];
|
|
||||||
$environment->is_multiline = $data['is_multiline'];
|
|
||||||
$environment->is_literal = $data['is_literal'];
|
|
||||||
$environment->is_preview = $data['is_preview'];
|
|
||||||
|
|
||||||
switch ($this->resource->type()) {
|
|
||||||
case 'application':
|
|
||||||
$environment->application_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-postgresql':
|
|
||||||
$environment->standalone_postgresql_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-redis':
|
|
||||||
$environment->standalone_redis_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-mongodb':
|
|
||||||
$environment->standalone_mongodb_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-mysql':
|
|
||||||
$environment->standalone_mysql_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-mariadb':
|
|
||||||
$environment->standalone_mariadb_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-keydb':
|
|
||||||
$environment->standalone_keydb_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-dragonfly':
|
|
||||||
$environment->standalone_dragonfly_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-clickhouse':
|
|
||||||
$environment->standalone_clickhouse_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'service':
|
|
||||||
$environment->service_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$environment->save();
|
|
||||||
$this->refreshEnvs();
|
|
||||||
$this->dispatch('success', 'Environment variable added.');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ class Show extends Component
|
|||||||
public string $type;
|
public string $type;
|
||||||
|
|
||||||
protected $listeners = [
|
protected $listeners = [
|
||||||
'refresh' => 'refresh',
|
'refreshEnvs' => 'refresh',
|
||||||
|
'refresh',
|
||||||
'compose_loaded' => '$refresh',
|
'compose_loaded' => '$refresh',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -129,9 +130,10 @@ class Show extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->env->delete();
|
$this->env->delete();
|
||||||
$this->dispatch('refreshEnvs');
|
$this->dispatch('environmentVariableDeleted');
|
||||||
|
$this->dispatch('success', 'Environment variable deleted successfully.');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ class Show extends Component
|
|||||||
|
|
||||||
public array $parameters;
|
public array $parameters;
|
||||||
|
|
||||||
protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey'];
|
protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey'];
|
||||||
|
|
||||||
public function saveKey($data)
|
public function saveKey($data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -479,12 +479,12 @@ class Application extends BaseModel
|
|||||||
$main_server_status = $this->destination->server->isFunctional();
|
$main_server_status = $this->destination->server->isFunctional();
|
||||||
foreach ($additional_servers_status as $status) {
|
foreach ($additional_servers_status as $status) {
|
||||||
$server_status = str($status)->before(':')->value();
|
$server_status = str($status)->before(':')->value();
|
||||||
if ($main_server_status !== $server_status) {
|
if ($server_status !== 'running') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return $main_server_status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use App\Models\EnvironmentVariable as ModelsEnvironmentVariable;
|
|||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
#[OA\Schema(
|
#[OA\Schema(
|
||||||
@@ -97,8 +96,22 @@ class EnvironmentVariable extends Model
|
|||||||
$resource = Application::find($this->application_id);
|
$resource = Application::find($this->application_id);
|
||||||
} elseif ($this->service_id) {
|
} elseif ($this->service_id) {
|
||||||
$resource = Service::find($this->service_id);
|
$resource = Service::find($this->service_id);
|
||||||
} elseif ($this->database_id) {
|
} elseif ($this->standalone_postgresql_id) {
|
||||||
$resource = getResourceByUuid($this->parameters['database_uuid'], data_get(auth()->user()->currentTeam(), 'id'));
|
$resource = StandalonePostgresql::find($this->standalone_postgresql_id);
|
||||||
|
} elseif ($this->standalone_redis_id) {
|
||||||
|
$resource = StandaloneRedis::find($this->standalone_redis_id);
|
||||||
|
} elseif ($this->standalone_mongodb_id) {
|
||||||
|
$resource = StandaloneMongodb::find($this->standalone_mongodb_id);
|
||||||
|
} elseif ($this->standalone_mysql_id) {
|
||||||
|
$resource = StandaloneMysql::find($this->standalone_mysql_id);
|
||||||
|
} elseif ($this->standalone_mariadb_id) {
|
||||||
|
$resource = StandaloneMariadb::find($this->standalone_mariadb_id);
|
||||||
|
} elseif ($this->standalone_keydb_id) {
|
||||||
|
$resource = StandaloneKeydb::find($this->standalone_keydb_id);
|
||||||
|
} elseif ($this->standalone_dragonfly_id) {
|
||||||
|
$resource = StandaloneDragonfly::find($this->standalone_dragonfly_id);
|
||||||
|
} elseif ($this->standalone_clickhouse_id) {
|
||||||
|
$resource = StandaloneClickhouse::find($this->standalone_clickhouse_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $resource;
|
return $resource;
|
||||||
@@ -122,63 +135,6 @@ class EnvironmentVariable extends Model
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isFoundInCompose(): Attribute
|
|
||||||
{
|
|
||||||
return Attribute::make(
|
|
||||||
get: function () {
|
|
||||||
if (! $this->application_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$found_in_compose = false;
|
|
||||||
$found_in_args = false;
|
|
||||||
$resource = $this->resource();
|
|
||||||
$compose = data_get($resource, 'docker_compose_raw');
|
|
||||||
if (! $compose) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$yaml = Yaml::parse($compose);
|
|
||||||
$services = collect(data_get($yaml, 'services'));
|
|
||||||
if ($services->isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
foreach ($services as $service) {
|
|
||||||
$environments = collect(data_get($service, 'environment'));
|
|
||||||
$args = collect(data_get($service, 'build.args'));
|
|
||||||
if ($environments->isEmpty() && $args->isEmpty()) {
|
|
||||||
$found_in_compose = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$found_in_compose = $environments->contains(function ($item) {
|
|
||||||
if (str($item)->contains('=')) {
|
|
||||||
$item = str($item)->before('=');
|
|
||||||
}
|
|
||||||
|
|
||||||
return strpos($item, $this->key) !== false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($found_in_compose) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$found_in_args = $args->contains(function ($item) {
|
|
||||||
if (str($item)->contains('=')) {
|
|
||||||
$item = str($item)->before('=');
|
|
||||||
}
|
|
||||||
|
|
||||||
return strpos($item, $this->key) !== false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($found_in_args) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $found_in_compose || $found_in_args;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isShared(): Attribute
|
protected function isShared(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
@@ -201,8 +157,10 @@ class EnvironmentVariable extends Model
|
|||||||
$environment_variable = trim($environment_variable);
|
$environment_variable = trim($environment_variable);
|
||||||
$sharedEnvsFound = str($environment_variable)->matchAll('/{{(.*?)}}/');
|
$sharedEnvsFound = str($environment_variable)->matchAll('/{{(.*?)}}/');
|
||||||
if ($sharedEnvsFound->isEmpty()) {
|
if ($sharedEnvsFound->isEmpty()) {
|
||||||
|
|
||||||
return $environment_variable;
|
return $environment_variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($sharedEnvsFound as $sharedEnv) {
|
foreach ($sharedEnvsFound as $sharedEnv) {
|
||||||
$type = str($sharedEnv)->match('/(.*?)\./');
|
$type = str($sharedEnv)->match('/(.*?)\./');
|
||||||
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
if (! collect(SHARED_VARIABLE_TYPES)->contains($type)) {
|
||||||
|
|||||||
@@ -24,6 +24,32 @@ class LocalFileVolume extends BaseModel
|
|||||||
return $this->morphTo('resource');
|
return $this->morphTo('resource');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function loadStorageOnServer()
|
||||||
|
{
|
||||||
|
$this->load(['service']);
|
||||||
|
$isService = data_get($this->resource, 'service');
|
||||||
|
if ($isService) {
|
||||||
|
$workdir = $this->resource->service->workdir();
|
||||||
|
$server = $this->resource->service->server;
|
||||||
|
} else {
|
||||||
|
$workdir = $this->resource->workdir();
|
||||||
|
$server = $this->resource->destination->server;
|
||||||
|
}
|
||||||
|
$commands = collect([]);
|
||||||
|
$path = data_get_str($this, 'fs_path');
|
||||||
|
if ($path->startsWith('.')) {
|
||||||
|
$path = $path->after('.');
|
||||||
|
$path = $workdir.$path;
|
||||||
|
}
|
||||||
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
|
if ($isFile === 'OK') {
|
||||||
|
$content = instant_remote_process(["cat $path"], $server, false);
|
||||||
|
$this->content = $content;
|
||||||
|
$this->is_directory = false;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function deleteStorageOnServer()
|
public function deleteStorageOnServer()
|
||||||
{
|
{
|
||||||
$isService = data_get($this->resource, 'service');
|
$isService = data_get($this->resource, 'service');
|
||||||
@@ -35,17 +61,20 @@ class LocalFileVolume extends BaseModel
|
|||||||
$server = $this->resource->destination->server;
|
$server = $this->resource->destination->server;
|
||||||
}
|
}
|
||||||
$commands = collect([]);
|
$commands = collect([]);
|
||||||
$fs_path = data_get($this, 'fs_path');
|
$path = data_get_str($this, 'fs_path');
|
||||||
$isFile = instant_remote_process(["test -f $fs_path && echo OK || echo NOK"], $server);
|
if ($path->startsWith('.')) {
|
||||||
$isDir = instant_remote_process(["test -d $fs_path && echo OK || echo NOK"], $server);
|
$path = $path->after('.');
|
||||||
if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') {
|
$path = $workdir.$path;
|
||||||
ray($isFile, $isDir);
|
}
|
||||||
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
|
if ($path && $path != '/' && $path != '.' && $path != '..') {
|
||||||
if ($isFile === 'OK') {
|
if ($isFile === 'OK') {
|
||||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
|
||||||
|
|
||||||
} elseif ($isDir === 'OK') {
|
} elseif ($isDir === 'OK') {
|
||||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
|
||||||
$commands->push("rmdir $fs_path > /dev/null 2>&1 || true");
|
$commands->push("rmdir $path > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($commands->count() > 0) {
|
if ($commands->count() > 0) {
|
||||||
@@ -55,6 +84,7 @@ class LocalFileVolume extends BaseModel
|
|||||||
|
|
||||||
public function saveStorageOnServer()
|
public function saveStorageOnServer()
|
||||||
{
|
{
|
||||||
|
$this->load(['service']);
|
||||||
$isService = data_get($this->resource, 'service');
|
$isService = data_get($this->resource, 'service');
|
||||||
if ($isService) {
|
if ($isService) {
|
||||||
$workdir = $this->resource->service->workdir();
|
$workdir = $this->resource->service->workdir();
|
||||||
@@ -74,30 +104,36 @@ class LocalFileVolume extends BaseModel
|
|||||||
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fileVolume = $this;
|
$path = data_get_str($this, 'fs_path');
|
||||||
$path = str(data_get($fileVolume, 'fs_path'));
|
$content = data_get($this, 'content');
|
||||||
$content = data_get($fileVolume, 'content');
|
|
||||||
if ($path->startsWith('.')) {
|
if ($path->startsWith('.')) {
|
||||||
$path = $path->after('.');
|
$path = $path->after('.');
|
||||||
$path = $workdir.$path;
|
$path = $workdir.$path;
|
||||||
}
|
}
|
||||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
if ($isFile == 'OK' && $this->is_directory) {
|
||||||
$content = instant_remote_process(["cat $path"], $server, false);
|
$content = instant_remote_process(["cat $path"], $server, false);
|
||||||
$fileVolume->is_directory = false;
|
$this->is_directory = false;
|
||||||
$fileVolume->content = $content;
|
$this->content = $content;
|
||||||
$fileVolume->save();
|
$this->save();
|
||||||
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||||
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
||||||
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
} elseif ($isDir == 'OK' && ! $this->is_directory) {
|
||||||
$fileVolume->is_directory = true;
|
if ($path == '/' || $path == '.' || $path == '..' || $path == '' || str($path)->isEmpty() || is_null($path)) {
|
||||||
$fileVolume->save();
|
$this->is_directory = true;
|
||||||
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
$this->save();
|
||||||
|
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
||||||
|
}
|
||||||
|
instant_remote_process([
|
||||||
|
"rm -fr $path",
|
||||||
|
"touch $path",
|
||||||
|
], $server, false);
|
||||||
|
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||||
}
|
}
|
||||||
if ($isDir == 'NOK' && ! $fileVolume->is_directory) {
|
if ($isDir == 'NOK' && ! $this->is_directory) {
|
||||||
$chmod = data_get($fileVolume, 'chmod');
|
$chmod = data_get($this, 'chmod');
|
||||||
$chown = data_get($fileVolume, 'chown');
|
$chown = data_get($this, 'chown');
|
||||||
if ($content) {
|
if ($content) {
|
||||||
$content = base64_encode($content);
|
$content = base64_encode($content);
|
||||||
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
|
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
|
||||||
@@ -111,7 +147,7 @@ class LocalFileVolume extends BaseModel
|
|||||||
if ($chmod) {
|
if ($chmod) {
|
||||||
$commands->push("chmod $chmod $path");
|
$commands->push("chmod $chmod $path");
|
||||||
}
|
}
|
||||||
} elseif ($isDir == 'NOK' && $fileVolume->is_directory) {
|
} elseif ($isDir == 'NOK' && $this->is_directory) {
|
||||||
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use Symfony\Component\Yaml\Yaml;
|
|||||||
'description' => ['type' => 'string', 'description' => 'The description of the service.'],
|
'description' => ['type' => 'string', 'description' => 'The description of the service.'],
|
||||||
'docker_compose_raw' => ['type' => 'string', 'description' => 'The raw docker-compose.yml file of the service.'],
|
'docker_compose_raw' => ['type' => 'string', 'description' => 'The raw docker-compose.yml file of the service.'],
|
||||||
'docker_compose' => ['type' => 'string', 'description' => 'The docker-compose.yml file that is parsed and modified by Coolify.'],
|
'docker_compose' => ['type' => 'string', 'description' => 'The docker-compose.yml file that is parsed and modified by Coolify.'],
|
||||||
|
'destination_type' => ['type' => 'integer', 'description' => 'The unique identifier of the destination where the service is running.'],
|
||||||
'destination_id' => ['type' => 'integer', 'description' => 'The unique identifier of the destination where the service is running.'],
|
'destination_id' => ['type' => 'integer', 'description' => 'The unique identifier of the destination where the service is running.'],
|
||||||
'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'],
|
'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'],
|
||||||
'is_container_label_escape_enabled' => ['type' => 'boolean', 'description' => 'The flag to enable the container label escape.'],
|
'is_container_label_escape_enabled' => ['type' => 'boolean', 'description' => 'The flag to enable the container label escape.'],
|
||||||
@@ -205,6 +206,41 @@ class Service extends BaseModel
|
|||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
$image = str($application->image)->before(':')->value();
|
$image = str($application->image)->before(':')->value();
|
||||||
switch ($image) {
|
switch ($image) {
|
||||||
|
case str($image)?->contains('rabbitmq'):
|
||||||
|
$data = collect([]);
|
||||||
|
$host_port = $this->environment_variables()->where('key', 'PORT')->first();
|
||||||
|
$username = $this->environment_variables()->where('key', 'SERVICE_USER_RABBITMQ')->first();
|
||||||
|
$password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_RABBITMQ')->first();
|
||||||
|
if ($host_port) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Host Port Binding' => [
|
||||||
|
'key' => data_get($host_port, 'key'),
|
||||||
|
'value' => data_get($host_port, 'value'),
|
||||||
|
'rules' => 'required',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if ($username) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Username' => [
|
||||||
|
'key' => data_get($username, 'key'),
|
||||||
|
'value' => data_get($username, 'value'),
|
||||||
|
'rules' => 'required',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if ($password) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Password' => [
|
||||||
|
'key' => data_get($password, 'key'),
|
||||||
|
'value' => data_get($password, 'value'),
|
||||||
|
'rules' => 'required',
|
||||||
|
'isPassword' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$fields->put('RabbitMQ', $data->toArray());
|
||||||
|
break;
|
||||||
case str($image)?->contains('tolgee'):
|
case str($image)?->contains('tolgee'):
|
||||||
$data = collect([]);
|
$data = collect([]);
|
||||||
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_TOLGEE')->first();
|
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_TOLGEE')->first();
|
||||||
@@ -504,6 +540,9 @@ class Service extends BaseModel
|
|||||||
default:
|
default:
|
||||||
$data = collect([]);
|
$data = collect([]);
|
||||||
$admin_user = $this->environment_variables()->where('key', 'SERVICE_USER_ADMIN')->first();
|
$admin_user = $this->environment_variables()->where('key', 'SERVICE_USER_ADMIN')->first();
|
||||||
|
// Chaskiq
|
||||||
|
$admin_email = $this->environment_variables()->where('key', 'ADMIN_EMAIL')->first();
|
||||||
|
|
||||||
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ADMIN')->first();
|
$admin_password = $this->environment_variables()->where('key', 'SERVICE_PASSWORD_ADMIN')->first();
|
||||||
if ($admin_user) {
|
if ($admin_user) {
|
||||||
$data = $data->merge([
|
$data = $data->merge([
|
||||||
@@ -525,6 +564,15 @@ class Service extends BaseModel
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
if ($admin_email) {
|
||||||
|
$data = $data->merge([
|
||||||
|
'Email' => [
|
||||||
|
'key' => 'ADMIN_EMAIL',
|
||||||
|
'value' => data_get($admin_email, 'value'),
|
||||||
|
'rules' => 'required|email',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
$fields->put('Admin', $data->toArray());
|
$fields->put('Admin', $data->toArray());
|
||||||
break;
|
break;
|
||||||
case str($image)?->contains('vaultwarden'):
|
case str($image)?->contains('vaultwarden'):
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function generate_database_name(string $type): string
|
|||||||
return $type.'-database-'.$cuid;
|
return $type.'-database-'.$cuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function create_standalone_postgresql($environmentId, $destinationUuid, ?array $otherData = null): StandalonePostgresql
|
function create_standalone_postgresql($environmentId, $destinationUuid, ?array $otherData = null, string $databaseImage = 'postgres:16-alpine'): StandalonePostgresql
|
||||||
{
|
{
|
||||||
$destination = StandaloneDocker::where('uuid', $destinationUuid)->first();
|
$destination = StandaloneDocker::where('uuid', $destinationUuid)->first();
|
||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
@@ -27,6 +27,7 @@ function create_standalone_postgresql($environmentId, $destinationUuid, ?array $
|
|||||||
}
|
}
|
||||||
$database = new StandalonePostgresql;
|
$database = new StandalonePostgresql;
|
||||||
$database->name = generate_database_name('postgresql');
|
$database->name = generate_database_name('postgresql');
|
||||||
|
$database->image = $databaseImage;
|
||||||
$database->postgres_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->postgres_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->environment_id = $environmentId;
|
$database->environment_id = $environmentId;
|
||||||
$database->destination_id = $destination->id;
|
$database->destination_id = $destination->id;
|
||||||
|
|||||||
@@ -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) {
|
||||||
@@ -677,18 +677,19 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
|||||||
'--sysctl',
|
'--sysctl',
|
||||||
'--ulimit',
|
'--ulimit',
|
||||||
'--device',
|
'--device',
|
||||||
|
'--shm-size',
|
||||||
]);
|
]);
|
||||||
$mapping = collect([
|
$mapping = collect([
|
||||||
'--cap-add' => 'cap_add',
|
'--cap-add' => 'cap_add',
|
||||||
'--cap-drop' => 'cap_drop',
|
'--cap-drop' => 'cap_drop',
|
||||||
'--security-opt' => 'security_opt',
|
'--security-opt' => 'security_opt',
|
||||||
'--sysctl' => 'sysctls',
|
'--sysctl' => 'sysctls',
|
||||||
'--ulimit' => 'ulimits',
|
|
||||||
'--device' => 'devices',
|
'--device' => 'devices',
|
||||||
'--init' => 'init',
|
'--init' => 'init',
|
||||||
'--ulimit' => 'ulimits',
|
'--ulimit' => 'ulimits',
|
||||||
'--privileged' => 'privileged',
|
'--privileged' => 'privileged',
|
||||||
'--ip' => 'ip',
|
'--ip' => 'ip',
|
||||||
|
'--shm-size' => 'shm_size',
|
||||||
]);
|
]);
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
$option = $match[1];
|
$option = $match[1];
|
||||||
@@ -704,7 +705,8 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
|||||||
$options = collect($options);
|
$options = collect($options);
|
||||||
// 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) {
|
||||||
if (! data_get($mapping, $option)) {
|
// ray($option,$value);
|
||||||
|
if (!data_get($mapping, $option)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($option === '--ulimit') {
|
if ($option === '--ulimit') {
|
||||||
@@ -728,10 +730,14 @@ function convert_docker_run_to_compose(?string $custom_docker_run_options = null
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
$compose_options->put($mapping[$option], $ulimits);
|
$compose_options->put($mapping[$option], $ulimits);
|
||||||
|
} elseif ($option === '--shm-size') {
|
||||||
|
if (!is_null($value) && is_array($value) && count($value) > 0) {
|
||||||
|
$compose_options->put($mapping[$option], $value[0]);
|
||||||
|
}
|
||||||
} 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);
|
||||||
}
|
}
|
||||||
@@ -749,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 {
|
||||||
|
|||||||
@@ -794,7 +794,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
$topLevelVolumes = collect($tempTopLevelVolumes);
|
$topLevelVolumes = collect($tempTopLevelVolumes);
|
||||||
}
|
}
|
||||||
$services = collect($services)->map(function ($service, $serviceName) use ($topLevelVolumes, $topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $allServices) {
|
$services = collect($services)->map(function ($service, $serviceName) use ($topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS, $resource, $allServices, $topLevelVolumes) {
|
||||||
// Workarounds for beta users.
|
// Workarounds for beta users.
|
||||||
if ($serviceName === 'registry') {
|
if ($serviceName === 'registry') {
|
||||||
$tempServiceName = 'docker-registry';
|
$tempServiceName = 'docker-registry';
|
||||||
@@ -963,102 +963,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
|
|
||||||
// Collect/create/update volumes
|
// Collect/create/update volumes
|
||||||
if ($serviceVolumes->count() > 0) {
|
if ($serviceVolumes->count() > 0) {
|
||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($savedService, $topLevelVolumes) {
|
['serviceVolumes' => $serviceVolumes, 'topLevelVolumes' => $topLevelVolumes] = parseServiceVolumes($serviceVolumes, $savedService, $topLevelVolumes);
|
||||||
$type = null;
|
|
||||||
$source = null;
|
|
||||||
$target = null;
|
|
||||||
$content = null;
|
|
||||||
$isDirectory = false;
|
|
||||||
if (is_string($volume)) {
|
|
||||||
$source = str($volume)->before(':');
|
|
||||||
$target = str($volume)->after(':')->beforeLast(':');
|
|
||||||
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
|
||||||
$type = str('bind');
|
|
||||||
// By default, we cannot determine if the bind is a directory or not, so we set it to directory
|
|
||||||
$isDirectory = true;
|
|
||||||
} else {
|
|
||||||
$type = str('volume');
|
|
||||||
}
|
|
||||||
} elseif (is_array($volume)) {
|
|
||||||
$type = data_get_str($volume, 'type');
|
|
||||||
$source = data_get_str($volume, 'source');
|
|
||||||
$target = data_get_str($volume, 'target');
|
|
||||||
$content = data_get($volume, 'content');
|
|
||||||
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
|
||||||
$foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
|
|
||||||
if ($foundConfig) {
|
|
||||||
$contentNotNull = data_get($foundConfig, 'content');
|
|
||||||
if ($contentNotNull) {
|
|
||||||
$content = $contentNotNull;
|
|
||||||
}
|
|
||||||
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
|
||||||
}
|
|
||||||
if (is_null($isDirectory) && is_null($content)) {
|
|
||||||
// if isDirectory is not set & content is also not set, we assume it is a directory
|
|
||||||
ray('setting isDirectory to true');
|
|
||||||
$isDirectory = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($type?->value() === 'bind') {
|
|
||||||
if ($source->value() === '/var/run/docker.sock') {
|
|
||||||
return $volume;
|
|
||||||
}
|
|
||||||
if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
|
|
||||||
return $volume;
|
|
||||||
}
|
|
||||||
LocalFileVolume::updateOrCreate(
|
|
||||||
[
|
|
||||||
'mount_path' => $target,
|
|
||||||
'resource_id' => $savedService->id,
|
|
||||||
'resource_type' => get_class($savedService),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'fs_path' => $source,
|
|
||||||
'mount_path' => $target,
|
|
||||||
'content' => $content,
|
|
||||||
'is_directory' => $isDirectory,
|
|
||||||
'resource_id' => $savedService->id,
|
|
||||||
'resource_type' => get_class($savedService),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} elseif ($type->value() === 'volume') {
|
|
||||||
if ($topLevelVolumes->has($source->value())) {
|
|
||||||
$v = $topLevelVolumes->get($source->value());
|
|
||||||
if (data_get($v, 'driver_opts.type') === 'cifs') {
|
|
||||||
return $volume;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$slugWithoutUuid = Str::slug($source, '-');
|
|
||||||
$name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
|
|
||||||
if (is_string($volume)) {
|
|
||||||
$source = str($volume)->before(':');
|
|
||||||
$target = str($volume)->after(':')->beforeLast(':');
|
|
||||||
$source = $name;
|
|
||||||
$volume = "$source:$target";
|
|
||||||
} elseif (is_array($volume)) {
|
|
||||||
data_set($volume, 'source', $name);
|
|
||||||
}
|
|
||||||
$topLevelVolumes->put($name, [
|
|
||||||
'name' => $name,
|
|
||||||
]);
|
|
||||||
LocalPersistentVolume::updateOrCreate(
|
|
||||||
[
|
|
||||||
'mount_path' => $target,
|
|
||||||
'resource_id' => $savedService->id,
|
|
||||||
'resource_type' => get_class($savedService),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => $name,
|
|
||||||
'mount_path' => $target,
|
|
||||||
'resource_id' => $savedService->id,
|
|
||||||
'resource_type' => get_class($savedService),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
dispatch(new ServerFilesFromServerJob($savedService));
|
|
||||||
|
|
||||||
return $volume;
|
|
||||||
});
|
|
||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1645,131 +1550,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
} elseif ($resource->compose_parsing_version === '2') {
|
} elseif ($resource->compose_parsing_version === '2') {
|
||||||
if (count($serviceVolumes) > 0) {
|
if (count($serviceVolumes) > 0) {
|
||||||
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
['serviceVolumes' => $serviceVolumes, 'topLevelVolumes' => $topLevelVolumes] = parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull_request_id);
|
||||||
if (is_string($volume)) {
|
|
||||||
$volume = str($volume);
|
|
||||||
if ($volume->contains(':') && ! $volume->startsWith('/')) {
|
|
||||||
$name = $volume->before(':');
|
|
||||||
$mount = $volume->after(':');
|
|
||||||
if ($name->startsWith('.') || $name->startsWith('~')) {
|
|
||||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
|
||||||
if ($name->startsWith('.')) {
|
|
||||||
$name = $name->replaceFirst('.', $dir);
|
|
||||||
}
|
|
||||||
if ($name->startsWith('~')) {
|
|
||||||
$name = $name->replaceFirst('~', $dir);
|
|
||||||
}
|
|
||||||
if ($pull_request_id !== 0) {
|
|
||||||
$name = $name."-pr-$pull_request_id";
|
|
||||||
}
|
|
||||||
$volume = str("$name:$mount");
|
|
||||||
} else {
|
|
||||||
if ($pull_request_id !== 0) {
|
|
||||||
$uuid = $resource->uuid;
|
|
||||||
$name = $uuid."-$name-pr-$pull_request_id";
|
|
||||||
$volume = str("$name:$mount");
|
|
||||||
if ($topLevelVolumes->has($name)) {
|
|
||||||
$v = $topLevelVolumes->get($name);
|
|
||||||
if (data_get($v, 'driver_opts.type') === 'cifs') {
|
|
||||||
// Do nothing
|
|
||||||
} else {
|
|
||||||
if (is_null(data_get($v, 'name'))) {
|
|
||||||
data_set($v, 'name', $name);
|
|
||||||
data_set($topLevelVolumes, $name, $v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$topLevelVolumes->put($name, [
|
|
||||||
'name' => $name,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$uuid = $resource->uuid;
|
|
||||||
$name = str($uuid."-$name");
|
|
||||||
$volume = str("$name:$mount");
|
|
||||||
if ($topLevelVolumes->has($name->value())) {
|
|
||||||
$v = $topLevelVolumes->get($name->value());
|
|
||||||
if (data_get($v, 'driver_opts.type') === 'cifs') {
|
|
||||||
// Do nothing
|
|
||||||
} else {
|
|
||||||
if (is_null(data_get($v, 'name'))) {
|
|
||||||
data_set($topLevelVolumes, $name->value(), $v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$topLevelVolumes->put($name->value(), [
|
|
||||||
'name' => $name->value(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($volume->startsWith('/')) {
|
|
||||||
$name = $volume->before(':');
|
|
||||||
$mount = $volume->after(':');
|
|
||||||
if ($pull_request_id !== 0) {
|
|
||||||
$name = $name."-pr-$pull_request_id";
|
|
||||||
}
|
|
||||||
$volume = str("$name:$mount");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif (is_array($volume)) {
|
|
||||||
$source = data_get($volume, 'source');
|
|
||||||
$target = data_get($volume, 'target');
|
|
||||||
$read_only = data_get($volume, 'read_only');
|
|
||||||
if ($source && $target) {
|
|
||||||
$uuid = $resource->uuid;
|
|
||||||
if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) {
|
|
||||||
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
|
||||||
if (str($source, '.')) {
|
|
||||||
$source = str($source)->replaceFirst('.', $dir);
|
|
||||||
}
|
|
||||||
if (str($source, '~')) {
|
|
||||||
$source = str($source)->replaceFirst('~', $dir);
|
|
||||||
}
|
|
||||||
if ($read_only) {
|
|
||||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
|
||||||
} else {
|
|
||||||
data_set($volume, 'source', $source.':'.$target);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($pull_request_id === 0) {
|
|
||||||
$source = $uuid."-$source";
|
|
||||||
} else {
|
|
||||||
$source = $uuid."-$source-pr-$pull_request_id";
|
|
||||||
}
|
|
||||||
if ($read_only) {
|
|
||||||
data_set($volume, 'source', $source.':'.$target.':ro');
|
|
||||||
} else {
|
|
||||||
data_set($volume, 'source', $source.':'.$target);
|
|
||||||
}
|
|
||||||
if (! str($source)->startsWith('/')) {
|
|
||||||
if ($topLevelVolumes->has($source)) {
|
|
||||||
$v = $topLevelVolumes->get($source);
|
|
||||||
if (data_get($v, 'driver_opts.type') === 'cifs') {
|
|
||||||
// Do nothing
|
|
||||||
} else {
|
|
||||||
if (is_null(data_get($v, 'name'))) {
|
|
||||||
data_set($v, 'name', $source);
|
|
||||||
data_set($topLevelVolumes, $source, $v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$topLevelVolumes->put($source, [
|
|
||||||
'name' => $source,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_array($volume)) {
|
|
||||||
return data_get($volume, 'source');
|
|
||||||
}
|
|
||||||
dispatch(new ServerFilesFromServerJob($resource));
|
|
||||||
|
|
||||||
return $volume->value();
|
|
||||||
});
|
|
||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2662,3 +2443,127 @@ function customApiValidator(Collection|array $item, array $rules)
|
|||||||
'required' => 'This field is required.',
|
'required' => 'This field is required.',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull_request_id = 0)
|
||||||
|
{
|
||||||
|
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($resource, $topLevelVolumes, $pull_request_id) {
|
||||||
|
$type = null;
|
||||||
|
$source = null;
|
||||||
|
$target = null;
|
||||||
|
$content = null;
|
||||||
|
$isDirectory = false;
|
||||||
|
if (is_string($volume)) {
|
||||||
|
$source = str($volume)->before(':');
|
||||||
|
$target = str($volume)->after(':')->beforeLast(':');
|
||||||
|
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
||||||
|
$type = str('bind');
|
||||||
|
// By default, we cannot determine if the bind is a directory or not, so we set it to directory
|
||||||
|
$isDirectory = true;
|
||||||
|
} else {
|
||||||
|
$type = str('volume');
|
||||||
|
}
|
||||||
|
} elseif (is_array($volume)) {
|
||||||
|
$type = data_get_str($volume, 'type');
|
||||||
|
$source = data_get_str($volume, 'source');
|
||||||
|
$target = data_get_str($volume, 'target');
|
||||||
|
$content = data_get($volume, 'content');
|
||||||
|
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
||||||
|
$foundConfig = $resource->fileStorages()->whereMountPath($target)->first();
|
||||||
|
if ($foundConfig) {
|
||||||
|
$contentNotNull = data_get($foundConfig, 'content');
|
||||||
|
if ($contentNotNull) {
|
||||||
|
$content = $contentNotNull;
|
||||||
|
}
|
||||||
|
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
||||||
|
}
|
||||||
|
if ((is_null($isDirectory) || ! $isDirectory) && is_null($content)) {
|
||||||
|
// if isDirectory is not set (or false) & content is also not set, we assume it is a directory
|
||||||
|
ray('setting isDirectory to true');
|
||||||
|
$isDirectory = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($type?->value() === 'bind') {
|
||||||
|
if ($source->value() === '/var/run/docker.sock') {
|
||||||
|
return $volume;
|
||||||
|
}
|
||||||
|
if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
|
||||||
|
return $volume;
|
||||||
|
}
|
||||||
|
if (get_class($resource) === "App\Models\Application") {
|
||||||
|
$dir = base_configuration_dir().'/applications/'.$resource->uuid;
|
||||||
|
} else {
|
||||||
|
$dir = base_configuration_dir().'/services/'.$resource->service->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($source->startsWith('.')) {
|
||||||
|
$source = $source->replaceFirst('.', $dir);
|
||||||
|
}
|
||||||
|
if ($source->startsWith('~')) {
|
||||||
|
$source = $source->replaceFirst('~', $dir);
|
||||||
|
}
|
||||||
|
if ($pull_request_id !== 0) {
|
||||||
|
$source = $source."-pr-$pull_request_id";
|
||||||
|
}
|
||||||
|
LocalFileVolume::updateOrCreate(
|
||||||
|
[
|
||||||
|
'mount_path' => $target,
|
||||||
|
'resource_id' => $resource->id,
|
||||||
|
'resource_type' => get_class($resource),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'fs_path' => $source,
|
||||||
|
'mount_path' => $target,
|
||||||
|
'content' => $content,
|
||||||
|
'is_directory' => $isDirectory,
|
||||||
|
'resource_id' => $resource->id,
|
||||||
|
'resource_type' => get_class($resource),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} elseif ($type->value() === 'volume') {
|
||||||
|
if ($topLevelVolumes->has($source->value())) {
|
||||||
|
$v = $topLevelVolumes->get($source->value());
|
||||||
|
if (data_get($v, 'driver_opts.type') === 'cifs') {
|
||||||
|
return $volume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$slugWithoutUuid = Str::slug($source, '-');
|
||||||
|
if (get_class($resource) === "App\Models\Application") {
|
||||||
|
$name = "{$resource->uuid}_{$slugWithoutUuid}";
|
||||||
|
} else {
|
||||||
|
$name = "{$resource->service->uuid}_{$slugWithoutUuid}";
|
||||||
|
}
|
||||||
|
if (is_string($volume)) {
|
||||||
|
$source = str($volume)->before(':');
|
||||||
|
$target = str($volume)->after(':')->beforeLast(':');
|
||||||
|
$source = $name;
|
||||||
|
$volume = "$source:$target";
|
||||||
|
} elseif (is_array($volume)) {
|
||||||
|
data_set($volume, 'source', $name);
|
||||||
|
}
|
||||||
|
$topLevelVolumes->put($name, [
|
||||||
|
'name' => $name,
|
||||||
|
]);
|
||||||
|
LocalPersistentVolume::updateOrCreate(
|
||||||
|
[
|
||||||
|
'mount_path' => $target,
|
||||||
|
'resource_id' => $resource->id,
|
||||||
|
'resource_type' => get_class($resource),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => $name,
|
||||||
|
'mount_path' => $target,
|
||||||
|
'resource_id' => $resource->id,
|
||||||
|
'resource_type' => get_class($resource),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dispatch(new ServerFilesFromServerJob($resource));
|
||||||
|
|
||||||
|
return $volume;
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
'serviceVolumes' => $serviceVolumes,
|
||||||
|
'topLevelVolumes' => $topLevelVolumes,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.323',
|
'release' => '4.0.0-beta.324',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.323';
|
return '4.0.0-beta.324';
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('local_file_volumes', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_based_on_git')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('local_file_volumes', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_based_on_git');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('environment_variables', function (Blueprint $table) {
|
||||||
|
$table->integer('order')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('environment_variables', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('order');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('application_deployment_queues', function (Blueprint $table) {
|
||||||
|
$table->integer('build_server_id')->nullable()->after('server_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('application_deployment_queues', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('build_server_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -12,11 +12,13 @@ class StandaloneDockerSeeder extends Seeder
|
|||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
StandaloneDocker::create([
|
if (StandaloneDocker::find(0) == null) {
|
||||||
'id' => 0,
|
StandaloneDocker::create([
|
||||||
'name' => 'Standalone Docker 1',
|
'id' => 0,
|
||||||
'network' => 'coolify',
|
'name' => 'Standalone Docker 1',
|
||||||
'server_id' => 0,
|
'network' => 'coolify',
|
||||||
]);
|
'server_id' => 0,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,13 +247,13 @@ paths:
|
|||||||
security:
|
security:
|
||||||
-
|
-
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
/applications/private-gh-app:
|
/applications/private-github-app:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Applications
|
- Applications
|
||||||
summary: 'Create (Private - GH App)'
|
summary: 'Create (Private - GH App)'
|
||||||
description: 'Create new application based on a private repository through a Github App.'
|
description: 'Create new application based on a private repository through a Github App.'
|
||||||
operationId: 4d46c84bda4f1a411f6dda15fce4061f
|
operationId: 8b7af9c9a509385963bf3e72eeeea786
|
||||||
requestBody:
|
requestBody:
|
||||||
description: 'Application object that needs to be created.'
|
description: 'Application object that needs to be created.'
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
21
public/svgs/budibase.svg
Normal file
21
public/svgs/budibase.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<svg width="1200" height="265" viewBox="0 0 1200 265" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_1_17)">
|
||||||
|
<path d="M456.1 140.1C451.8 135.6 446.3 132.2 439.5 130C459.2 121.8 463.3 97.1 452.7 80.7C443.4 67.5 427.4 64.2 410.3 64C395 64 370.2 64 355.1 64V204C361.1 204 375.9 204 381.7 204C397.9 203.6 428.5 206 442.5 199.5C466.7 191.5 473.4 158 456.1 140.1ZM408.1 86.8C414.8 86.8 420.2 88 424.4 90.4C434.4 96.1 432.6 117.1 419.9 119.5C412.7 122.1 389.7 120.7 381.7 121V86.8H408.1ZM431.7 176.7C427.3 179.7 421.4 181.2 413.9 181.2H381.7V142.4H413.9C421.4 142.4 427.3 143.9 431.7 146.8C440.5 151.7 440.5 171.6 431.7 176.7Z" fill="black"/>
|
||||||
|
<path d="M527.6 206.3C502.3 207 481.5 188.6 482.4 162.5V101.1H507.6V161C507.3 175 514.6 183.8 527.6 184C540.6 183.8 547.8 175 547.6 161V101.2H572.6V162.6C573.5 188.5 552.7 207 527.6 206.3Z" fill="black"/>
|
||||||
|
<path d="M666.6 69.3V116.3C656.2 97.1 628.2 93.7 610.7 105.7C595.5 115.9 588.1 133.5 588.2 152.5C588.1 171.3 595.6 189.2 610.7 199.3C628.1 211.4 656.1 207.9 666.6 188.8V204H691.6V63L666.6 69.3ZM659.7 175.8C650.5 186.7 630.5 186.7 621.3 175.8C611.4 165.9 611.4 139.3 621.3 129.4C630.5 118.5 650.5 118.5 659.7 129.4C669.5 139.2 669.5 165.9 659.7 175.8Z" fill="black"/>
|
||||||
|
<path d="M730.9 88.8C709 89.3 709.1 58 730.9 58.4C752.4 58.3 752.5 89 730.9 88.8ZM743.1 101.2V204H718.1V101.2H743.1Z" fill="black"/>
|
||||||
|
<path d="M867 124.9C854.6 96.2 811.3 88 794.6 116.4V63L769.6 69.3V204H794.6V188.9C805 208 833.3 211.5 850.6 199.4C873.6 184.5 878.7 148.4 867 124.9ZM840 175.8C830.8 186.7 810.8 186.7 801.6 175.8C791.7 165.9 791.7 139.3 801.6 129.4C810.8 118.5 830.8 118.5 840 129.4C849.9 139.2 849.9 165.9 840 175.8Z" fill="black"/>
|
||||||
|
<path d="M973.4 116.4C954.1 90.2 902.3 92.8 890.1 125.1L911.2 134C917.7 118.9 943.3 115.9 952.1 130C955.5 134.8 954.8 145.2 954.8 151.4C935.4 133 885 141.8 886 174.3C884.7 208.5 938.3 216.1 956.4 194V203.9H979.8V139.3C979.8 130 977.6 122.4 973.4 116.4ZM949.2 184.3C941.7 189.3 925.4 189.2 917.9 184.4C909.8 180.1 909.8 167.9 917.9 163.6C928.4 157.6 954.7 157.6 955.2 174C955.2 178.4 953.2 181.8 949.2 184.3Z" fill="black"/>
|
||||||
|
<path d="M1043.7 206.3C1022.2 206.7 1001.5 194.6 996.9 172.3L1017.1 165.7C1019.8 179.2 1030.7 185.9 1043.7 185.9C1052.2 185.7 1062.1 184.1 1062.9 175.7C1062.2 166.9 1053.4 166.5 1044.3 163.5C1032.2 161.1 1014.7 155.9 1008.5 149C996.7 138.1 998 116.4 1011.7 107.1C1034.3 90.3 1082.5 98.3 1085.7 131.9L1064.9 137.3C1062.8 124.5 1053.5 119.2 1041.5 119.1C1033.7 119.2 1024.9 121.1 1024.3 128.9C1025.3 138.1 1036.6 138.2 1044.3 140.9C1056 143.2 1072.3 147.9 1078.8 155.1C1088.6 164 1089.5 180.8 1081.5 191.1C1072.9 202.3 1058.6 206.3 1043.7 206.3Z" fill="black"/>
|
||||||
|
<path d="M1193.8 124.2C1182.3 99.2 1148.3 91.9 1125.7 105.5C1109.3 115.3 1101.5 132.8 1101.6 152.6C1101.5 172.3 1109.6 190.1 1126.2 199.7C1150.3 213.7 1187 205.7 1198 177.9L1176.5 170.2C1170 184.2 1151.7 188.7 1138.8 181.4C1131.3 176.8 1127.8 167.6 1127 158.2H1199.7C1200.7 146.3 1198.7 133.5 1193.8 124.2ZM1151.6 119C1164.3 119 1172.5 128.2 1174.5 140.8H1127.8C1130 127.9 1138 118.9 1151.6 119Z" fill="black"/>
|
||||||
|
<path d="M158.2 8.6V116.6C158.2 121.3 162 125.2 166.8 125.2H213.8C218 125.2 222 123.2 224.6 119.8L262.9 68.9C265.7 65.2 265.7 60.1 262.9 56.4L224.6 5.4C222 2 218 0 213.8 0H166.8C162 0 158.2 3.8 158.2 8.6Z" fill="#FF4E4E"/>
|
||||||
|
<path d="M158.2 148.4V256.4C158.2 261.1 162 265 166.8 265H213.8C218 265 222 263 224.6 259.6L262.9 208.7C265.7 205 265.7 199.9 262.9 196.2L224.6 145.3C222.1 141.9 218.1 139.9 213.8 139.9H166.8C162 139.8 158.2 143.7 158.2 148.4Z" fill="#6E56FF"/>
|
||||||
|
<path d="M0 8.6V116.6C0 121.3 3.8 125.2 8.6 125.2H109.6C113.8 125.2 117.8 123.2 120.4 119.8L155.9 72.5C160.3 66.6 160.3 58.5 155.9 52.6L120.3 5.4C117.8 2 113.8 0 109.5 0H8.6C3.8 0 0 3.8 0 8.6Z" fill="#F97777"/>
|
||||||
|
<path d="M0 148.4V256.4C0 261.1 3.8 265 8.6 265H109.6C113.8 265 117.8 263 120.4 259.6L155.9 212.3C160.3 206.4 160.3 198.3 155.9 192.4L120.4 145.1C117.9 141.7 113.9 139.7 109.6 139.7H8.6C3.8 139.8 0 143.7 0 148.4Z" fill="#9F8FFF"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_1_17">
|
||||||
|
<rect width="1200" height="265" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
BIN
public/svgs/chaskiq.png
Normal file
BIN
public/svgs/chaskiq.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
1
public/svgs/rabbitmq.svg
Normal file
1
public/svgs/rabbitmq.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg height="271" preserveAspectRatio="xMidYMid" viewBox="0 0 256 271" width="256" xmlns="http://www.w3.org/2000/svg"><path d="m245.44 108.307692h-85.090462c-4.268307 0-7.734153-3.465846-7.734153-7.734154v-88.6793842c0-6.56738457-5.32677-11.8941538-11.889231-11.8941538h-30.375385c-6.567384 0-11.8892305 5.32676923-11.8892305 11.8941538v88.1427692c0 4.573539-3.6972308 8.290462-8.2707693 8.310154l-27.8843077.132923c-4.612923.024615-8.3593846-3.716923-8.3495384-8.324923l.1723077-88.2412308c.0147692-6.57723082-5.312-11.9138462-11.8892308-11.9138462h-30.3507692c-6.56738465 0-11.8892308 5.32676923-11.8892308 11.8941538v248.3150772c0 5.833846 4.72615385 10.56 10.5550769 10.56h234.8849231c5.833846 0 10.56-4.726154 10.56-10.56v-141.341539c0-5.833846-4.726154-10.56-10.56-10.56zm-39.901538 93.233231c0 7.645539-6.198154 13.843692-13.843693 13.843692h-24.004923c-7.645538 0-13.843692-6.198153-13.843692-13.843692v-24.004923c0-7.645538 6.198154-13.843692 13.843692-13.843692h24.004923c7.645539 0 13.843693 6.198154 13.843693 13.843692z" fill="#f60"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
29
public/svgs/windmill.svg
Normal file
29
public/svgs/windmill.svg
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 256 256" style="enable-background:new 0 0 256 256;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
.st1{opacity:0.4;fill:#FFFFFF;}
|
||||||
|
.st2{fill:#BCD4FC;}
|
||||||
|
.st3{fill:#3B82F6;}
|
||||||
|
.st4{fill:#B3B3B3;}
|
||||||
|
.st5{fill:url(#SVGID_1_);}
|
||||||
|
.st6{fill:url(#SVGID_00000021089067129159788970000008246765442136188072_);}
|
||||||
|
.st7{fill:url(#SVGID_00000117639240116366130650000015074833605515028638_);}
|
||||||
|
.st8{opacity:0.4;fill:url(#SVGID_00000101781798616409025840000016567063639337360777_);}
|
||||||
|
.st9{opacity:0.4;fill:url(#SVGID_00000052086836598721292040000002033117744178971046_);}
|
||||||
|
.st10{opacity:0.4;fill:url(#SVGID_00000159460939004760751800000002448009281983951536_);}
|
||||||
|
.st11{opacity:0.4;fill:url(#SVGID_00000013177830667419993080000017721442101626521532_);}
|
||||||
|
.st12{opacity:0.4;fill:url(#SVGID_00000152235521444854938490000006526001119318383285_);}
|
||||||
|
.st13{opacity:0.4;fill:url(#SVGID_00000119823135212293698520000012774889010992664993_);}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<polygon class="st2" points="134.78,14.22 114.31,48.21 101.33,69.75 158.22,69.75 177.97,36.95 191.67,14.22 "/>
|
||||||
|
<polygon class="st3" points="227.55,69.75 186.61,69.75 101.33,69.75 129.78,119.02 158.16,119.02 228.61,119.02 256,119.02 "/>
|
||||||
|
<polygon class="st3" points="136.93,132.47 116.46,167.93 73.82,241.78 130.71,241.78 144.9,217.2 180.13,156.18 193.82,132.46
|
||||||
|
"/>
|
||||||
|
<polygon class="st3" points="121.7,131.95 101.23,96.49 58.59,22.63 30.15,71.91 44.34,96.49 79.57,157.5 93.26,181.22 "/>
|
||||||
|
<polygon class="st2" points="64.81,131.95 25.15,131.21 0,130.74 28.44,180.01 66.73,180.72 93.26,181.21 "/>
|
||||||
|
<polygon class="st2" points="165.38,181.74 184.58,216.46 196.75,238.47 225.19,189.2 206.66,155.69 193.83,132.46 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -617,6 +617,85 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
@if ($current_step === 'select-postgresql-type')
|
||||||
|
<h2>Select a Postgresql type</h2>
|
||||||
|
<div>If you need extra extensions, you can select Supabase PostgreSQL (or others), otherwise select PostgreSQL
|
||||||
|
16 (default).</div>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex"
|
||||||
|
wire:click="setPostgresqlType('postgres:16-alpine')">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="box-title">PostgreSQL 16 (default)</div>
|
||||||
|
<div class="box-description">
|
||||||
|
PostgreSQL is a powerful, open-source object-relational database system (no extensions).
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
|
||||||
|
<div class="flex items-center px-2" title="Read the documentation.">
|
||||||
|
<a class="p-2 hover:underline group-hover:dark:text-white dark:text-white text-neutral-6000"
|
||||||
|
onclick="event.stopPropagation()" href="https://hub.docker.com/_/postgres/"
|
||||||
|
target="_blank">
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex"
|
||||||
|
wire:click="setPostgresqlType('supabase/postgres:15.6.1.113')">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="box-title">Supabase PostgreSQL (with extensions)</div>
|
||||||
|
<div class="box-description">
|
||||||
|
Supabase is a modern, open-source alternative to PostgreSQL with lots of extensions.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex items-center px-2" title="Read the documentation.">
|
||||||
|
<a class="p-2 hover:underline group-hover:dark:text-white dark:text-white text-neutral-600"
|
||||||
|
onclick="event.stopPropagation()" href="https://github.com/supabase/postgres"
|
||||||
|
target="_blank">
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex"
|
||||||
|
wire:click="setPostgresqlType('postgis/postgis')">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="box-title">PostGIS</div>
|
||||||
|
<div class="box-description">
|
||||||
|
PostGIS is a PostgreSQL extension for geographic objects.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<div class="flex items-center px-2" title="Read the documentation.">
|
||||||
|
<a class="p-2 hover:underline group-hover:dark:text-white dark:text-white text-neutral-600"
|
||||||
|
onclick="event.stopPropagation()" href="https://github.com/postgis/docker-postgis"
|
||||||
|
target="_blank">
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gap-2 border border-transparent cursor-pointer box-without-bg dark:bg-coolgray-100 bg-white dark:hover:text-neutral-400 dark:hover:bg-coollabs group flex"
|
||||||
|
wire:click="setPostgresqlType('pgvector/pgvector:pg16')">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="box-title">PGVector (16)</div>
|
||||||
|
<div class="box-description">
|
||||||
|
PGVector is a PostgreSQL extension for vector data types.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
|
||||||
|
<div class="flex items-center px-2" title="Read the documentation.">
|
||||||
|
<a class="p-2 hover:underline group-hover:dark:text-white dark:text-white text-neutral-600"
|
||||||
|
onclick="event.stopPropagation()" href="https://github.com/pgvector/pgvector"
|
||||||
|
target="_blank">
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
@if ($current_step === 'existing-postgresql')
|
@if ($current_step === 'existing-postgresql')
|
||||||
<form wire:submit='addExistingPostgresql' class="flex items-end gap-4">
|
<form wire:submit='addExistingPostgresql' class="flex items-end gap-4">
|
||||||
<x-forms.input placeholder="postgres://username:password@database:5432" label="Database URL"
|
<x-forms.input placeholder="postgres://username:password@database:5432" label="Database URL"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
@endif
|
@endif
|
||||||
<div>{{ $workdir }}{{ $fs_path }} -> {{ $fileStorage->mount_path }}</div>
|
<div>{{ $workdir }}{{ $fs_path }} -> {{ $fileStorage->mount_path }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form wire:submit='submit' class="flex flex-col gap-2">
|
<form wire:submit='submit' class="flex flex-col gap-2">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@if ($fileStorage->is_directory)
|
@if ($fileStorage->is_directory)
|
||||||
@@ -26,25 +27,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</x-modal-confirmation>
|
</x-modal-confirmation>
|
||||||
@endif
|
@endif
|
||||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
|
||||||
<div class="px-2">This storage will be deleted. It is not reversible. <strong
|
@if (!$fileStorage->is_based_on_git)
|
||||||
class="text-error">Please
|
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||||
think
|
<div class="px-2">This storage will be deleted. It is not reversible. <strong
|
||||||
again.</strong><br><br></div>
|
class="text-error">Please
|
||||||
<h4>Actions</h4>
|
think
|
||||||
@if ($fileStorage->is_directory)
|
again.</strong><br><br></div>
|
||||||
<x-forms.checkbox id="permanently_delete"
|
<h4>Actions</h4>
|
||||||
label="Permanently delete directory from the server?"></x-forms.checkbox>
|
@if ($fileStorage->is_directory)
|
||||||
@else
|
<x-forms.checkbox id="permanently_delete"
|
||||||
<x-forms.checkbox id="permanently_delete"
|
label="Permanently delete directory from the server?"></x-forms.checkbox>
|
||||||
label="Permanently delete file from the server?"></x-forms.checkbox>
|
@else
|
||||||
@endif
|
<x-forms.checkbox id="permanently_delete"
|
||||||
</x-modal-confirmation>
|
label="Permanently delete file from the server?"></x-forms.checkbox>
|
||||||
|
@endif
|
||||||
|
</x-modal-confirmation>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@if (!$fileStorage->is_directory)
|
@if (!$fileStorage->is_directory)
|
||||||
<x-forms.textarea label="Content" rows="20" id="fileStorage.content"></x-forms.textarea>
|
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
|
||||||
<x-forms.button class="w-full" type="submit">Save</x-forms.button>
|
<div class="w-96">
|
||||||
|
<x-forms.checkbox instantSave label="Is this based on the Git repository?"
|
||||||
|
id="fileStorage.is_based_on_git"></x-forms.checkbox>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<x-forms.textarea
|
||||||
|
label="{{ $fileStorage->is_based_on_git ? 'Content (refreshed after a successful deployment)' : 'Content' }}"
|
||||||
|
rows="20" id="fileStorage.content"
|
||||||
|
readonly="{{ $fileStorage->is_based_on_git }}"></x-forms.textarea>
|
||||||
|
@if (!$fileStorage->is_based_on_git)
|
||||||
|
<x-forms.button class="w-full" type="submit">Save</x-forms.button>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,9 +19,6 @@
|
|||||||
<div class="box-description">
|
<div class="box-description">
|
||||||
Network: {{ data_get($resource, 'destination.network') }}
|
Network: {{ data_get($resource, 'destination.network') }}
|
||||||
</div>
|
</div>
|
||||||
@if ($resource->server_status == false)
|
|
||||||
<div class="text-xs font-bold text-error"> This server has connection problems. </div>
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
@if ($resource?->additional_networks?->count() > 0)
|
@if ($resource?->additional_networks?->count() > 0)
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<h2>Environment Variables</h2>
|
<h2>Environment Variables</h2>
|
||||||
<x-modal-input buttonTitle="+ Add" title="New Environment Variable">
|
<div class="flex flex-col items-center">
|
||||||
<livewire:project.shared.environment-variable.add />
|
<x-modal-input buttonTitle="+ Add" title="New Environment Variable">
|
||||||
</x-modal-input>
|
<livewire:project.shared.environment-variable.add />
|
||||||
|
</x-modal-input>
|
||||||
|
</div>
|
||||||
<x-forms.button
|
<x-forms.button
|
||||||
wire:click='switch'>{{ $view === 'normal' ? 'Developer view' : 'Normal view' }}</x-forms.button>
|
wire:click='switch'>{{ $view === 'normal' ? 'Developer view' : 'Normal view' }}</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
@if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose')
|
@if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose')
|
||||||
<div class="w-64 pt-2">
|
<div class="w-64 pt-2">
|
||||||
<x-forms.checkbox id="resource.settings.is_env_sorting_enabled" label="Sort alphabetically"
|
<x-forms.checkbox id="resource.settings.is_env_sorting_enabled" label="Sort alphabetically"
|
||||||
helper="Turn this off if one environment is dependent on an other. It will be sorted by creation order."
|
helper="Turn this off if one environment is dependent on an other. It will be sorted by creation order (like you pasted them or in the order you created them)."
|
||||||
instantSave></x-forms.checkbox>
|
instantSave></x-forms.checkbox>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -31,6 +33,10 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@if ($view === 'normal')
|
@if ($view === 'normal')
|
||||||
|
<div>
|
||||||
|
<h3>Production Environment Variables</h3>
|
||||||
|
<div>Environment (secrets) variables for Production.</div>
|
||||||
|
</div>
|
||||||
@forelse ($resource->environment_variables as $env)
|
@forelse ($resource->environment_variables as $env)
|
||||||
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
|
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
|
||||||
:env="$env" :type="$resource->type()" />
|
:env="$env" :type="$resource->type()" />
|
||||||
@@ -39,7 +45,7 @@
|
|||||||
@endforelse
|
@endforelse
|
||||||
@if ($resource->type() === 'application' && $resource->environment_variables_preview->count() > 0 && $showPreview)
|
@if ($resource->type() === 'application' && $resource->environment_variables_preview->count() > 0 && $showPreview)
|
||||||
<div>
|
<div>
|
||||||
<h3>Preview Deployments</h3>
|
<h3>Preview Deployments Environment Variables</h3>
|
||||||
<div>Environment (secrets) variables for Preview Deployments.</div>
|
<div>Environment (secrets) variables for Preview Deployments.</div>
|
||||||
</div>
|
</div>
|
||||||
@foreach ($resource->environment_variables_preview as $env)
|
@foreach ($resource->environment_variables_preview as $env)
|
||||||
@@ -48,16 +54,15 @@
|
|||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
<form wire:submit='saveVariables(false)' class="flex flex-col gap-2">
|
<form wire:submit.prevent='submit' class="flex flex-col gap-2">
|
||||||
<x-forms.textarea rows="10" class="whitespace-pre-wrap" id="variables"></x-forms.textarea>
|
<x-forms.textarea rows="10" class="whitespace-pre-wrap" id="variables" wire:model="variables" label="Production Environment Variables"></x-forms.textarea>
|
||||||
<x-forms.button type="submit" class="btn btn-primary">Save</x-forms.button>
|
|
||||||
|
@if ($showPreview)
|
||||||
|
<x-forms.textarea rows="10" class="whitespace-pre-wrap" label="Preview Deployments Environment Variables"
|
||||||
|
id="variablesPreview" wire:model="variablesPreview"></x-forms.textarea>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<x-forms.button type="submit" class="btn btn-primary">Save All Environment Variables</x-forms.button>
|
||||||
</form>
|
</form>
|
||||||
@if ($showPreview)
|
|
||||||
<form wire:submit='saveVariables(true)' class="flex flex-col gap-2">
|
|
||||||
<x-forms.textarea rows="10" class="whitespace-pre-wrap" label="Preview Environment Variables"
|
|
||||||
id="variablesPreview"></x-forms.textarea>
|
|
||||||
<x-forms.button type="submit" class="btn btn-primary">Save</x-forms.button>
|
|
||||||
</form>
|
|
||||||
@endif
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@@ -1,15 +1,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<form wire:submit='submit'
|
<form wire:submit='submit'
|
||||||
class="flex flex-col items-center gap-4 p-4 bg-white border lg:items-start dark:bg-base dark:border-coolgray-300">
|
class="flex flex-col items-center gap-4 p-4 bg-white border lg:items-start dark:bg-base dark:border-coolgray-300">
|
||||||
{{-- @if (!$env->isFoundInCompose && !$isSharedVariable)
|
|
||||||
<div class="flex items-center justify-center gap-2 dark:text-warning text-coollabs"> <svg
|
|
||||||
class="hidden w-4 h-4 dark:text-warning lg:block" viewBox="0 0 256 256"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill="currentColor"
|
|
||||||
d="M240.26 186.1L152.81 34.23a28.74 28.74 0 0 0-49.62 0L15.74 186.1a27.45 27.45 0 0 0 0 27.71A28.31 28.31 0 0 0 40.55 228h174.9a28.31 28.31 0 0 0 24.79-14.19a27.45 27.45 0 0 0 .02-27.71m-20.8 15.7a4.46 4.46 0 0 1-4 2.2H40.55a4.46 4.46 0 0 1-4-2.2a3.56 3.56 0 0 1 0-3.73L124 46.2a4.77 4.77 0 0 1 8 0l87.44 151.87a3.56 3.56 0 0 1 .02 3.73M116 136v-32a12 12 0 0 1 24 0v32a12 12 0 0 1-24 0m28 40a16 16 0 1 1-16-16a16 16 0 0 1 16 16">
|
|
||||||
</path>
|
|
||||||
</svg>This variable is not found in the compose file, so it won't be used.</div>
|
|
||||||
@endif --}}
|
|
||||||
@if ($isLocked)
|
@if ($isLocked)
|
||||||
<div class="flex flex-1 w-full gap-2">
|
<div class="flex flex-1 w-full gap-2">
|
||||||
<x-forms.input disabled id="env.key" />
|
<x-forms.input disabled id="env.key" />
|
||||||
|
|||||||
@@ -1,43 +1,47 @@
|
|||||||
<div class="flex flex-col w-full gap-2 rounded">
|
<div class="flex flex-col w-full gap-2 rounded max-h-[80vh] overflow-y-auto scrollbar">
|
||||||
You can add Volumes, Files and Directories to your resources here.
|
<div class="p-4">
|
||||||
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submitPersistentVolume'>
|
You can add Volumes, Files and Directories to your resources here.
|
||||||
<h3>Volume Mount</h3>
|
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submitPersistentVolume'>
|
||||||
@if ($isSwarm)
|
<h3>Volume Mount</h3>
|
||||||
<h5>Swarm Mode detected: You need to set a shared volume (EFS/NFS/etc) on all the worker nodes if you would
|
@if ($isSwarm)
|
||||||
like to use a persistent volumes.</h5>
|
<h5>Swarm Mode detected: You need to set a shared volume (EFS/NFS/etc) on all the worker nodes if you
|
||||||
@endif
|
would
|
||||||
<x-forms.input placeholder="pv-name" id="name" label="Name" required helper="Volume name." />
|
like to use a persistent volumes.</h5>
|
||||||
@if ($isSwarm)
|
@endif
|
||||||
<x-forms.input placeholder="/root" id="host_path" label="Source Path" required
|
<x-forms.input placeholder="pv-name" id="name" label="Name" required helper="Volume name." />
|
||||||
|
@if ($isSwarm)
|
||||||
|
<x-forms.input placeholder="/root" id="host_path" label="Source Path" required
|
||||||
|
helper="Directory on the host system." />
|
||||||
|
@else
|
||||||
|
<x-forms.input placeholder="/root" id="host_path" label="Source Path"
|
||||||
|
helper="Directory on the host system." />
|
||||||
|
@endif
|
||||||
|
<x-forms.input placeholder="/tmp/root" id="mount_path" label="Destination Path" required
|
||||||
|
helper="Directory inside the container." />
|
||||||
|
<x-forms.button type="submit" @click="modalOpen=false">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submitFileStorage'>
|
||||||
|
<h3>File Mount</h3>
|
||||||
|
<x-forms.input placeholder="/etc/nginx/nginx.conf" id="file_storage_path" label="Destination Path" required
|
||||||
|
helper="File inside the container" />
|
||||||
|
<x-forms.textarea label="Content" id="file_storage_content"></x-forms.textarea>
|
||||||
|
<x-forms.button type="submit" @click="modalOpen=false">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</form>
|
||||||
|
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submitFileStorageDirectory'>
|
||||||
|
<h3>Directory Mount</h3>
|
||||||
|
<x-forms.input placeholder="{{ application_configuration_dir() }}/{{ $resource->uuid }}/etc/nginx"
|
||||||
|
id="file_storage_directory_source" label="Source Directory" required
|
||||||
helper="Directory on the host system." />
|
helper="Directory on the host system." />
|
||||||
@else
|
<x-forms.input placeholder="/etc/nginx" id="file_storage_directory_destination"
|
||||||
<x-forms.input placeholder="/root" id="host_path" label="Source Path"
|
label="Destination Directory" required helper="Directory inside the container." />
|
||||||
helper="Directory on the host system." />
|
<x-forms.button type="submit" @click="modalOpen=false">
|
||||||
@endif
|
Save
|
||||||
<x-forms.input placeholder="/tmp/root" id="mount_path" label="Destination Path" required
|
</x-forms.button>
|
||||||
helper="Directory inside the container." />
|
</form>
|
||||||
<x-forms.button type="submit" @click="modalOpen=false">
|
</div>
|
||||||
Save
|
|
||||||
</x-forms.button>
|
|
||||||
</form>
|
|
||||||
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submitFileStorage'>
|
|
||||||
<h3>File Mount</h3>
|
|
||||||
<x-forms.input placeholder="/etc/nginx/nginx.conf" id="file_storage_path" label="Destination Path" required
|
|
||||||
helper="File inside the container" />
|
|
||||||
<x-forms.textarea label="Content" id="file_storage_content"></x-forms.textarea>
|
|
||||||
<x-forms.button type="submit" @click="modalOpen=false">
|
|
||||||
Save
|
|
||||||
</x-forms.button>
|
|
||||||
</form>
|
|
||||||
<form class="flex flex-col w-full gap-2 rounded" wire:submit='submitFileStorageDirectory'>
|
|
||||||
<h3>Directory Mount</h3>
|
|
||||||
<x-forms.input placeholder="{{ application_configuration_dir() }}/{{ $resource->uuid }}/etc/nginx"
|
|
||||||
id="file_storage_directory_source" label="Source Directory" required
|
|
||||||
helper="Directory on the host system." />
|
|
||||||
<x-forms.input placeholder="/etc/nginx" id="file_storage_directory_destination" label="Destination Directory"
|
|
||||||
required helper="Directory inside the container." />
|
|
||||||
<x-forms.button type="submit" @click="modalOpen=false">
|
|
||||||
Save
|
|
||||||
</x-forms.button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -120,8 +120,6 @@ Route::group([
|
|||||||
Route::match(['get', 'post'], '/services/{uuid}/restart', [ServicesController::class, 'action_restart'])->middleware([IgnoreReadOnlyApiToken::class]);
|
Route::match(['get', 'post'], '/services/{uuid}/restart', [ServicesController::class, 'action_restart'])->middleware([IgnoreReadOnlyApiToken::class]);
|
||||||
Route::match(['get', 'post'], '/services/{uuid}/stop', [ServicesController::class, 'action_stop'])->middleware([IgnoreReadOnlyApiToken::class]);
|
Route::match(['get', 'post'], '/services/{uuid}/stop', [ServicesController::class, 'action_stop'])->middleware([IgnoreReadOnlyApiToken::class]);
|
||||||
|
|
||||||
// Route::delete('/envs/{env_uuid}', [EnvironmentVariablesController::class, 'delete_env_by_uuid'])->middleware([IgnoreReadOnlyApiToken::class]);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::any('/{any}', function () {
|
Route::any('/{any}', function () {
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ arch)
|
|||||||
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
||||||
;;
|
;;
|
||||||
ubuntu | debian | raspbian)
|
ubuntu | debian | raspbian)
|
||||||
apt update -y >/dev/null
|
apt-get update -y >/dev/null
|
||||||
apt install -y curl wget git jq >/dev/null
|
apt-get install -y curl wget git jq >/dev/null
|
||||||
;;
|
;;
|
||||||
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||||
if [ "$OS_TYPE" = "amzn" ]; then
|
if [ "$OS_TYPE" = "amzn" ]; then
|
||||||
|
|||||||
150
templates/compose/budibase.yaml
Normal file
150
templates/compose/budibase.yaml
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
# documentation: https://docs.budibase.com/docs/docker-compose
|
||||||
|
# slogan: Low code platform for building business apps and workflows in minutes. Supports PostgreSQL, MySQL, MSSQL, MongoDB, Rest API, Docker, K8s, and more.
|
||||||
|
# tags: budibase,low-code,business-apps,workflow,automation,postgresql,mysql,mssql,mongodb,docker,kubernetes
|
||||||
|
# logo: svgs/budibase.svg
|
||||||
|
# port: 10000
|
||||||
|
|
||||||
|
services:
|
||||||
|
app-service:
|
||||||
|
image: budibase.docker.scarf.sh/budibase/apps
|
||||||
|
environment:
|
||||||
|
- SELF_HOSTED=1
|
||||||
|
- COUCH_DB_URL=http://$SERVICE_USER_BUDIBASE_COUCHDB:$SERVICE_PASSWORD_BUDIBASE_COUCHDB@couchdb-service:5984
|
||||||
|
- WORKER_URL=http://worker-service:4003
|
||||||
|
- MINIO_URL=http://minio-service:9000
|
||||||
|
- MINIO_ACCESS_KEY=$SERVICE_USER_BUDIBASE_MINIO
|
||||||
|
- MINIO_SECRET_KEY=$SERVICE_PASSWORD_BUDIBASE_MINIO
|
||||||
|
- INTERNAL_API_KEY=$SERVICE_BASE64_128_BUDIBASE
|
||||||
|
- BUDIBASE_ENVIRONMENT=${BUDIBASE_ENVIRONMENT:-PRODUCTION}
|
||||||
|
- PORT=4002
|
||||||
|
- API_ENCRYPTION_KEY=$SERVICE_BASE64_64_BUDIBASE
|
||||||
|
- JWT_SECRET=$SERVICE_BASE64_64_BUDIBASE
|
||||||
|
- LOG_LEVEL=info
|
||||||
|
- ENABLE_ANALYTICS=${ENABLE_ANALYTICS:-true}
|
||||||
|
- REDIS_URL=redis-service:6379
|
||||||
|
- REDIS_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_REDIS
|
||||||
|
- BB_ADMIN_USER_EMAIL=
|
||||||
|
- BB_ADMIN_USER_PASSWORD=
|
||||||
|
depends_on:
|
||||||
|
- worker-service
|
||||||
|
- redis-service
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://app-service:4002"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 15s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
worker-service:
|
||||||
|
image: budibase.docker.scarf.sh/budibase/worker
|
||||||
|
environment:
|
||||||
|
- SELF_HOSTED=1
|
||||||
|
- PORT=4003
|
||||||
|
- CLUSTER_PORT=10000
|
||||||
|
- API_ENCRYPTION_KEY=$SERVICE_BASE64_64_BUDIBASE
|
||||||
|
- JWT_SECRET=$SERVICE_BASE64_64_BUDIBASE
|
||||||
|
- MINIO_ACCESS_KEY=$SERVICE_USER_BUDIBASE_MINIO
|
||||||
|
- MINIO_SECRET_KEY=$SERVICE_PASSWORD_BUDIBASE_MINIO
|
||||||
|
- MINIO_URL=http://minio-service:9000
|
||||||
|
- APPS_URL=http://app-service:4002
|
||||||
|
- COUCH_DB_USERNAME=$SERVICE_USER_BUDIBASE_COUCHDB
|
||||||
|
- COUCH_DB_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_COUCHDB
|
||||||
|
- COUCH_DB_URL=http://$SERVICE_USER_BUDIBASE_COUCHDB:$SERVICE_PASSWORD_BUDIBASE_COUCHDB@couchdb-service:5984
|
||||||
|
- INTERNAL_API_KEY=$SERVICE_BASE64_128_BUDIBASE
|
||||||
|
- REDIS_URL=redis-service:6379
|
||||||
|
- REDIS_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_REDIS
|
||||||
|
depends_on:
|
||||||
|
- redis-service
|
||||||
|
- minio-service
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://worker-service:4003"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 15s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
minio-service:
|
||||||
|
image: minio/minio
|
||||||
|
volumes:
|
||||||
|
- minio_data:/data
|
||||||
|
environment:
|
||||||
|
- MINIO_ACCESS_KEY=$SERVICE_USER_BUDIBASE_MINIO
|
||||||
|
- MINIO_SECRET_KEY=$SERVICE_PASSWORD_BUDIBASE_MINIO
|
||||||
|
- MINIO_BROWSER=off
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
proxy-service:
|
||||||
|
image: budibase/proxy
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_BUDIBASE_10000
|
||||||
|
- PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND=10
|
||||||
|
- PROXY_RATE_LIMIT_API_PER_SECOND=20
|
||||||
|
- APPS_UPSTREAM_URL=http://app-service:4002
|
||||||
|
- WORKER_UPSTREAM_URL=http://worker-service:4003
|
||||||
|
- MINIO_UPSTREAM_URL=http://minio-service:9000
|
||||||
|
- COUCHDB_UPSTREAM_URL=http://couchdb-service:5984
|
||||||
|
- WATCHTOWER_UPSTREAM_URL=http://watchtower-service:8080
|
||||||
|
- RESOLVER=127.0.0.11
|
||||||
|
depends_on:
|
||||||
|
- minio-service
|
||||||
|
- worker-service
|
||||||
|
- app-service
|
||||||
|
- couchdb-service
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:10000/"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 15s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
couchdb-service:
|
||||||
|
image: budibase/couchdb
|
||||||
|
environment:
|
||||||
|
- COUCHDB_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_COUCHDB
|
||||||
|
- COUCHDB_USER=$SERVICE_USER_BUDIBASE_COUCHDB
|
||||||
|
- TARGETBUILD=docker-compose
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:5984/"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 15s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
volumes:
|
||||||
|
- couchdb3_data:/opt/couchdb/data
|
||||||
|
|
||||||
|
redis-service:
|
||||||
|
image: redis
|
||||||
|
command: redis-server --requirepass "$SERVICE_PASSWORD_BUDIBASE_REDIS"
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
["CMD", "redis-cli", "-a", "$SERVICE_PASSWORD_BUDIBASE_REDIS", "ping"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 15s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
watchtower-service:
|
||||||
|
restart: always
|
||||||
|
image: containrrr/watchtower
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
command: --debug --http-api-update bbapps bbworker bbproxy
|
||||||
|
environment:
|
||||||
|
- WATCHTOWER_HTTP_API=true
|
||||||
|
- WATCHTOWER_HTTP_API_TOKEN=$SERVICE_PASSWORD_BUDIBASE_WATCHTOWER
|
||||||
|
- WATCHTOWER_CLEANUP=true
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=false"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://watchtower-service:8080"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 15s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
152
templates/compose/chaskiq.yaml
Normal file
152
templates/compose/chaskiq.yaml
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# documentation: https://chaskiq.io
|
||||||
|
# slogan: Chaskiq is an messaging platform for marketing, support & sales
|
||||||
|
# tags: chaskiq,messaging,chat,marketing,support,sales,open,source,rails,redis,postgresql,sidekiq
|
||||||
|
# logo: svgs/chaskiq.png
|
||||||
|
# port: 3000
|
||||||
|
|
||||||
|
services:
|
||||||
|
chaskiq:
|
||||||
|
image: chaskiq/chaskiq:latest
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_CHASKIQ_3000
|
||||||
|
- REDIS_URL=redis://redis:6379/
|
||||||
|
- DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/${POSTGRES_DB:-chaskiq}
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- SERVICE_URL=${SERVICE_URL_CHASKIQ}
|
||||||
|
- HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- ASSET_HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- WS=wss://${SERVICE_URL_CHASKIQ}/cable
|
||||||
|
- SNS_CONFIGURATION_SET=metrics
|
||||||
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
|
||||||
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
|
||||||
|
- AWS_S3_BUCKET=${AWS_S3_BUCKET:-}
|
||||||
|
- AWS_S3_REGION=${AWS_S3_REGION:-}
|
||||||
|
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example}
|
||||||
|
- ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}
|
||||||
|
- DEFAULT_SENDER_EMAIL=${DEFAULT_SENDER_EMAIL:-admin@example}
|
||||||
|
- LOCAL_STORAGE_PATH=/data/storage
|
||||||
|
- ACTIVE_STORAGE_SERVICE=${ACTIVE_STORAGE_SERVICE:-local}
|
||||||
|
- SMTP_DELIVERY_METHOD=${SMTP_DELIVERY_METHOD:-}
|
||||||
|
- SMTP_ADDRESS=${SMTP_ADDRESS:-}
|
||||||
|
- SMTP_USERNAME=${SMTP_USERNAME:-}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASSWORD:-}
|
||||||
|
- CHASKIQ_APPSTORE_TOKEN=${CHASKIQ_APPSTORE_TOKEN:-}
|
||||||
|
- APP_ENV=production
|
||||||
|
- RAILS_ENV=production
|
||||||
|
- RACK_ENV=production
|
||||||
|
- RAILS_SERVE_STATIC_FILES=true
|
||||||
|
- SECRET_KEY_BASE=$SERVICE_PASSWORD_64_SECRET
|
||||||
|
- RAILS_LOG_TO_STDOUT=true
|
||||||
|
- ENABLED_AUDITS=true
|
||||||
|
- TZ=Europe/Madrid
|
||||||
|
entrypoint: ["/entrypoint.sh"]
|
||||||
|
depends_on:
|
||||||
|
postgresql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- chaskiq-storage:/data/storage
|
||||||
|
- type: bind
|
||||||
|
source: ./entrypoint.sh
|
||||||
|
target: /entrypoint.sh
|
||||||
|
content: |
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
rm -f /usr/src/app/tmp/pids/server.pid
|
||||||
|
exec "$@"
|
||||||
|
echo "Running database migrations..."
|
||||||
|
bundle exec rails db:setup || true
|
||||||
|
bundle exec rails db:migrate
|
||||||
|
echo "Finished running database migrations."
|
||||||
|
echo "Running packages update..."
|
||||||
|
bundle exec rails packages:update
|
||||||
|
echo "Finished packages update."
|
||||||
|
if [ ! -f /usr/src/app/admin_generated ]; then
|
||||||
|
echo "/usr/src/app/admin_generated not found, executing admin generation.."
|
||||||
|
bundle exec rake admin_generator
|
||||||
|
touch /usr/src/app/admin_generated
|
||||||
|
echo "Admin generation finished !"
|
||||||
|
fi
|
||||||
|
bundle exec rails s -b 0.0.0.0 -p 3000
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 15
|
||||||
|
sidekiq:
|
||||||
|
image: chaskiq/chaskiq:latest
|
||||||
|
environment:
|
||||||
|
- REDIS_URL=redis://redis:6379/
|
||||||
|
- DATABASE_URL=postgres://$SERVICE_USER_POSTGRES:$SERVICE_PASSWORD_POSTGRES@postgresql:5432/${POSTGRES_DB:-chaskiq}
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- ASSET_HOST=${SERVICE_FQDN_CHASKIQ_3000}
|
||||||
|
- WS=wss://${SERVICE_URL_CHASKIQ}/cable
|
||||||
|
- SNS_CONFIGURATION_SET=metrics
|
||||||
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
|
||||||
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
|
||||||
|
- AWS_S3_BUCKET=${AWS_S3_BUCKET:-}
|
||||||
|
- AWS_S3_REGION=${AWS_S3_REGION:-}
|
||||||
|
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example}
|
||||||
|
- ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN}
|
||||||
|
- DEFAULT_SENDER_EMAIL=${DEFAULT_SENDER_EMAIL:-admin@example}
|
||||||
|
- LOCAL_STORAGE_PATH=/data/storage
|
||||||
|
- ACTIVE_STORAGE_SERVICE=${ACTIVE_STORAGE_SERVICE:-local}
|
||||||
|
- SMTP_DELIVERY_METHOD=${SMTP_DELIVERY_METHOD:-}
|
||||||
|
- SMTP_ADDRESS=${SMTP_ADDRESS:-}
|
||||||
|
- SMTP_USERNAME=${SMTP_USERNAME:-}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASSWORD:-}
|
||||||
|
- CHASKIQ_APPSTORE_TOKEN=${CHASKIQ_APPSTORE_TOKEN:-}
|
||||||
|
- APP_ENV=production
|
||||||
|
- RAILS_ENV=production
|
||||||
|
- RACK_ENV=production
|
||||||
|
- RAILS_SERVE_STATIC_FILES=true
|
||||||
|
- SECRET_KEY_BASE=$SERVICE_PASSWORD_64_SECRET
|
||||||
|
- RAILS_LOG_TO_STDOUT=true
|
||||||
|
- ENABLED_AUDITS=true
|
||||||
|
- TZ=Europe/Madrid
|
||||||
|
volumes:
|
||||||
|
- chaskiq-storage:/data/storage
|
||||||
|
depends_on:
|
||||||
|
postgresql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
chaskiq:
|
||||||
|
condition: service_healthy
|
||||||
|
command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"]
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
[
|
||||||
|
"CMD-SHELL",
|
||||||
|
"bundle exec rails runner 'puts Sidekiq.redis(&:info)' > /dev/null 2>&1",
|
||||||
|
]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 15
|
||||||
|
postgresql:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
volumes:
|
||||||
|
- postgresql-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=$SERVICE_USER_POSTGRES
|
||||||
|
- POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
|
||||||
|
- POSTGRES_DB=${POSTGRES_DB:-chaskiq}
|
||||||
|
- POSTGRES_INITDB_ARGS= --data-checksums
|
||||||
|
- PSQL_HISTFILE=/root/log/.psql_history
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
redis:
|
||||||
|
image: redis:6-alpine
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- redis-data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
# ignore: true
|
|
||||||
# documentation: https://www.rabbitmq.com/documentation.html
|
# documentation: https://www.rabbitmq.com/documentation.html
|
||||||
# slogan: With tens of thousands of users, RabbitMQ is one of the most popular open source message brokers.
|
# slogan: With tens of thousands of users, RabbitMQ is one of the most popular open source message brokers.
|
||||||
# tags: message broker, message queue, message-oriented middleware, MOM, AMQP, MQTT, STOMP, messaging
|
# tags: message broker, message queue, message-oriented middleware, MOM, AMQP, MQTT, STOMP, messaging
|
||||||
|
# logo: svgs/rabbitmq.svg
|
||||||
|
# port: 15672
|
||||||
|
|
||||||
services:
|
services:
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
image: rabbitmq:3
|
image: rabbitmq:3-management
|
||||||
environment:
|
environment:
|
||||||
- SERVICE_FQDN_RABBITMQ_5672
|
- SERVICE_FQDN_RABBITMQ_15672
|
||||||
- RABBITMQ_DEFAULT_USER=$SERVICE_USER_RABBITMQ
|
- RABBITMQ_DEFAULT_USER=$SERVICE_USER_RABBITMQ
|
||||||
- RABBITMQ_DEFAULT_PASS=$SERVICE_PASSWORD_RABBITMQ
|
- RABBITMQ_DEFAULT_PASS=$SERVICE_PASSWORD_RABBITMQ
|
||||||
|
- PORT=${PORT:-5672}
|
||||||
|
ports:
|
||||||
|
- ${PORT}:5672
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: rabbitmq-diagnostics -q ping
|
test: rabbitmq-diagnostics -q ping
|
||||||
interval: 30s
|
interval: 30s
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ services:
|
|||||||
config:
|
config:
|
||||||
hide_credentials: true
|
hide_credentials: true
|
||||||
supabase-studio:
|
supabase-studio:
|
||||||
image: supabase/studio:20240514-6f5cabd
|
image: supabase/studio:20240729-ce42139
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test:
|
test:
|
||||||
[
|
[
|
||||||
@@ -315,7 +315,7 @@ services:
|
|||||||
# Uncomment to use Big Query backend for analytics
|
# Uncomment to use Big Query backend for analytics
|
||||||
# NEXT_ANALYTICS_BACKEND_PROVIDER=bigquery
|
# NEXT_ANALYTICS_BACKEND_PROVIDER=bigquery
|
||||||
supabase-db:
|
supabase-db:
|
||||||
image: supabase/postgres:15.1.1.41
|
image: supabase/postgres:15.1.1.78
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: pg_isready -U postgres -h 127.0.0.1
|
test: pg_isready -U postgres -h 127.0.0.1
|
||||||
interval: 5s
|
interval: 5s
|
||||||
@@ -895,7 +895,7 @@ services:
|
|||||||
command: ["--config", "etc/vector/vector.yml"]
|
command: ["--config", "etc/vector/vector.yml"]
|
||||||
|
|
||||||
supabase-rest:
|
supabase-rest:
|
||||||
image: postgrest/postgrest:v12.0.1
|
image: postgrest/postgrest:v12.2.0
|
||||||
depends_on:
|
depends_on:
|
||||||
supabase-db:
|
supabase-db:
|
||||||
# Disable this if you are using an external Postgres database
|
# Disable this if you are using an external Postgres database
|
||||||
@@ -941,8 +941,9 @@ services:
|
|||||||
|
|
||||||
- GOTRUE_DB_DRIVER=postgres
|
- GOTRUE_DB_DRIVER=postgres
|
||||||
- GOTRUE_DB_DATABASE_URL=postgres://supabase_auth_admin:${SERVICE_PASSWORD_POSTGRES}@${POSTGRES_HOSTNAME:-supabase-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}
|
- GOTRUE_DB_DATABASE_URL=postgres://supabase_auth_admin:${SERVICE_PASSWORD_POSTGRES}@${POSTGRES_HOSTNAME:-supabase-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}
|
||||||
|
# The base URL your site is located at. Currently used in combination with other settings to construct URLs used in emails.
|
||||||
- GOTRUE_SITE_URL=${SERVICE_FQDN_SUPABASEKONG}
|
- GOTRUE_SITE_URL=${SERVICE_FQDN_SUPABASEKONG}
|
||||||
|
# A comma separated list of URIs (e.g. "https://foo.example.com,https://*.foo.example.com,https://bar.example.com") which are permitted as valid redirect_to destinations.
|
||||||
- GOTRUE_URI_ALLOW_LIST=${ADDITIONAL_REDIRECT_URLS}
|
- GOTRUE_URI_ALLOW_LIST=${ADDITIONAL_REDIRECT_URLS}
|
||||||
- GOTRUE_DISABLE_SIGNUP=${DISABLE_SIGNUP:-false}
|
- GOTRUE_DISABLE_SIGNUP=${DISABLE_SIGNUP:-false}
|
||||||
|
|
||||||
@@ -991,10 +992,20 @@ services:
|
|||||||
|
|
||||||
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED="true"
|
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED="true"
|
||||||
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/password_verification_attempt"
|
# GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="pg-functions://postgres/public/password_verification_attempt"
|
||||||
|
|
||||||
|
# Uncomment to enable common OAuth Variables
|
||||||
|
#- 'GOTRUE_EXTERNAL_GITHUB_CLIENT_ID=${GOTRUE_EXTERNAL_GITHUB_CLIENT_ID}'
|
||||||
|
#- 'GOTRUE_EXTERNAL_GITHUB_ENABLED=${GOTRUE_EXTERNAL_GITHUB_ENABLED}'
|
||||||
|
#- 'GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI=${GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI}'
|
||||||
|
#- 'GOTRUE_EXTERNAL_GITHUB_SECRET=${GOTRUE_EXTERNAL_GITHUB_SECRET}'
|
||||||
|
#- 'GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=${GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID}'
|
||||||
|
#- 'GOTRUE_EXTERNAL_GOOGLE_ENABLED=${GOTRUE_EXTERNAL_GOOGLE_ENABLED}'
|
||||||
|
#- 'GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=${GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI}'
|
||||||
|
#- 'GOTRUE_EXTERNAL_GOOGLE_SECRET=${GOTRUE_EXTERNAL_GOOGLE_SECRET}'
|
||||||
|
|
||||||
realtime-dev:
|
realtime-dev:
|
||||||
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
|
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
|
||||||
image: supabase/realtime:v2.28.32
|
image: supabase/realtime:v2.30.23
|
||||||
container_name: realtime-dev.supabase-realtime
|
container_name: realtime-dev.supabase-realtime
|
||||||
depends_on:
|
depends_on:
|
||||||
supabase-db:
|
supabase-db:
|
||||||
@@ -1034,6 +1045,9 @@ services:
|
|||||||
- ERL_AFLAGS=-proto_dist inet_tcp
|
- ERL_AFLAGS=-proto_dist inet_tcp
|
||||||
- ENABLE_TAILSCALE=false
|
- ENABLE_TAILSCALE=false
|
||||||
- DNS_NODES=''
|
- DNS_NODES=''
|
||||||
|
- RLIMIT_NOFILE=10000
|
||||||
|
- APP_NAME=realtime
|
||||||
|
- SEED_SELF_HOST=true
|
||||||
command: >
|
command: >
|
||||||
sh -c "/app/bin/migrate && /app/bin/realtime eval 'Realtime.Release.seeds(Realtime.Repo)' && /app/bin/server"
|
sh -c "/app/bin/migrate && /app/bin/realtime eval 'Realtime.Release.seeds(Realtime.Repo)' && /app/bin/server"
|
||||||
supabase-minio:
|
supabase-minio:
|
||||||
@@ -1155,7 +1169,7 @@ services:
|
|||||||
- ./volumes/storage:/var/lib/storage
|
- ./volumes/storage:/var/lib/storage
|
||||||
|
|
||||||
supabase-meta:
|
supabase-meta:
|
||||||
image: supabase/postgres-meta:v0.80.0
|
image: supabase/postgres-meta:v0.83.2
|
||||||
depends_on:
|
depends_on:
|
||||||
supabase-db:
|
supabase-db:
|
||||||
# Disable this if you are using an external Postgres database
|
# Disable this if you are using an external Postgres database
|
||||||
|
|||||||
97
templates/compose/windmill.yaml
Normal file
97
templates/compose/windmill.yaml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# documentation: https://www.windmill.dev/docs/
|
||||||
|
# slogan: Windmill is a developer platform to build production-grade multi-steps automations and internal apps.\
|
||||||
|
# info: Login as admin@windmill.dev / changeme to setup the instance & accounts and give yourself super-admin privileges.
|
||||||
|
# tags: windmill,workflow,automation,developer,platform
|
||||||
|
# logo: svgs/windmill.svg
|
||||||
|
# port: 8000
|
||||||
|
|
||||||
|
version: "3.7"
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16
|
||||||
|
shm_size: 1g
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: $SERVICE_PASSWORD_WINDMILL_POSTGRES
|
||||||
|
POSTGRES_DB: windmill
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
windmill_server:
|
||||||
|
image: ghcr.io/windmill-labs/windmill:main
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
|
||||||
|
- MODE=server
|
||||||
|
- BASE_URL=$SERVICE_FQDN_WINDMILL
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
|
||||||
|
windmill_worker_1:
|
||||||
|
image: ghcr.io/windmill-labs/windmill:main
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
|
||||||
|
- MODE=worker
|
||||||
|
- WORKER_GROUP=default
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- worker_dependency_cache:/tmp/windmill/cache
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
|
||||||
|
windmill_worker_2:
|
||||||
|
image: ghcr.io/windmill-labs/windmill:main
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
|
||||||
|
- MODE=worker
|
||||||
|
- WORKER_GROUP=default
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- worker_dependency_cache:/tmp/windmill/cache
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
|
||||||
|
windmill_worker_3:
|
||||||
|
image: ghcr.io/windmill-labs/windmill:main
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
|
||||||
|
- MODE=worker
|
||||||
|
- WORKER_GROUP=default
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- worker_dependency_cache:/tmp/windmill/cache
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
|
||||||
|
windmill_worker_native:
|
||||||
|
image: ghcr.io/windmill-labs/windmill:main
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://postgres:$SERVICE_PASSWORD_WINDMILL_POSTGRES@db/windmill
|
||||||
|
- MODE=worker
|
||||||
|
- WORKER_GROUP=native
|
||||||
|
- NUM_WORKERS=8
|
||||||
|
- SLEEP_QUEUE=200
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- worker_logs:/tmp/windmill/logs
|
||||||
|
|
||||||
|
lsp:
|
||||||
|
image: ghcr.io/windmill-labs/windmill-lsp:latest
|
||||||
|
volumes:
|
||||||
|
- lsp_cache:/root/.cache
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"coolify": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.323"
|
"version": "4.0.0-beta.324"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user