Refactor code
This commit is contained in:
6
backend/app/.env
Normal file
6
backend/app/.env
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
MAIN_DOMAIN=lxdapp.local
|
||||||
|
MAIN_COOKIE_DOMAIN=.lxdapp.local
|
||||||
|
LXD_API_URL=https://localhost:8443
|
||||||
|
LXD_CLIENT_CERT=/etc/ssl/lxdapp/client.crt
|
||||||
|
LXD_CLIENT_KEY=/etc/ssl/lxdapp/client.key
|
||||||
|
LXD_IMAGE_FINGERPRINT=2edfd84b1396
|
||||||
@ -35,9 +35,6 @@ backend/
|
|||||||
└── README.md
|
└── README.md
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚙️ Requirements
|
## ⚙️ Requirements
|
||||||
@ -46,9 +43,10 @@ backend/
|
|||||||
- LXD installed and configured
|
- LXD installed and configured
|
||||||
- PHP-FPM + NGINX
|
- PHP-FPM + NGINX
|
||||||
- Composer
|
- Composer
|
||||||
- `guzzlehttp/guzzle`
|
|
||||||
- `slim/slim`
|
- `slim/slim`
|
||||||
- `slim/psr7`
|
- `slim/psr7`
|
||||||
|
- `guzzlehttp/guzzle`
|
||||||
|
- `vlucas/phpdotenv`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -57,15 +55,15 @@ backend/
|
|||||||
1. **put the folder in /var/www/html**
|
1. **put the folder in /var/www/html**
|
||||||
|
|
||||||
2. **Install dependencies**
|
2. **Install dependencies**
|
||||||
|
```bash
|
||||||
composer install
|
composer install
|
||||||
|
|
||||||
|
|
||||||
3. **Ensure PHP and NGINX are configured**
|
3. **Ensure PHP and NGINX are configured**
|
||||||
|
|
||||||
NGINX config example:
|
NGINX config example:
|
||||||
|
```bash
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name *.lxdapp.local;
|
server_name *.lxdapp.local;
|
||||||
|
|
||||||
@ -83,15 +81,15 @@ server {
|
|||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
fastcgi_read_timeout 300;
|
fastcgi_read_timeout 300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
4. **Map domain in /etc/hosts**
|
4. **Map domain in /etc/hosts**
|
||||||
|
```bash
|
||||||
127.0.0.1 customer1.lxdapp.local
|
127.0.0.1 mitul.lxdapp.local
|
||||||
|
|
||||||
5. **Make sure LXD is working**
|
5. **Make sure LXD is working**
|
||||||
|
```bash
|
||||||
lxc list
|
lxc list
|
||||||
|
|
||||||
6. **🔐 CAPTCHA Protection**
|
6. **🔐 CAPTCHA Protection**
|
||||||
@ -106,7 +104,7 @@ server {
|
|||||||
POST /api/v1/proxy
|
POST /api/v1/proxy
|
||||||
|
|
||||||
**Request Body:**
|
**Request Body:**
|
||||||
|
```bash
|
||||||
{
|
{
|
||||||
"source": "login",
|
"source": "login",
|
||||||
"panswer": "abc123"
|
"panswer": "abc123"
|
||||||
@ -114,19 +112,16 @@ server {
|
|||||||
|
|
||||||
**Headers:**
|
**Headers:**
|
||||||
|
|
||||||
Origin: http://customer1.lxdapp.local
|
Origin: http://mitul.lxdapp.local
|
||||||
|
|
||||||
**Response:**
|
**Response:**
|
||||||
|
```bash
|
||||||
{
|
{
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"ip": "10.210.189.24"
|
"ip": "10.210.189.24"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**🧠 Notes**
|
**🧠 Notes**
|
||||||
|
|
||||||
Container names are auto-generated using the subdomain prefix.
|
Container names are auto-generated using the subdomain prefix.
|
||||||
@ -144,6 +139,7 @@ server {
|
|||||||
public/last-access-logs/container-*.txt
|
public/last-access-logs/container-*.txt
|
||||||
|
|
||||||
NGINX error logs (for debugging):
|
NGINX error logs (for debugging):
|
||||||
|
```bash
|
||||||
tail -f /var/log/nginx/error.log
|
tail -f /var/log/nginx/error.log
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
"slim/psr7": "^1.7",
|
"slim/psr7": "^1.7",
|
||||||
"php-di/php-di": "^7.0",
|
"php-di/php-di": "^7.0",
|
||||||
"guzzlehttp/guzzle": "^7.9",
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
"nyholm/psr7": "^1.8"
|
"nyholm/psr7": "^1.8",
|
||||||
|
"vlucas/phpdotenv": "^5.6"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
{
|
{
|
||||||
"customer1.lxdapp.local": "container-customer1"
|
|
||||||
}
|
}
|
||||||
@ -1,7 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
$domain = '.lxdapp.local'; // Leading dot is important for subdomain support
|
|
||||||
|
use DI\ContainerBuilder;
|
||||||
|
use Slim\Factory\AppFactory;
|
||||||
|
use Dotenv\Dotenv;
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
// 🔹 Load .env config
|
||||||
|
$dotenv = Dotenv::createImmutable(__DIR__ . '/../');
|
||||||
|
$dotenv->load();
|
||||||
|
|
||||||
|
$domain = $_ENV['MAIN_COOKIE_DOMAIN'] ?? '.lxdapp.local';
|
||||||
session_set_cookie_params([
|
session_set_cookie_params([
|
||||||
'lifetime' => 0,
|
'lifetime' => 0,
|
||||||
'path' => '/',
|
'path' => '/',
|
||||||
@ -14,13 +25,6 @@ session_set_cookie_params([
|
|||||||
if (session_status() === PHP_SESSION_NONE) {
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
session_start();
|
session_start();
|
||||||
}
|
}
|
||||||
use DI\ContainerBuilder;
|
|
||||||
use Slim\Factory\AppFactory;
|
|
||||||
|
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
|
||||||
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
ini_set('display_errors', '1');
|
|
||||||
|
|
||||||
// Build Container using PHP-DI
|
// Build Container using PHP-DI
|
||||||
$containerBuilder = new ContainerBuilder();
|
$containerBuilder = new ContainerBuilder();
|
||||||
@ -44,11 +48,11 @@ AppFactory::setContainer($container);
|
|||||||
// Create App
|
// Create App
|
||||||
$app = AppFactory::create();
|
$app = AppFactory::create();
|
||||||
|
|
||||||
|
// 🔹 CORS middleware
|
||||||
$app->add(function ($request, $handler) {
|
$app->add(function ($request, $handler) {
|
||||||
$response = $handler->handle($request);
|
$response = $handler->handle($request);
|
||||||
|
|
||||||
// $origin = $request->getHeaderLine('Origin') ?: '*';
|
|
||||||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '*';
|
$origin = $_SERVER['HTTP_ORIGIN'] ?? '*';
|
||||||
|
|
||||||
return $response
|
return $response
|
||||||
->withHeader('Access-Control-Allow-Origin', $origin)
|
->withHeader('Access-Control-Allow-Origin', $origin)
|
||||||
->withHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
|
->withHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
|
||||||
@ -56,7 +60,6 @@ $app->add(function ($request, $handler) {
|
|||||||
->withHeader('Access-Control-Allow-Credentials', 'true');
|
->withHeader('Access-Control-Allow-Credentials', 'true');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Register middleware
|
// Register middleware
|
||||||
(require __DIR__ . '/../src/Bootstrap/middleware.php')($app);
|
(require __DIR__ . '/../src/Bootstrap/middleware.php')($app);
|
||||||
|
|
||||||
|
|||||||
@ -7,3 +7,4 @@
|
|||||||
2025-07-08 15:12:49 : http://10.110.90.95:80
|
2025-07-08 15:12:49 : http://10.110.90.95:80
|
||||||
2025-07-08 15:23:59 : http://10.110.90.147:80
|
2025-07-08 15:23:59 : http://10.110.90.147:80
|
||||||
2025-07-08 15:24:26 : http://10.110.90.147:80
|
2025-07-08 15:24:26 : http://10.110.90.147:80
|
||||||
|
2025-07-09 06:15:42 : http://10.110.90.248:80
|
||||||
|
|||||||
@ -12,12 +12,15 @@ use App\lib\PCaptcha;
|
|||||||
|
|
||||||
class ProxyController
|
class ProxyController
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Handles forwarding requests to the appropriate container.
|
||||||
|
*/
|
||||||
public function forward(Request $request, Response $response): Response
|
public function forward(Request $request, Response $response): Response
|
||||||
{
|
{
|
||||||
$mainDomain = 'lxdapp.local';
|
$mainDomain = $_ENV['MAIN_DOMAIN'] ?? 'lxdapp.local';
|
||||||
|
|
||||||
$origin = $request->getHeaderLine('Origin');
|
$origin = $request->getHeaderLine('Origin');
|
||||||
$domain = parse_url($origin, PHP_URL_HOST); // e.g. customer1.lxdapp.local
|
$domain = parse_url($origin, PHP_URL_HOST); // e.g. mitul.lxdapp.local
|
||||||
$params = (array)$request->getParsedBody();
|
$params = (array)$request->getParsedBody();
|
||||||
|
|
||||||
$configPath = __DIR__ . '/../../config.json';
|
$configPath = __DIR__ . '/../../config.json';
|
||||||
@ -95,6 +98,9 @@ class ProxyController
|
|||||||
return $this->proxyToContainer($request, $response, $ip, $name);
|
return $this->proxyToContainer($request, $response, $ip, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a domain to a container name.
|
||||||
|
*/
|
||||||
private function mapDomainToContainer(string $domain): ?string
|
private function mapDomainToContainer(string $domain): ?string
|
||||||
{
|
{
|
||||||
$configPath = __DIR__ . '/../../config.json';
|
$configPath = __DIR__ . '/../../config.json';
|
||||||
@ -108,7 +114,9 @@ class ProxyController
|
|||||||
return $config[$domain] ?? null;
|
return $config[$domain] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a JSON response.
|
||||||
|
*/
|
||||||
protected function json($response, array $data, int $status = 200)
|
protected function json($response, array $data, int $status = 200)
|
||||||
{
|
{
|
||||||
$payload = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
$payload = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
@ -121,6 +129,9 @@ class ProxyController
|
|||||||
->withStatus($status);
|
->withStatus($status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a sanitized container name based on a subdomain.
|
||||||
|
*/
|
||||||
public function generateContainerName(string $subdomain): string
|
public function generateContainerName(string $subdomain): string
|
||||||
{
|
{
|
||||||
// Convert to lowercase, remove unsafe characters
|
// Convert to lowercase, remove unsafe characters
|
||||||
@ -130,6 +141,9 @@ class ProxyController
|
|||||||
return "container-{$sanitized}";
|
return "container-{$sanitized}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxies the request to the container.
|
||||||
|
*/
|
||||||
private function proxyToContainer(Request $request, Response $response, string $ip, string $name): Response
|
private function proxyToContainer(Request $request, Response $response, string $ip, string $name): Response
|
||||||
{
|
{
|
||||||
$target = $ip ? "http://$ip:80" : "http://127.0.0.1:3000";
|
$target = $ip ? "http://$ip:80" : "http://127.0.0.1:3000";
|
||||||
@ -153,6 +167,9 @@ class ProxyController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the last access to a container.
|
||||||
|
*/
|
||||||
protected function writeLastAccessLog(string $name, string $uri): void {
|
protected function writeLastAccessLog(string $name, string $uri): void {
|
||||||
// Dynamically resolve the log directory relative to the current file
|
// Dynamically resolve the log directory relative to the current file
|
||||||
$logDir = realpath(__DIR__ . '/../../public/last-access-logs');
|
$logDir = realpath(__DIR__ . '/../../public/last-access-logs');
|
||||||
|
|||||||
@ -6,29 +6,40 @@ use Exception;
|
|||||||
class LxdService
|
class LxdService
|
||||||
{
|
{
|
||||||
private string $baseUrl;
|
private string $baseUrl;
|
||||||
private string $socketPath;
|
private string $imageFingerprint;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
// $this->baseUrl = "http://unix.socket";
|
$this->baseUrl = $_ENV['LXD_API_URL'] ?? 'https://localhost:8443';
|
||||||
$this->baseUrl = "https://localhost:8443";
|
$this->imageFingerprint = $_ENV['LXD_IMAGE_FINGERPRINT'] ?? '2edfd84b1396';
|
||||||
$this->socketPath = "/var/snap/lxd/common/lxd/unix.socket";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an HTTP request to the LXD API.
|
||||||
|
*
|
||||||
|
* @param string $method HTTP method (GET, POST, PUT, etc.)
|
||||||
|
* @param string $endpoint API endpoint
|
||||||
|
* @param array $body Request body (optional)
|
||||||
|
* @return array Response from the API
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
private function request(string $method, string $endpoint, array $body = []): array {
|
private function request(string $method, string $endpoint, array $body = []): array {
|
||||||
|
|
||||||
|
if (!isset($_ENV['LXD_CLIENT_CERT'], $_ENV['LXD_CLIENT_KEY'])) {
|
||||||
|
throw new \Exception("LXD_CLIENT_CERT and LXD_CLIENT_KEY must be set in .env");
|
||||||
|
}
|
||||||
|
|
||||||
$ch = curl_init("{$this->baseUrl}{$endpoint}");
|
$ch = curl_init("{$this->baseUrl}{$endpoint}");
|
||||||
// Paths to your client cert and key
|
|
||||||
$clientCert = '/etc/ssl/lxdapp/client.crt';
|
|
||||||
$clientKey = '/etc/ssl/lxdapp/client.key';
|
|
||||||
|
|
||||||
//curl_setopt($ch, CURLOPT_UNIX_SOCKET_PATH, $this->socketPath);
|
// Paths to client certificate and key for TLS authentication
|
||||||
|
$clientCert = $_ENV['LXD_CLIENT_CERT'] ?? '/etc/ssl/lxdapp/client.crt';
|
||||||
|
$clientKey = $_ENV['LXD_CLIENT_KEY'] ?? '/etc/ssl/lxdapp/client.key';
|
||||||
|
|
||||||
|
|
||||||
// Specify your client certificate and key for TLS authentication
|
|
||||||
curl_setopt($ch, CURLOPT_SSLCERT, $clientCert);
|
curl_setopt($ch, CURLOPT_SSLCERT, $clientCert);
|
||||||
curl_setopt($ch, CURLOPT_SSLKEY, $clientKey);
|
curl_setopt($ch, CURLOPT_SSLKEY, $clientKey);
|
||||||
// For testing only: disable peer verification (use carefully in production!)
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
|
||||||
// curl_setopt($ch, CURLOPT_URL, "{$this->baseUrl}{$endpoint}");
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||||
|
|
||||||
@ -59,15 +70,12 @@ class LxdService
|
|||||||
return $json;
|
return $json;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getStatus(string $name): ?array
|
/**
|
||||||
{
|
* Retrieves a container.
|
||||||
try {
|
*
|
||||||
return $this->request('GET', "/1.0/instances/$name/state");
|
* @param string $name Container name
|
||||||
} catch (\Throwable $e) {
|
* @return array|null Container or null if an error occurs
|
||||||
return null;
|
*/
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContainer(string $name) {
|
public function getContainer(string $name) {
|
||||||
try {
|
try {
|
||||||
return $this->request('GET', "/1.0/instances/$name");
|
return $this->request('GET', "/1.0/instances/$name");
|
||||||
@ -76,6 +84,12 @@ class LxdService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the status of a container.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @return array|null Container status or null if an error occurs
|
||||||
|
*/
|
||||||
public function getContainerState(string $name) {
|
public function getContainerState(string $name) {
|
||||||
try {
|
try {
|
||||||
return $this->request('GET', "/1.0/instances/$name/state");
|
return $this->request('GET', "/1.0/instances/$name/state");
|
||||||
@ -84,10 +98,23 @@ class LxdService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a container exists.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @return bool True if the container exists, false otherwise
|
||||||
|
*/
|
||||||
public function containerExists(string $name): bool {
|
public function containerExists(string $name): bool {
|
||||||
return $this->getContainerState($name) !== null;
|
return $this->getContainerState($name) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a container.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @return array Response from the API
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public function startContainer(string $name): array {
|
public function startContainer(string $name): array {
|
||||||
$startResponse = $this->request('PUT', "/1.0/instances/$name/state", [
|
$startResponse = $this->request('PUT', "/1.0/instances/$name/state", [
|
||||||
"action" => "start",
|
"action" => "start",
|
||||||
@ -117,6 +144,12 @@ class LxdService
|
|||||||
return $containerResponse['metadata'] ?? [];
|
return $containerResponse['metadata'] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a container.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @return array Response from the API
|
||||||
|
*/
|
||||||
public function stopContainer(string $name): array {
|
public function stopContainer(string $name): array {
|
||||||
$response = $this->request('PUT', "/1.0/instances/$name/state", [
|
$response = $this->request('PUT', "/1.0/instances/$name/state", [
|
||||||
"action" => "stop",
|
"action" => "stop",
|
||||||
@ -127,18 +160,31 @@ class LxdService
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createContainer(string $name, string $fingerprint = "2edfd84b1396"): array {
|
/**
|
||||||
|
* Creates a new container.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @param string $fingerprint Image fingerprint
|
||||||
|
* @return array Response from the API
|
||||||
|
*/
|
||||||
|
public function createContainer(string $name): array {
|
||||||
$response = $this->request('POST', "/1.0/instances", [
|
$response = $this->request('POST', "/1.0/instances", [
|
||||||
"name" => $name,
|
"name" => $name,
|
||||||
"source" => [
|
"source" => [
|
||||||
"type" => "image",
|
"type" => "image",
|
||||||
"fingerprint" => $fingerprint
|
"fingerprint" => $this->imageFingerprint
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
sleep(5);
|
sleep(5);
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs packages inside a container.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public function installPackages(string $name) {
|
public function installPackages(string $name) {
|
||||||
$log = '';
|
$log = '';
|
||||||
|
|
||||||
@ -152,49 +198,44 @@ class LxdService
|
|||||||
|
|
||||||
file_put_contents('/tmp/lxd_install.log', $log);
|
file_put_contents('/tmp/lxd_install.log', $log);
|
||||||
|
|
||||||
// Wait for nginx service to be active
|
// Wait for services to start
|
||||||
$nginxActive = false;
|
$this->waitForService($name, 'nginx');
|
||||||
for ($i = 0; $i < 10; $i++) {
|
$this->waitForService($name, 'mysql');
|
||||||
$status = shell_exec("/snap/bin/lxc exec $name -- systemctl is-active nginx");
|
|
||||||
if (trim($status) === 'active') {
|
|
||||||
$nginxActive = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sleep(2); // wait 2 seconds before retry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for mysql service to be active
|
/**
|
||||||
$mysqlActive = false;
|
* Waits for a service to become active inside a container.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @param string $service Service name
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function waitForService(string $name, string $service)
|
||||||
|
{
|
||||||
for ($i = 0; $i < 10; $i++) {
|
for ($i = 0; $i < 10; $i++) {
|
||||||
$status = shell_exec("/snap/bin/lxc exec $name -- systemctl is-active mysql");
|
$status = shell_exec("/snap/bin/lxc exec $name -- systemctl is-active $service");
|
||||||
if (trim($status) === 'active') {
|
if (trim($status) === 'active') {
|
||||||
$mysqlActive = true;
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
sleep(2);
|
sleep(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$nginxActive || !$mysqlActive) {
|
throw new Exception("Failed to start $service inside container $name");
|
||||||
file_put_contents('/tmp/lxd_install.log', "Service(s) failed to start: nginx active=$nginxActive, mysql active=$mysqlActive\n", FILE_APPEND);
|
|
||||||
throw new \Exception("Failed to start nginx or mysql inside container $name");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function getContainerIP($name)
|
|
||||||
{
|
|
||||||
$container = $this->getStatus($name);
|
|
||||||
return $this->getIPv4FromMetadata($container['metadata']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new container and wait for start.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @param string $fingerprint Image fingerprint
|
||||||
|
* @return array Response from the API
|
||||||
|
*/
|
||||||
public function createContainerAndWait(string $name, array $config = []): array {
|
public function createContainerAndWait(string $name, array $config = []): array {
|
||||||
// 1. Prepare the creation request body
|
|
||||||
$body = [
|
$body = [
|
||||||
"name" => $name,
|
"name" => $name,
|
||||||
"source" => array_merge([
|
"source" => array_merge([
|
||||||
"type" => "image",
|
"type" => "image",
|
||||||
"fingerprint" => "2edfd84b1396"
|
"fingerprint" => $this->imageFingerprint
|
||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -225,7 +266,27 @@ class LxdService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function waitForPort(string $ip, int $port = 80, int $timeout = 30): bool
|
/**
|
||||||
|
* Retrieves the IPv4 address of a container.
|
||||||
|
*
|
||||||
|
* @param string $name Container name
|
||||||
|
* @return string|null IPv4 address or null if not found
|
||||||
|
*/
|
||||||
|
public function getContainerIP($name)
|
||||||
|
{
|
||||||
|
$container = $this->getContainerState($name);
|
||||||
|
return $this->getIPv4FromMetadata($container['metadata']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a specific port to become available.
|
||||||
|
*
|
||||||
|
* @param string $ip IP address
|
||||||
|
* @param int $port Port number
|
||||||
|
* @param int $timeout Timeout in seconds
|
||||||
|
* @return bool True if the port is available, false otherwise
|
||||||
|
*/
|
||||||
|
public function waitForPort(string $ip, int $port = 80, int $timeout = 10): bool
|
||||||
{
|
{
|
||||||
$startTime = time();
|
$startTime = time();
|
||||||
|
|
||||||
@ -244,7 +305,12 @@ class LxdService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Function to get IPv4 address from metadata
|
/**
|
||||||
|
* Extracts the IPv4 address from container metadata.
|
||||||
|
*
|
||||||
|
* @param array $metadata Container metadata
|
||||||
|
* @return string|null IPv4 address or null if not found
|
||||||
|
*/
|
||||||
public function getIPv4FromMetadata(array $metadata): ?string
|
public function getIPv4FromMetadata(array $metadata): ?string
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
|
|||||||
Reference in New Issue
Block a user