diff --git a/app/Actions/Server/StartLogDrain.php b/app/Actions/Server/StartLogDrain.php index 57068e0b52..6a73ae5df8 100644 --- a/app/Actions/Server/StartLogDrain.php +++ b/app/Actions/Server/StartLogDrain.php @@ -19,7 +19,7 @@ class StartLogDrain * Bump when the generated files change (image, config, compose, or README), so that the * server checks start running log drains again with the new files. */ - public const CONFIG_VERSION = '1'; + public const CONFIG_VERSION = '2'; public const CONFIG_VERSION_LABEL = 'coolify.logDrainConfigVersion'; @@ -56,6 +56,24 @@ class StartLogDrain return 'Amazon CloudWatch Logs uses the built-in Docker awslogs driver.'; } $serverName = $this->fluentBitValue((string) $server->name); + // Rename keeps a key that exists, so the container labels fill a field only when the + // Coolify default variables are not on the container. Then the labels are removed. + $coolifyFieldsFilter = "[FILTER] + Name modify + Match * + Set coolify.server_name {$serverName} + Rename COOLIFY_APP_NAME coolify.app_name + Rename COOLIFY_PROJECT_NAME coolify.project_name + Rename COOLIFY_SERVER_IP coolify.server_ip + Rename COOLIFY_ENVIRONMENT_NAME coolify.environment_name + Rename coolify.resourceName coolify.app_name + Rename coolify.projectName coolify.project_name + Rename coolify.environmentName coolify.environment_name + Rename coolify.serviceName coolify.service_name + Remove coolify.resourceName + Remove coolify.projectName + Remove coolify.environmentName +"; try { if ($type === 'none') { return 'No log drain is enabled.'; @@ -77,15 +95,7 @@ class StartLogDrain Name grep Match * Exclude log 127.0.0.1 -[FILTER] - Name modify - Match * - Set coolify.server_name {$serverName} - Rename COOLIFY_APP_NAME coolify.app_name - Rename COOLIFY_PROJECT_NAME coolify.project_name - Rename COOLIFY_SERVER_IP coolify.server_ip - Rename COOLIFY_ENVIRONMENT_NAME coolify.environment_name -[OUTPUT] +{$coolifyFieldsFilter}[OUTPUT] Name nrlogs Match * license_key \${LICENSE_KEY} @@ -111,15 +121,7 @@ class StartLogDrain Name grep Match * Exclude log 127.0.0.1 -[FILTER] - Name modify - Match * - Set coolify.server_name {$serverName} - Rename COOLIFY_APP_NAME coolify.app_name - Rename COOLIFY_PROJECT_NAME coolify.project_name - Rename COOLIFY_SERVER_IP coolify.server_ip - Rename COOLIFY_ENVIRONMENT_NAME coolify.environment_name -[OUTPUT] +{$coolifyFieldsFilter}[OUTPUT] Name http Match * Host \${AXIOM_DOMAIN} diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 98298709c2..5fba707049 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -4621,8 +4621,10 @@ function generate_fluentd_configuration(): array 'fluentd-address' => 'tcp://127.0.0.1:24224', 'fluentd-async' => 'true', 'fluentd-sub-second-precision' => 'true', - // env vars are used in the LogDrain configurations + // The env vars exist only when the resource includes the Coolify default variables. 'env' => 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME', + // Every Coolify container has these labels. Docker skips a label that a container does not have. + 'labels' => 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName', ], ]; } diff --git a/tests/Feature/LogDrain/LogDrainConfigRefreshTest.php b/tests/Feature/LogDrain/LogDrainConfigRefreshTest.php index eee7702ef8..ef09cdbb4b 100644 --- a/tests/Feature/LogDrain/LogDrainConfigRefreshTest.php +++ b/tests/Feature/LogDrain/LogDrainConfigRefreshTest.php @@ -175,5 +175,5 @@ it('changes the configuration version when the generated files change', function }); expect([StartLogDrain::CONFIG_VERSION, hash('sha256', $hashes->implode("\0"))]) - ->toBe(['1', '11916cd1142514c158a6fbe812ce468e3fe80fc79428cef6ba2654c86aa384ba']); + ->toBe(['2', '4f4ceaf642f0de8009e256b54f2bbe2f842190297bbf2da92f2b31dd0a9baf3d']); }); diff --git a/tests/Feature/LogDrain/LogDrainServerNameTest.php b/tests/Feature/LogDrain/LogDrainServerNameTest.php index 3b8fcf6c51..87168112a4 100644 --- a/tests/Feature/LogDrain/LogDrainServerNameTest.php +++ b/tests/Feature/LogDrain/LogDrainServerNameTest.php @@ -75,3 +75,30 @@ test('a server name with spaces is written as a single fluent-bit value', functi 'new relic' => [['is_logdrain_newrelic_enabled' => true, 'logdrain_newrelic_license_key' => 'key', 'logdrain_newrelic_base_uri' => 'https://log-api.newrelic.com/log/v1']], 'axiom' => [['is_logdrain_axiom_enabled' => true, 'logdrain_axiom_dataset_name' => 'dataset', 'logdrain_axiom_api_key' => 'key']], ]); + +test('the built-in fluent-bit config uses the container labels only when the default variables are missing', function (array $settings) { + $team = Team::factory()->create(); + $server = Server::factory()->create([ + 'team_id' => $team->id, + 'private_key_id' => PrivateKey::factory()->create(['team_id' => $team->id])->id, + ]); + $server->settings()->update($settings); + + $commands = new Collection; + Process::fake(function ($process) use ($commands) { + $commands->push(remoteProcessScript($process)); + + return Process::result(); + }); + + StartLogDrain::run($server->fresh()); + + preg_match("/echo '([A-Za-z0-9+\\/=]+)' \\| base64 -d \\| tee \\S+\\/fluent-bit\\.conf/", $commands->implode("\n"), $matches); + $config = base64_decode($matches[1]); + + expect($config)->toMatch('/Rename\s+COOLIFY_PROJECT_NAME coolify\.project_name\n(.*\n)*\s+Rename\s+coolify\.projectName coolify\.project_name\n(.*\n)*\s+Remove\s+coolify\.projectName\n/') + ->and($config)->toMatch('/Rename\s+coolify\.serviceName coolify\.service_name\n/'); +})->with([ + 'new relic' => [['is_logdrain_newrelic_enabled' => true, 'logdrain_newrelic_license_key' => 'key', 'logdrain_newrelic_base_uri' => 'https://log-api.newrelic.com/log/v1']], + 'axiom' => [['is_logdrain_axiom_enabled' => true, 'logdrain_axiom_dataset_name' => 'dataset', 'logdrain_axiom_api_key' => 'key']], +]); diff --git a/tests/Fixtures/parser/expected/application-with-settings.yaml b/tests/Fixtures/parser/expected/application-with-settings.yaml index b55728dd9b..63709e6f12 100644 --- a/tests/Fixtures/parser/expected/application-with-settings.yaml +++ b/tests/Fixtures/parser/expected/application-with-settings.yaml @@ -180,6 +180,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env image: 'referenceapplication0001_web:abcdef0123456789abcdef0123456789abcdef01' @@ -265,6 +266,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env my-app: @@ -336,6 +338,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env api.v2: @@ -390,6 +393,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env admin: @@ -462,6 +466,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env blog: @@ -537,6 +542,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env db: @@ -602,6 +608,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env sidecar: @@ -656,6 +663,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env worker: @@ -718,6 +726,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env volumes: @@ -949,6 +958,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env image: 'referenceapplication0001_web:abcdef0123456789abcdef0123456789abcdef01' @@ -1048,6 +1058,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env my-app: @@ -1128,6 +1139,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env api.v2: @@ -1203,6 +1215,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env admin: @@ -1284,6 +1297,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env blog: @@ -1366,6 +1380,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env db: @@ -1433,6 +1448,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env sidecar: @@ -1489,6 +1505,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env worker: @@ -1553,6 +1570,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env volumes: @@ -1812,6 +1830,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env image: 'referenceapplication0001_web:pr-7' @@ -1911,6 +1930,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env my-app-pr-7: @@ -1996,6 +2016,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env api.v2-pr-7: @@ -2076,6 +2097,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env admin-pr-7: @@ -2162,6 +2184,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env blog-pr-7: @@ -2248,6 +2271,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env db-pr-7: @@ -2317,6 +2341,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env sidecar-pr-7: @@ -2373,6 +2398,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env worker-pr-7: @@ -2439,6 +2465,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env volumes: @@ -2658,6 +2685,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env image: 'referenceapplication0001_web:pr-8' @@ -2719,6 +2747,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env my-app-pr-8: @@ -2766,6 +2795,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env api.v2-pr-8: @@ -2812,6 +2842,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env admin-pr-8: @@ -2860,6 +2891,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env blog-pr-8: @@ -2907,6 +2939,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env db-pr-8: @@ -2964,6 +2997,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env sidecar-pr-8: @@ -3008,6 +3042,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env worker-pr-8: @@ -3062,6 +3097,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' env_file: - .env volumes: diff --git a/tests/Fixtures/parser/expected/reference-with-application-settings.yaml b/tests/Fixtures/parser/expected/reference-with-application-settings.yaml index e91538c13d..cc0a7a0afb 100644 --- a/tests/Fixtures/parser/expected/reference-with-application-settings.yaml +++ b/tests/Fixtures/parser/expected/reference-with-application-settings.yaml @@ -270,6 +270,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' api: image: 'node:22-alpine' build: @@ -1149,6 +1150,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' api: image: 'node:22-alpine' build: @@ -2071,6 +2073,7 @@ fluentd-async: 'true' fluentd-sub-second-precision: 'true' env: 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME' + labels: 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName' api: image: 'node:22-alpine' build: diff --git a/tests/Unit/GenerateLogDrainConfigurationTest.php b/tests/Unit/GenerateLogDrainConfigurationTest.php index 0ac5eb05b2..4dd432adf4 100644 --- a/tests/Unit/GenerateLogDrainConfigurationTest.php +++ b/tests/Unit/GenerateLogDrainConfigurationTest.php @@ -75,3 +75,11 @@ it('reports CloudWatch as an enabled drain that does not use Fluent Bit', functi ->and($axiom->isLogDrainEnabled())->toBeTrue() ->and($axiom->isFluentBitLogDrainEnabled())->toBeTrue(); }); + +it('sends the Coolify labels with fluentd, so containers without the default variables are identified', function () { + $server = serverWithLogDrainSettings(['is_logdrain_custom_enabled' => true]); + + expect(generate_log_drain_configuration($server)['options']) + ->toHaveKey('env', 'COOLIFY_APP_NAME,COOLIFY_PROJECT_NAME,COOLIFY_SERVER_IP,COOLIFY_ENVIRONMENT_NAME') + ->toHaveKey('labels', 'coolify.projectName,coolify.environmentName,coolify.resourceName,coolify.serviceName'); +});