Skip to content

Commit 58f6f9e

Browse files
authored
feat(dev): add Lima testing server fixtures (#10844)
1 parent bf37db3 commit 58f6f9e

14 files changed

Lines changed: 600 additions & 38 deletions

CONTRIBUTING.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,13 @@ A: Yes, but keep in mind a PR closure is feedback, not a rejection of your effor
219219
## Local Development
220220
To build and run Coolify locally, see: [Development](./DEVELOPMENT.md)
221221

222+
### macOS Development with Lima
223+
Mac users can use [Lima](https://lima-vm.io/) to run a lightweight Linux virtual machine for local Coolify development. This is useful if you prefer a Linux-based Docker environment on macOS.
224+
225+
After creating and starting a Lima VM, run the normal local development commands from inside the VM as described in [Development](./DEVELOPMENT.md).
226+
222227
## Adding a New Service
223228
To add a new one-click service, follow: https://coolify.io/docs/get-started/contribute/service
224229

225230
## Contributing to Documentation
226-
To contribute to documentation, see: https://coolify.io/docs/get-started/contribute/documentation
231+
To contribute to documentation, see: https://coolify.io/docs/get-started/contribute/documentation

app/Livewire/Server/Show.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,20 @@ public function loadHetznerTokens(): void
537537
->get();
538538
}
539539

540+
#[Computed]
541+
public function limaStartCommand(): ?string
542+
{
543+
if (! isDev()) {
544+
return null;
545+
}
546+
547+
return match ($this->server->uuid) {
548+
'lima-ubuntu-2404' => 'limactl start --yes --name=coolify-lima-ubuntu-2404 docker/lima/ubuntu-2404.yaml',
549+
'lima-ubuntu-2604' => 'limactl start --yes --name=coolify-lima-ubuntu-2604 docker/lima/ubuntu-2604.yaml',
550+
default => null,
551+
};
552+
}
553+
540554
public function searchHetznerServer(): void
541555
{
542556
$this->hetznerSearchError = null;

database/seeders/DevelopmentRailpackExamplesSeeder.php

Lines changed: 152 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,33 @@ class DevelopmentRailpackExamplesSeeder extends Seeder
2020
{
2121
public const PROJECT_UUID = 'railpack-examples';
2222

23-
public const ENVIRONMENT_UUID = 'railpack-examples-production';
24-
2523
public const GIT_REPOSITORY = 'coollabsio/coolify-examples';
2624

2725
public const GIT_BRANCH = 'next';
2826

2927
public const REPOSITORY_PROJECT_ID = 603035348;
3028

29+
public const LIMA_SERVERS = [
30+
[
31+
'server_uuid' => 'lima-ubuntu-2404',
32+
'server_name' => 'lima-ubuntu-2404',
33+
'port' => 2222,
34+
'environment_name' => 'ubuntu24',
35+
'environment_uuid' => 'railpack-examples-ubuntu24',
36+
'uuid_prefix' => 'ubuntu24-',
37+
],
38+
[
39+
'server_uuid' => 'lima-ubuntu-2604',
40+
'server_name' => 'lima-ubuntu-2604',
41+
'port' => 2223,
42+
'environment_name' => 'ubuntu26',
43+
'environment_uuid' => 'railpack-examples-ubuntu26',
44+
'uuid_prefix' => 'ubuntu26-',
45+
],
46+
];
47+
48+
private const LIMA_SENTINEL_URL = 'http://host.lima.internal:8000';
49+
3150
public function run(): void
3251
{
3352
if (! $this->isDevelopmentEnvironment()) {
@@ -37,16 +56,22 @@ public function run(): void
3756
}
3857

3958
$this->ensureDevelopmentPrerequisitesExist();
40-
$destination = StandaloneDocker::query()->find(0);
4159

42-
if (! $destination) {
60+
if (! StandaloneDocker::query()->find(0)) {
4361
throw new RuntimeException('StandaloneDocker with id=0 is required before running DevelopmentRailpackExamplesSeeder.');
4462
}
4563

46-
$environment = $this->prepareEnvironment();
64+
$this->cleanupLegacyLimaProjects();
65+
$this->cleanupLegacyProductionExamples();
4766

48-
foreach (self::examples() as $example) {
49-
$this->upsertApplication($environment, $destination, $example);
67+
foreach (self::LIMA_SERVERS as $limaServer) {
68+
$this->seedEnvironment(
69+
environmentUuid: $limaServer['environment_uuid'],
70+
environmentName: $limaServer['environment_name'],
71+
destination: $this->limaDestination($limaServer['server_uuid']),
72+
uuidPrefix: $limaServer['uuid_prefix'],
73+
nameSuffix: " ({$limaServer['environment_name']})",
74+
);
5075
}
5176
}
5277

@@ -440,6 +465,37 @@ private function ensureDevelopmentPrerequisitesExist(): void
440465
],
441466
);
442467

468+
foreach (self::LIMA_SERVERS as $limaServer) {
469+
$server = Server::query()->firstOrCreate(
470+
['uuid' => $limaServer['server_uuid']],
471+
[
472+
'name' => $limaServer['server_name'],
473+
'description' => 'This is a Lima VM for local development testing',
474+
'ip' => 'host.docker.internal',
475+
'port' => $limaServer['port'],
476+
'team_id' => 0,
477+
'private_key_id' => 1,
478+
'proxy' => [
479+
'type' => ProxyTypes::TRAEFIK->value,
480+
'status' => ProxyStatus::EXITED->value,
481+
],
482+
],
483+
);
484+
485+
$server->settings->forceFill([
486+
'sentinel_custom_url' => self::LIMA_SENTINEL_URL,
487+
])->saveQuietly();
488+
489+
StandaloneDocker::query()->firstOrCreate(
490+
['server_id' => $server->id],
491+
[
492+
'uuid' => "{$limaServer['server_uuid']}-docker",
493+
'name' => "{$limaServer['server_name']} Docker",
494+
'network' => 'coolify',
495+
],
496+
);
497+
}
498+
443499
StandaloneDocker::query()->firstOrCreate(
444500
['id' => 0],
445501
[
@@ -489,7 +545,71 @@ private function isDevelopmentEnvironment(): bool
489545
return in_array(config('app.env'), ['local', 'development', 'dev'], true);
490546
}
491547

492-
private function prepareEnvironment(): Environment
548+
private function limaDestination(string $serverUuid): StandaloneDocker
549+
{
550+
$limaDestination = Server::query()
551+
->where('uuid', $serverUuid)
552+
->first()
553+
?->standaloneDockers()
554+
->first();
555+
556+
if (! $limaDestination) {
557+
throw new RuntimeException("Lima StandaloneDocker destination is required for {$serverUuid} before running DevelopmentRailpackExamplesSeeder.");
558+
}
559+
560+
return $limaDestination;
561+
}
562+
563+
private function cleanupLegacyLimaProjects(): void
564+
{
565+
Project::query()
566+
->whereIn('uuid', [
567+
'railpack-examples-lima-ubuntu-2404',
568+
'railpack-examples-lima-ubuntu-2604',
569+
])
570+
->get()
571+
->each(function (Project $project): void {
572+
Application::withTrashed()
573+
->whereIn('environment_id', $project->environments()->pluck('id'))
574+
->get()
575+
->each
576+
->forceDelete();
577+
578+
$project->delete();
579+
});
580+
}
581+
582+
private function cleanupLegacyProductionExamples(): void
583+
{
584+
$project = Project::query()->where('uuid', self::PROJECT_UUID)->first();
585+
586+
if (! $project) {
587+
return;
588+
}
589+
590+
Application::withTrashed()
591+
->whereIn('environment_id', $project->environments()->pluck('id'))
592+
->whereIn('uuid', collect(self::examples())->pluck('uuid'))
593+
->get()
594+
->each
595+
->forceDelete();
596+
}
597+
598+
private function seedEnvironment(
599+
string $environmentUuid,
600+
string $environmentName,
601+
StandaloneDocker $destination,
602+
string $uuidPrefix = '',
603+
string $nameSuffix = '',
604+
): void {
605+
$environment = $this->prepareEnvironment($environmentUuid, $environmentName);
606+
607+
foreach (self::examples() as $example) {
608+
$this->upsertApplication($environment, $destination, $example, $uuidPrefix, $nameSuffix);
609+
}
610+
}
611+
612+
private function prepareEnvironment(string $environmentUuid, string $environmentName): Environment
493613
{
494614
$project = Project::query()->firstOrNew(['uuid' => self::PROJECT_UUID]);
495615
$project->fill([
@@ -499,17 +619,29 @@ private function prepareEnvironment(): Environment
499619
]);
500620
$project->save();
501621

502-
$environment = $project->environments()->first();
622+
$environment = $project->environments()
623+
->where(function ($query) use ($environmentName, $environmentUuid): void {
624+
$query
625+
->where('name', $environmentName)
626+
->orWhere('uuid', $environmentUuid);
627+
})
628+
->first();
629+
630+
$existingEnvironment = $project->environments()->first();
631+
632+
if (! $environment && $project->environments()->count() === 1 && $existingEnvironment?->name === 'production') {
633+
$environment = $existingEnvironment;
634+
}
503635

504636
if (! $environment) {
505637
$environment = $project->environments()->create([
506-
'name' => 'production',
507-
'uuid' => self::ENVIRONMENT_UUID,
638+
'name' => $environmentName,
639+
'uuid' => $environmentUuid,
508640
]);
509641
} else {
510642
$environment->update([
511-
'name' => 'production',
512-
'uuid' => self::ENVIRONMENT_UUID,
643+
'name' => $environmentName,
644+
'uuid' => $environmentUuid,
513645
]);
514646
}
515647

@@ -519,13 +651,15 @@ private function prepareEnvironment(): Environment
519651
/**
520652
* @param array<string, mixed> $example
521653
*/
522-
private function upsertApplication(Environment $environment, StandaloneDocker $destination, array $example): void
654+
private function upsertApplication(Environment $environment, StandaloneDocker $destination, array $example, string $uuidPrefix = '', string $nameSuffix = ''): void
523655
{
524-
$application = Application::withTrashed()->firstOrNew(['uuid' => $example['uuid']]);
656+
$uuid = $uuidPrefix.$example['uuid'];
657+
$name = $example['name'].$nameSuffix;
658+
$application = Application::withTrashed()->firstOrNew(['uuid' => $uuid]);
525659
$application->fill([
526-
'name' => $example['name'],
527-
'description' => $example['name'],
528-
'fqdn' => "http://{$example['uuid']}.127.0.0.1.sslip.io",
660+
'name' => $name,
661+
'description' => $name,
662+
'fqdn' => "http://{$uuid}.127.0.0.1.sslip.io",
529663
'repository_project_id' => $example['repository_project_id'] ?? self::REPOSITORY_PROJECT_ID,
530664
'git_repository' => $example['git_repository'] ?? self::GIT_REPOSITORY,
531665
'git_branch' => $example['git_branch'] ?? self::GIT_BRANCH,

database/seeders/ProjectSeeder.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77

88
class ProjectSeeder extends Seeder
99
{
10+
private const LIMA_ENVIRONMENTS = [
11+
['name' => 'ubuntu24', 'uuid' => 'ubuntu24'],
12+
['name' => 'ubuntu26', 'uuid' => 'ubuntu26'],
13+
];
14+
1015
public function run(): void
1116
{
1217
$project = Project::create([
@@ -16,7 +21,14 @@ public function run(): void
1621
'team_id' => 0,
1722
]);
1823

19-
// Update the auto-created environment with a deterministic UUID
20-
$project->environments()->first()->update(['uuid' => 'production']);
24+
foreach (self::LIMA_ENVIRONMENTS as $index => $environment) {
25+
if ($index === 0) {
26+
$project->environments()->first()->update($environment);
27+
28+
continue;
29+
}
30+
31+
$project->environments()->create($environment);
32+
}
2133
}
2234
}

database/seeders/ServerSeeder.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99

1010
class ServerSeeder extends Seeder
1111
{
12+
private const LIMA_SENTINEL_URL = 'http://host.lima.internal:8000';
13+
14+
private const LIMA_SERVERS = [
15+
['uuid' => 'lima-ubuntu-2404', 'name' => 'lima-ubuntu-2404', 'port' => 2222],
16+
['uuid' => 'lima-ubuntu-2604', 'name' => 'lima-ubuntu-2604', 'port' => 2223],
17+
];
18+
1219
public function run(): void
1320
{
1421
Server::create([
@@ -24,5 +31,25 @@ public function run(): void
2431
'status' => ProxyStatus::EXITED->value,
2532
],
2633
]);
34+
35+
foreach (self::LIMA_SERVERS as $limaServer) {
36+
$server = Server::create([
37+
'uuid' => $limaServer['uuid'],
38+
'name' => $limaServer['name'],
39+
'description' => 'This is a Lima VM for local development testing',
40+
'ip' => 'host.docker.internal',
41+
'port' => $limaServer['port'],
42+
'team_id' => 0,
43+
'private_key_id' => 1,
44+
'proxy' => [
45+
'type' => ProxyTypes::TRAEFIK->value,
46+
'status' => ProxyStatus::EXITED->value,
47+
],
48+
]);
49+
50+
$server->settings->forceFill([
51+
'sentinel_custom_url' => self::LIMA_SENTINEL_URL,
52+
])->saveQuietly();
53+
}
2754
}
2855
}

docker-compose-maxio.dev.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ services:
1010
- GROUP_ID=${GROUPID:-1000}
1111
ports:
1212
- "${APP_PORT:-8000}:8080"
13+
extra_hosts:
14+
- "host.docker.internal:host-gateway"
1315
environment:
1416
AUTORUN_ENABLED: false
1517
PUSHER_HOST: "${PUSHER_HOST}"
@@ -70,6 +72,8 @@ services:
7072
ports:
7173
- "${FORWARD_SOKETI_PORT:-6001}:6001"
7274
- "6002:6002"
75+
extra_hosts:
76+
- "host.docker.internal:host-gateway"
7377
volumes:
7478
- ./storage:/var/www/html/storage
7579
- ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js

docker-compose.dev.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ services:
1010
- GROUP_ID=${GROUPID:-1000}
1111
ports:
1212
- "${APP_PORT:-8000}:8080"
13+
extra_hosts:
14+
- "host.docker.internal:host-gateway"
1315
environment:
1416
AUTORUN_ENABLED: false
1517
PUSHER_HOST: "${PUSHER_HOST}"
@@ -70,6 +72,8 @@ services:
7072
ports:
7173
- "${FORWARD_SOKETI_PORT:-6001}:6001"
7274
- "6002:6002"
75+
extra_hosts:
76+
- "host.docker.internal:host-gateway"
7377
volumes:
7478
- ./storage:/var/www/html/storage
7579
- ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js

0 commit comments

Comments
 (0)