Initial Ladill Hosting app with Gitea deploy pipeline.
Deploy Ladill Hosting / deploy (push) Failing after 17s
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>
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
<?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
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user