Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions app/Actions/Server/InstallDocker.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public function handle(Server $server)
$command = $command->merge([$this->getSuseDockerInstallCommand()]);
} elseif ($supported_os_type->contains('arch')) {
$command = $command->merge([$this->getArchDockerInstallCommand()]);
} elseif ($supported_os_type->contains('alpine')) {
$command = $command->merge([$this->getAlpineDockerInstallCommand()]);
} else {
$command = $command->merge([$this->getGenericDockerInstallCommand()]);
}
Expand All @@ -94,8 +96,8 @@ public function handle(Server $server)
"jq -s '.[0] * .[1]' /etc/docker/daemon.json.coolify /etc/docker/daemon.json | tee /etc/docker/daemon.json.appended > /dev/null",
'mv /etc/docker/daemon.json.appended /etc/docker/daemon.json',
"echo 'Restarting Docker Engine...'",
'systemctl enable docker >/dev/null 2>&1 || true',
'systemctl restart docker',
'command -v systemctl >/dev/null 2>&1 && systemctl enable docker >/dev/null 2>&1 || command -v rc-update >/dev/null 2>&1 && rc-update add docker default >/dev/null 2>&1 || true',
'command -v systemctl >/dev/null 2>&1 && systemctl restart docker || command -v rc-service >/dev/null 2>&1 && rc-service docker restart || command -v service >/dev/null 2>&1 && service docker restart || true',
]);
if ($server->isSwarm()) {
$command = $command->merge([
Expand Down Expand Up @@ -159,6 +161,13 @@ private function getArchDockerInstallCommand(): string
'systemctl start docker.service';
}

private function getAlpineDockerInstallCommand(): string
{
return 'apk add --no-cache docker docker-cli-compose && '.
'command -v rc-update >/dev/null 2>&1 && rc-update add docker default >/dev/null 2>&1 || true && '.
'command -v rc-service >/dev/null 2>&1 && rc-service docker start || command -v service >/dev/null 2>&1 && service docker start || true';
}

private function getGenericDockerInstallCommand(): string
{
return "curl --max-time 300 --retry 3 https://releases.rancher.com/install-docker/{$this->dockerVersion}.sh | sh || curl --max-time 300 --retry 3 https://get.docker.com | sh -s -- --version {$this->dockerVersion}";
Expand Down
6 changes: 6 additions & 0 deletions app/Actions/Server/InstallPrerequisites.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ public function handle(Server $server)
"echo 'Installing Prerequisites for Arch Linux...'",
'pacman -Syu --noconfirm --needed curl wget git jq',
]);
} elseif ($supported_os_type->contains('alpine')) {
$command = $command->merge([
"echo 'Installing Prerequisites for Alpine Linux...'",
'apk update',
'apk add --no-cache curl wget git jq',
]);
} else {
throw new \Exception('Unsupported OS type for prerequisites installation');
}
Expand Down
35 changes: 23 additions & 12 deletions app/Models/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -1050,19 +1050,30 @@ public function validateOS(): bool|Stringable
$item = str($line)->trim();
$collectedData->put($item->before('=')->value(), $item->after('=')->lower()->replace('"', '')->value());
}
$ID = data_get($collectedData, 'ID');
// $ID_LIKE = data_get($collectedData, 'ID_LIKE');
// $VERSION_ID = data_get($collectedData, 'VERSION_ID');
$supported = collect(SUPPORTED_OS)->filter(function ($supportedOs) use ($ID) {
if (str($supportedOs)->contains($ID)) {
return str($ID);
}
return $this->resolveSupportedOsType($collectedData);
}

public function resolveSupportedOsType($osReleaseData): bool|Stringable
{
$ID = data_get($osReleaseData, 'ID');
$ID_LIKE = data_get($osReleaseData, 'ID_LIKE', '');

$detectedIds = collect([$ID])
->merge(str($ID_LIKE)->explode(' '))
->map(fn ($item) => str($item)->trim()->lower()->value())
->filter()
->unique();

$supported = collect(SUPPORTED_OS)->first(function ($supportedOs) use ($detectedIds) {
$supportedIds = str($supportedOs)
->explode(' ')
->map(fn ($item) => str($item)->trim()->lower()->value())
->filter();

return $detectedIds->intersect($supportedIds)->isNotEmpty();
});
if ($supported->count() === 1) {
return str($supported->first());
} else {
return false;
}

return $supported ? str($supported) : false;
}

public function isTerminalEnabled()
Expand Down
18 changes: 18 additions & 0 deletions tests/Unit/Actions/Server/InstallDockerAlpineCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

use App\Actions\Server\InstallDocker;

it('has alpine docker install command with openrc-friendly startup', function () {
$action = new InstallDocker;

$reflection = new ReflectionClass($action);
$method = $reflection->getMethod('getAlpineDockerInstallCommand');
$method->setAccessible(true);

$command = $method->invoke($action);

expect($command)->toBeString()
->and($command)->toContain('apk add --no-cache docker docker-cli-compose')
->and($command)->toContain('rc-update add docker default')
->and($command)->toContain('rc-service docker start');
});
63 changes: 63 additions & 0 deletions tests/Unit/ServerResolveSupportedOsTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

use App\Models\Server;

it('detects debian family by ID', function () {
$server = new Server;

$result = $server->resolveSupportedOsType(collect([
'ID' => 'debian',
'ID_LIKE' => '',
]));

expect($result)->not->toBeFalse()
->and((string) $result)->toContain('debian');
});

it('detects alpine by ID', function () {
$server = new Server;

$result = $server->resolveSupportedOsType(collect([
'ID' => 'alpine',
'ID_LIKE' => '',
]));

expect($result)->not->toBeFalse()
->and((string) $result)->toContain('alpine');
});

it('detects supported family using ID_LIKE fallback', function () {
$server = new Server;

$result = $server->resolveSupportedOsType(collect([
'ID' => 'linuxmint',
'ID_LIKE' => 'ubuntu debian',
]));

expect($result)->not->toBeFalse()
->and((string) $result)->toContain('ubuntu')
->and((string) $result)->toContain('debian');
});

it('returns false for unsupported os identifiers', function () {
$server = new Server;

$result = $server->resolveSupportedOsType(collect([
'ID' => 'freebsd',
'ID_LIKE' => '',
]));

expect($result)->toBeFalse();
});

it('normalizes mixed casing and extra spaces in os release identifiers', function () {
$server = new Server;

$result = $server->resolveSupportedOsType(collect([
'ID' => ' AlPiNe ',
'ID_LIKE' => ' MUSL busybox ',
]));

expect($result)->not->toBeFalse()
->and((string) $result)->toContain('alpine');
});