Deploy Ladill Hosting / deploy (push) Failing after 17s
Shared web hosting extracted from the platform monolith, with CI deploy to /var/www/ladill-hosting matching Bird/Domains/Email. Co-authored-by: Cursor <cursoragent@cursor.com>
230 lines
7.2 KiB
PHP
230 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Hosting;
|
|
|
|
use App\Models\CustomerHostingOrder;
|
|
use App\Services\Hosting\Providers\ContaboProvider;
|
|
|
|
class ServerAgentInstallerService
|
|
{
|
|
public function __construct(
|
|
private ContaboProvider $contaboProvider,
|
|
private ServerAgentReleaseService $releaseService,
|
|
) {}
|
|
|
|
public function augmentProvisioningConfig(CustomerHostingOrder $order, array $provisioning, array $bootstrap): array
|
|
{
|
|
if (! (bool) ($provisioning['panel_snapshot']['managed_stack_candidate'] ?? false)) {
|
|
return $provisioning;
|
|
}
|
|
|
|
$provisioning['user_data'] = $this->buildCloudInit(
|
|
$order,
|
|
$bootstrap,
|
|
(string) ($provisioning['user_data'] ?? '')
|
|
);
|
|
|
|
return $provisioning;
|
|
}
|
|
|
|
public function buildCloudInit(CustomerHostingOrder $order, array $bootstrap, string $existingCloudInit = ''): string
|
|
{
|
|
$parsed = $this->parseGeneratedCloudInit($existingCloudInit);
|
|
$release = $this->releaseService->ensureRelease();
|
|
$releaseUrl = $this->releaseService->temporaryDownloadUrl($release['version']);
|
|
$envFile = implode("\n", [
|
|
'ORDER_ID='.$order->id,
|
|
'BOOTSTRAP_TOKEN='.$bootstrap['bootstrap_token'],
|
|
'REGISTRATION_URL='.$bootstrap['registration_url'],
|
|
'HEARTBEAT_URL='.$bootstrap['heartbeat_url'],
|
|
'AGENT_RELEASE_VERSION='.$release['version'],
|
|
'',
|
|
]);
|
|
|
|
$packages = array_values(array_unique(array_merge($parsed['packages'], [
|
|
'curl',
|
|
'wget',
|
|
'jq',
|
|
'ca-certificates',
|
|
'git',
|
|
'unzip',
|
|
'zip',
|
|
])));
|
|
|
|
$runCommands = array_merge([
|
|
$this->managedStackInstallCommand($releaseUrl, $release['checksum_sha256']),
|
|
'bash -lc \'mkdir -p /etc/ladill /var/lib/ladill-server-agent /var/www /tmp/ladill-server-agent-release\'',
|
|
'bash -lc \'cd /tmp/ladill-server-agent-release && bash install.sh\'',
|
|
'bash -lc \'chmod 0600 /etc/ladill/server-agent.env\'',
|
|
$this->managedStackEnableServicesCommand(),
|
|
], $parsed['run_commands']);
|
|
|
|
return $this->contaboProvider->generateCloudInit([
|
|
'packages' => $packages,
|
|
'write_files' => [
|
|
[
|
|
'path' => '/etc/ladill/server-agent.env',
|
|
'permissions' => '0600',
|
|
'owner' => 'root:root',
|
|
'encoding' => 'b64',
|
|
'content' => base64_encode($envFile),
|
|
],
|
|
],
|
|
'run_commands' => $runCommands,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return array{packages: array<int, string>, run_commands: array<int, string>}
|
|
*/
|
|
private function parseGeneratedCloudInit(string $cloudInit): array
|
|
{
|
|
$packages = [];
|
|
$runCommands = [];
|
|
$section = null;
|
|
|
|
foreach (preg_split("/\r\n|\n|\r/", $cloudInit) ?: [] as $line) {
|
|
$trimmed = trim($line);
|
|
|
|
if ($trimmed === '' || $trimmed === '#cloud-config') {
|
|
continue;
|
|
}
|
|
|
|
if (! str_starts_with($line, ' ')) {
|
|
$section = match ($trimmed) {
|
|
'packages:' => 'packages',
|
|
'runcmd:' => 'runcmd',
|
|
default => null,
|
|
};
|
|
continue;
|
|
}
|
|
|
|
if ($section === 'packages' && str_starts_with($trimmed, '- ')) {
|
|
$packages[] = trim(substr($trimmed, 2));
|
|
}
|
|
|
|
if ($section === 'runcmd' && str_starts_with($trimmed, '- ')) {
|
|
$runCommands[] = trim(substr($trimmed, 2));
|
|
}
|
|
}
|
|
|
|
return [
|
|
'packages' => array_values(array_filter($packages)),
|
|
'run_commands' => array_values(array_filter($runCommands)),
|
|
];
|
|
}
|
|
|
|
private function managedStackInstallCommand(string $releaseUrl, string $checksum): string
|
|
{
|
|
$script = str_replace(
|
|
['__RELEASE_URL__', '__CHECKSUM__'],
|
|
[$releaseUrl, $checksum],
|
|
<<<'BASH'
|
|
set -e
|
|
|
|
detect_pm() {
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
echo apt-get
|
|
return 0
|
|
fi
|
|
|
|
if command -v dnf >/dev/null 2>&1; then
|
|
echo dnf
|
|
return 0
|
|
fi
|
|
|
|
if command -v yum >/dev/null 2>&1; then
|
|
echo yum
|
|
return 0
|
|
fi
|
|
|
|
if command -v zypper >/dev/null 2>&1; then
|
|
echo zypper
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
install_composer_if_missing() {
|
|
if command -v composer >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
curl -fsSL https://getcomposer.org/installer -o /tmp/composer-setup.php
|
|
php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer
|
|
rm -f /tmp/composer-setup.php
|
|
}
|
|
|
|
pm="$(detect_pm || true)"
|
|
if [ -z "${pm}" ]; then
|
|
echo "Ladill managed stack currently supports apt, dnf, yum, or zypper based Linux distributions only." >&2
|
|
exit 1
|
|
fi
|
|
|
|
case "${pm}" in
|
|
apt-get)
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update
|
|
apt-get install -y nginx mariadb-server php-fpm php-cli php-mysql php-curl php-xml php-zip php-mbstring php-gd php-intl php-bcmath certbot jq curl wget ca-certificates cron composer git unzip zip bubblewrap
|
|
;;
|
|
dnf)
|
|
dnf install -y epel-release || true
|
|
dnf install -y nginx mariadb-server php-fpm php-cli php-mysqlnd certbot jq curl wget ca-certificates cronie git unzip zip bubblewrap
|
|
dnf install -y php-curl php-xml php-zip php-mbstring php-gd php-intl php-bcmath || true
|
|
;;
|
|
yum)
|
|
yum install -y epel-release || true
|
|
yum install -y nginx mariadb-server php-fpm php-cli php-mysqlnd certbot jq curl wget ca-certificates cronie git unzip zip bubblewrap
|
|
yum install -y php-curl php-xml php-zip php-mbstring php-gd php-intl php-bcmath || true
|
|
;;
|
|
zypper)
|
|
zypper --non-interactive refresh
|
|
zypper --non-interactive install -y nginx mariadb php8 php8-fpm php8-mysql certbot jq curl wget ca-certificates cron git unzip zip bubblewrap
|
|
zypper --non-interactive install -y php8-curl php8-xmlreader php8-xmlwriter php8-zip php8-mbstring php8-gd php8-intl php8-bcmath || true
|
|
;;
|
|
esac
|
|
|
|
install_composer_if_missing
|
|
mkdir -p /etc/ladill /var/lib/ladill-server-agent /var/www /tmp/ladill-server-agent-release
|
|
curl -fsSL "__RELEASE_URL__" -o /tmp/ladill-server-agent-release/agent.tar.gz
|
|
echo "__CHECKSUM__ /tmp/ladill-server-agent-release/agent.tar.gz" | sha256sum -c -
|
|
tar -xzf /tmp/ladill-server-agent-release/agent.tar.gz -C /tmp/ladill-server-agent-release
|
|
BASH
|
|
);
|
|
|
|
return 'bash -lc '.escapeshellarg($script);
|
|
}
|
|
|
|
private function managedStackEnableServicesCommand(): string
|
|
{
|
|
return 'bash -lc '.escapeshellarg(<<<'BASH'
|
|
set -e
|
|
|
|
service_exists() {
|
|
systemctl list-unit-files "$1.service" --no-legend 2>/dev/null | grep -q "^$1\.service"
|
|
}
|
|
|
|
enable_if_present() {
|
|
for service in "$@"; do
|
|
if [ -n "$service" ] && service_exists "$service"; then
|
|
systemctl enable --now "$service" >/dev/null 2>&1 || true
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
chmod 0600 /etc/ladill/server-agent.env
|
|
systemctl daemon-reload
|
|
enable_if_present nginx
|
|
enable_if_present mariadb mysql
|
|
enable_if_present cron crond
|
|
enable_if_present php-fpm php8-fpm php8.4-fpm php8.3-fpm php8.2-fpm php8.1-fpm php8.0-fpm
|
|
enable_if_present ladill-server-agent
|
|
BASH
|
|
);
|
|
}
|
|
}
|