768 lines
25 KiB
PHP
768 lines
25 KiB
PHP
<?php
|
|
/**
|
|
* Enrollment Manager for Ziti Router
|
|
* Replicates the functionality of the bash script
|
|
*/
|
|
|
|
require_once 'config.php';
|
|
require_once 'api_client.php';
|
|
|
|
class EnrollmentManager {
|
|
private $apiClient;
|
|
private $routerData;
|
|
private $progressCallback;
|
|
|
|
public function __construct($apiEndpoint = DEFAULT_API_ENDPOINT) {
|
|
$this->apiClient = new ApiClient($apiEndpoint);
|
|
$this->routerData = [];
|
|
}
|
|
|
|
/**
|
|
* Set progress callback function
|
|
*/
|
|
public function setProgressCallback($callback) {
|
|
$this->progressCallback = $callback;
|
|
}
|
|
|
|
/**
|
|
* Report progress
|
|
*/
|
|
private function reportProgress($step, $message, $percentage = null) {
|
|
logMessage('INFO', "[$step] $message");
|
|
|
|
// Store progress in session for AJAX polling
|
|
$this->updateSessionProgress($step, $message, $percentage);
|
|
|
|
if ($this->progressCallback && is_callable($this->progressCallback)) {
|
|
call_user_func($this->progressCallback, $step, $message, $percentage);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update session progress for AJAX polling
|
|
*/
|
|
private function updateSessionProgress($step, $message, $percentage = null) {
|
|
$steps = [
|
|
'INIT' => 0, 'REQUIREMENTS' => 1, 'INSTALL' => 2, 'DIRECTORIES' => 3,
|
|
'REGISTER' => 4, 'CONFIG' => 5, 'ENROLL' => 6, 'SERVICE' => 7,
|
|
'START' => 8, 'REPORT' => 9, 'COMPLETE' => 10, 'ERROR' => -1
|
|
];
|
|
|
|
$currentStepIndex = $steps[$step] ?? 0;
|
|
|
|
// Initialize progress if not exists
|
|
if (!isset($_SESSION['enrollment_progress'])) {
|
|
$_SESSION['enrollment_progress'] = [
|
|
'step' => 'INIT',
|
|
'message' => 'Ready to start enrollment',
|
|
'percentage' => 0,
|
|
'completed_steps' => [],
|
|
'current_step_index' => 0,
|
|
'status' => 'ready',
|
|
'error' => null,
|
|
'logs' => []
|
|
];
|
|
}
|
|
|
|
$progress = &$_SESSION['enrollment_progress'];
|
|
|
|
// Update progress data
|
|
$progress['step'] = $step;
|
|
$progress['message'] = $message;
|
|
$progress['current_step_index'] = $currentStepIndex;
|
|
|
|
if ($percentage !== null) {
|
|
$progress['percentage'] = $percentage;
|
|
}
|
|
|
|
// Update status
|
|
if ($step === 'ERROR') {
|
|
$progress['status'] = 'error';
|
|
$progress['error'] = $message;
|
|
} elseif ($step === 'COMPLETE') {
|
|
$progress['status'] = 'completed';
|
|
$progress['percentage'] = 100;
|
|
} else {
|
|
$progress['status'] = 'running';
|
|
}
|
|
|
|
// Add completed steps
|
|
if ($currentStepIndex > 0 && $step !== 'ERROR') {
|
|
$stepNames = array_keys($steps);
|
|
for ($i = 0; $i < $currentStepIndex; $i++) {
|
|
if (!in_array($stepNames[$i], $progress['completed_steps'])) {
|
|
$progress['completed_steps'][] = $stepNames[$i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add log entry
|
|
$timestamp = date('H:i:s');
|
|
$progress['logs'][] = [
|
|
'timestamp' => $timestamp,
|
|
'step' => $step,
|
|
'message' => $message,
|
|
'type' => $step === 'ERROR' ? 'error' : 'info'
|
|
];
|
|
|
|
// Keep only last 50 log entries
|
|
if (count($progress['logs']) > 50) {
|
|
$progress['logs'] = array_slice($progress['logs'], -50);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize progress tracking
|
|
*/
|
|
private function initializeProgress() {
|
|
$_SESSION['enrollment_progress'] = [
|
|
'step' => 'INIT',
|
|
'message' => 'Starting router enrollment process...',
|
|
'percentage' => 0,
|
|
'completed_steps' => [],
|
|
'current_step_index' => 0,
|
|
'status' => 'running',
|
|
'error' => null,
|
|
'logs' => []
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Clear progress tracking
|
|
*/
|
|
public function clearProgress() {
|
|
unset($_SESSION['enrollment_progress']);
|
|
}
|
|
|
|
/**
|
|
* Main enrollment process
|
|
*/
|
|
public function enrollRouter($hashKey, $apiEndpoint = null) {
|
|
try {
|
|
// Initialize progress tracking
|
|
$this->initializeProgress();
|
|
|
|
if ($apiEndpoint) {
|
|
$this->apiClient = new ApiClient($apiEndpoint);
|
|
}
|
|
|
|
$this->reportProgress('INIT', 'Starting router enrollment process...', 0);
|
|
|
|
// Step 1: Check system requirements
|
|
$this->reportProgress('REQUIREMENTS', 'Checking system requirements...', 10);
|
|
if (!$this->checkSystemRequirements()) {
|
|
throw new Exception('System requirements check failed');
|
|
}
|
|
|
|
// Step 2: Install OpenZiti if needed
|
|
$this->reportProgress('INSTALL', 'Installing OpenZiti CLI...', 20);
|
|
if (!$this->installZiti()) {
|
|
throw new Exception('OpenZiti installation failed');
|
|
}
|
|
|
|
// Step 3: Create directories
|
|
$this->reportProgress('DIRECTORIES', 'Creating necessary directories...', 30);
|
|
if (!$this->createDirectories()) {
|
|
throw new Exception('Failed to create directories');
|
|
}
|
|
|
|
// Step 4: Register router with API
|
|
$this->reportProgress('REGISTER', 'Registering router with ZitiNexus Portal...', 40);
|
|
$result = $this->apiClient->registerRouter($hashKey);
|
|
if (!$result['success']) {
|
|
throw new Exception('Router registration failed: ' . $result['error']);
|
|
}
|
|
|
|
$this->routerData = $result['data'];
|
|
$this->reportProgress('REGISTER', 'Router registered successfully: ' . $this->routerData['routerInfo']['name'], 50);
|
|
|
|
// Step 5: Save configuration files
|
|
$this->reportProgress('CONFIG', 'Saving configuration files...', 60);
|
|
if (!$this->saveConfiguration()) {
|
|
throw new Exception('Failed to save configuration files');
|
|
}
|
|
|
|
// Step 6: Enroll router with OpenZiti
|
|
$this->reportProgress('ENROLL', 'Enrolling router with OpenZiti controller...', 70);
|
|
if (!$this->enrollWithZiti()) {
|
|
throw new Exception('Router enrollment with OpenZiti failed');
|
|
}
|
|
|
|
// Step 7: Create systemd service
|
|
$this->reportProgress('SERVICE', 'Creating systemd service...', 80);
|
|
if (!$this->createSystemdService()) {
|
|
throw new Exception('Failed to create systemd service');
|
|
}
|
|
|
|
// Step 8: Start router service
|
|
$this->reportProgress('START', 'Starting router service...', 90);
|
|
if (!$this->startRouter()) {
|
|
throw new Exception('Failed to start router service');
|
|
}
|
|
|
|
// Step 9: Report success status
|
|
$this->reportProgress('REPORT', 'Reporting enrollment status...', 95);
|
|
$this->reportSuccessStatus($hashKey);
|
|
|
|
$this->reportProgress('COMPLETE', 'Router enrollment completed successfully!', 100);
|
|
|
|
return [
|
|
'success' => true,
|
|
'routerName' => $this->routerData['routerInfo']['name'],
|
|
'routerId' => $this->routerData['routerInfo']['id'],
|
|
'message' => 'Router enrollment completed successfully'
|
|
];
|
|
|
|
} catch (Exception $e) {
|
|
$errorMsg = $e->getMessage();
|
|
logMessage('ERROR', $errorMsg);
|
|
$this->reportProgress('ERROR', $errorMsg, null);
|
|
|
|
// Report failure status
|
|
if (!empty($hashKey) && !empty($this->routerData['callbackUrl'])) {
|
|
$this->apiClient->reportStatus(
|
|
$this->routerData['callbackUrl'],
|
|
$hashKey,
|
|
'failed',
|
|
null,
|
|
$errorMsg
|
|
);
|
|
}
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => $errorMsg
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check system requirements
|
|
*/
|
|
private function checkSystemRequirements() {
|
|
// Check if running as root
|
|
if (!isRunningAsRoot()) {
|
|
throw new Exception('This script must be run as root (use sudo)');
|
|
}
|
|
|
|
// Check if curl is available
|
|
if (!$this->checkCommand('curl')) {
|
|
$this->reportProgress('REQUIREMENTS', 'Installing curl...');
|
|
if (!$this->installPackage('curl')) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check if jq is available
|
|
if (!$this->checkCommand('jq')) {
|
|
$this->reportProgress('REQUIREMENTS', 'Installing jq...');
|
|
if (!$this->installPackage('jq')) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check if systemctl is available
|
|
if (!$this->checkCommand('systemctl')) {
|
|
throw new Exception('systemctl is required but not available');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Install OpenZiti CLI
|
|
*/
|
|
private function installZiti() {
|
|
// Check if ziti is already installed
|
|
if ($this->checkCommand('ziti')) {
|
|
$output = '';
|
|
executeCommand('ziti version 2>/dev/null | head -n1', $output);
|
|
$this->reportProgress('INSTALL', 'OpenZiti CLI already installed: ' . trim($output));
|
|
return true;
|
|
}
|
|
|
|
$this->reportProgress('INSTALL', 'Installing OpenZiti CLI from pre-configured repository...');
|
|
|
|
// Verify repository is configured
|
|
if (!file_exists('/etc/apt/sources.list.d/openziti-release.list')) {
|
|
throw new Exception('OpenZiti repository not configured. Please run install.sh first to set up the system.');
|
|
}
|
|
|
|
if (!file_exists('/usr/share/keyrings/openziti.gpg')) {
|
|
throw new Exception('OpenZiti GPG key not found. Please run install.sh first to set up the system.');
|
|
}
|
|
|
|
// Install openziti-router package from pre-configured repository
|
|
$this->reportProgress('INSTALL', 'Installing openziti-router package...');
|
|
if (!executeCommand('apt-get install -y openziti-router')) {
|
|
$this->reportProgress('INSTALL', 'Trying to install ziti CLI only...');
|
|
if (!executeCommand('apt-get install -y ziti')) {
|
|
throw new Exception('Failed to install OpenZiti CLI. Repository may not be properly configured. Please run install.sh first.');
|
|
}
|
|
}
|
|
|
|
// Verify installation
|
|
if (!$this->checkCommand('ziti')) {
|
|
throw new Exception('OpenZiti CLI installation failed - command not found after installation');
|
|
}
|
|
|
|
$output = '';
|
|
executeCommand('ziti version 2>/dev/null | head -n1', $output);
|
|
$this->reportProgress('INSTALL', 'OpenZiti CLI installed successfully: ' . trim($output));
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Create necessary directories
|
|
*/
|
|
private function createDirectories() {
|
|
$directories = [
|
|
CONFIG_DIR => 0755,
|
|
CERTS_DIR => 0700,
|
|
dirname(LOG_FILE) => 0755
|
|
];
|
|
|
|
foreach ($directories as $dir => $permissions) {
|
|
if (!is_dir($dir)) {
|
|
// Use sudo to create system directories
|
|
if (!executeCommand("mkdir -p '$dir'")) {
|
|
throw new Exception("Failed to create directory: $dir");
|
|
}
|
|
if (!executeCommand("chmod " . decoct($permissions) . " '$dir'")) {
|
|
throw new Exception("Failed to set permissions for directory: $dir");
|
|
}
|
|
} else {
|
|
// Ensure permissions are correct even if directory exists
|
|
executeCommand("chmod " . decoct($permissions) . " '$dir'");
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Save configuration files
|
|
*/
|
|
private function saveConfiguration() {
|
|
// Save JWT using temp file and sudo
|
|
$tempJwtFile = tempnam(sys_get_temp_dir(), 'ziti-jwt');
|
|
file_put_contents($tempJwtFile, $this->routerData['jwt']);
|
|
|
|
if (!executeCommand("cp '$tempJwtFile' " . JWT_FILE)) {
|
|
unlink($tempJwtFile);
|
|
throw new Exception('Failed to save JWT file');
|
|
}
|
|
unlink($tempJwtFile);
|
|
|
|
if (!executeCommand("chmod 600 " . JWT_FILE)) {
|
|
throw new Exception('Failed to set JWT file permissions');
|
|
}
|
|
|
|
// Save router configuration using temp file and sudo
|
|
$tempConfigFile = tempnam(sys_get_temp_dir(), 'ziti-config');
|
|
file_put_contents($tempConfigFile, $this->routerData['routerConfig']['yaml']);
|
|
|
|
if (!executeCommand("cp '$tempConfigFile' " . ROUTER_CONFIG)) {
|
|
unlink($tempConfigFile);
|
|
throw new Exception('Failed to save router configuration');
|
|
}
|
|
unlink($tempConfigFile);
|
|
|
|
if (!executeCommand("chmod 644 " . ROUTER_CONFIG)) {
|
|
throw new Exception('Failed to set router config permissions');
|
|
}
|
|
|
|
// Fix router configuration for proper enrollment
|
|
$this->fixRouterConfiguration();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Fix router configuration (replicate bash script logic)
|
|
*/
|
|
private function fixRouterConfiguration() {
|
|
// Create backup using sudo
|
|
executeCommand("cp " . ROUTER_CONFIG . " " . ROUTER_CONFIG . ".backup");
|
|
|
|
$routerName = $this->routerData['routerInfo']['name'];
|
|
$routerId = $this->routerData['routerInfo']['id'];
|
|
$tenantId = $this->routerData['metadata']['tenantId'];
|
|
$controllerEndpoint = $this->routerData['metadata']['controllerEndpoint'] ?? 'enroll.zitinexus.com:443';
|
|
|
|
// Add tls: prefix if not present
|
|
if (strpos($controllerEndpoint, 'tls:') !== 0) {
|
|
$controllerEndpoint = 'tls:' . $controllerEndpoint;
|
|
}
|
|
|
|
// Build role attributes
|
|
$roleAttributesSection = '# No role attributes specified';
|
|
if (!empty($this->routerData['routerInfo']['roleAttributes'])) {
|
|
$roleAttributesSection = "roleAttributes:";
|
|
foreach ($this->routerData['routerInfo']['roleAttributes'] as $attr) {
|
|
$roleAttributesSection .= "\n - \"$attr\"";
|
|
}
|
|
}
|
|
|
|
$generatedAt = date('c');
|
|
|
|
$configContent = <<<EOF
|
|
v: 3
|
|
|
|
identity:
|
|
cert: /etc/zitirouter/certs/$routerName.cert
|
|
server_cert: /etc/zitirouter/certs/$routerName.server.chain.cert
|
|
key: /etc/zitirouter/certs/$routerName.key
|
|
ca: /etc/zitirouter/certs/$routerName.cas
|
|
|
|
ctrl:
|
|
endpoint: $controllerEndpoint
|
|
|
|
link:
|
|
dialers:
|
|
- binding: transport
|
|
|
|
listeners:
|
|
# bindings of edge and tunnel requires an "edge" section below
|
|
- binding: edge
|
|
address: tls:0.0.0.0:443
|
|
options:
|
|
advertise: 127.0.0.1:443
|
|
connectTimeoutMs: 5000
|
|
getSessionTimeout: 60
|
|
- binding: tunnel
|
|
options:
|
|
mode: host
|
|
|
|
edge:
|
|
csr:
|
|
country: SG
|
|
province: SG
|
|
locality: Singapore
|
|
organization: Genworx
|
|
organizationalUnit: ZitiNexus
|
|
sans:
|
|
dns:
|
|
- localhost
|
|
- $routerName
|
|
ip:
|
|
- "127.0.0.1"
|
|
- "::1"
|
|
|
|
# Tenant-specific role attributes
|
|
$roleAttributesSection
|
|
|
|
# Router metadata
|
|
metadata:
|
|
tenantId: "$tenantId"
|
|
zitiRouterId: "$routerId"
|
|
routerType: "private-edge"
|
|
generatedAt: "$generatedAt"
|
|
generatedBy: "ZitiNexus"
|
|
EOF;
|
|
|
|
// Write updated config using temp file and sudo
|
|
$tempConfigFile = tempnam(sys_get_temp_dir(), 'ziti-fixed-config');
|
|
file_put_contents($tempConfigFile, $configContent);
|
|
|
|
if (!executeCommand("cp '$tempConfigFile' " . ROUTER_CONFIG)) {
|
|
unlink($tempConfigFile);
|
|
throw new Exception('Failed to save updated router configuration');
|
|
}
|
|
unlink($tempConfigFile);
|
|
|
|
if (!executeCommand("chmod 644 " . ROUTER_CONFIG)) {
|
|
throw new Exception('Failed to set updated router config permissions');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enroll router with OpenZiti
|
|
*/
|
|
private function enrollWithZiti() {
|
|
$command = 'ziti router enroll --jwt ' . JWT_FILE . ' ' . ROUTER_CONFIG . ' 2>&1';
|
|
$output = '';
|
|
|
|
if (!executeCommand($command, $output)) {
|
|
throw new Exception('Router enrollment failed: ' . $output);
|
|
}
|
|
|
|
// Verify certificates were created using sudo (since certs are root-owned with 600 permissions)
|
|
$routerName = $this->routerData['routerInfo']['name'];
|
|
$certFile = CERTS_DIR . '/' . $routerName . '.cert';
|
|
|
|
// Use sudo to check if certificate file exists (www-data can't read root-owned 600 files)
|
|
$checkOutput = '';
|
|
if (!executeCommand("test -f '$certFile'", $checkOutput)) {
|
|
// List what files actually exist for debugging
|
|
$listOutput = '';
|
|
executeCommand("ls -la " . CERTS_DIR . "/", $listOutput);
|
|
throw new Exception("Router certificate not found after enrollment. Expected: $certFile. Files in certs directory: " . $listOutput);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Create systemd service
|
|
*/
|
|
private function createSystemdService() {
|
|
$finalConfig = '/etc/zitirouter/zitirouter.yaml';
|
|
|
|
// Copy router config to final location using sudo
|
|
if (!executeCommand("cp " . ROUTER_CONFIG . " '$finalConfig'")) {
|
|
throw new Exception('Failed to copy router config to final location');
|
|
}
|
|
|
|
if (!executeCommand("chmod 644 '$finalConfig'")) {
|
|
throw new Exception('Failed to set final config permissions');
|
|
}
|
|
|
|
$serviceContent = <<<EOF
|
|
[Unit]
|
|
Description=OpenZiti Router
|
|
After=network.target
|
|
|
|
[Service]
|
|
ExecStart=/usr/bin/ziti router run /etc/zitirouter/zitirouter.yaml
|
|
Restart=on-failure
|
|
User=root
|
|
WorkingDirectory=/etc/zitirouter
|
|
LimitNOFILE=65536
|
|
StandardOutput=append:/var/log/ziti-router.log
|
|
StandardError=append:/var/log/ziti-router.log
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF;
|
|
|
|
// Write service file using sudo
|
|
$tempFile = tempnam(sys_get_temp_dir(), 'ziti-service');
|
|
file_put_contents($tempFile, $serviceContent);
|
|
|
|
if (!executeCommand("cp '$tempFile' " . SYSTEMD_SERVICE_FILE)) {
|
|
unlink($tempFile);
|
|
throw new Exception('Failed to create systemd service file');
|
|
}
|
|
unlink($tempFile);
|
|
|
|
// Reload systemd and enable service
|
|
if (!executeCommand('systemctl daemon-reload')) {
|
|
throw new Exception('Failed to reload systemd');
|
|
}
|
|
|
|
if (!executeCommand('systemctl enable ziti-router.service')) {
|
|
throw new Exception('Failed to enable ziti-router service');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Start router service
|
|
*/
|
|
private function startRouter() {
|
|
if (!executeCommand('systemctl start ziti-router.service')) {
|
|
throw new Exception('Failed to start router service');
|
|
}
|
|
|
|
// Wait and check status
|
|
sleep(3);
|
|
$output = '';
|
|
executeCommand('systemctl is-active ziti-router.service', $output);
|
|
|
|
if (trim($output) !== 'active') {
|
|
logMessage('WARNING', 'Router service may not be running properly');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Report success status
|
|
*/
|
|
private function reportSuccessStatus($hashKey) {
|
|
if (empty($this->routerData['callbackUrl'])) {
|
|
return;
|
|
}
|
|
|
|
$hostname = '';
|
|
$arch = '';
|
|
$os = '';
|
|
$zitiVersion = '';
|
|
|
|
executeCommand('hostname', $hostname);
|
|
executeCommand('uname -m', $arch);
|
|
executeCommand('lsb_release -d 2>/dev/null | cut -f2', $os);
|
|
executeCommand('ziti version 2>/dev/null | head -n1', $zitiVersion);
|
|
|
|
$routerInfo = [
|
|
'version' => trim($zitiVersion) ?: 'unknown',
|
|
'hostname' => trim($hostname),
|
|
'arch' => trim($arch),
|
|
'os' => trim($os) ?: 'Linux'
|
|
];
|
|
|
|
$this->apiClient->reportStatus(
|
|
$this->routerData['callbackUrl'],
|
|
$hashKey,
|
|
'success',
|
|
$routerInfo
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if command exists
|
|
*/
|
|
private function checkCommand($command) {
|
|
$output = '';
|
|
return executeCommand("which $command", $output);
|
|
}
|
|
|
|
/**
|
|
* Install package using apt
|
|
*/
|
|
private function installPackage($package) {
|
|
return executeCommand("apt-get update && apt-get install -y $package");
|
|
}
|
|
|
|
/**
|
|
* Get system status information with enhanced package detection
|
|
*/
|
|
public function getSystemStatus() {
|
|
$status = [
|
|
'hostname' => '',
|
|
'ziti_status' => 'unknown',
|
|
'ziti_version' => '',
|
|
'service_active' => false,
|
|
'config_exists' => false,
|
|
'certificates_exist' => false,
|
|
'package_installed' => false,
|
|
'last_checked' => time()
|
|
];
|
|
|
|
// Get hostname
|
|
executeCommand('hostname', $status['hostname']);
|
|
$status['hostname'] = trim($status['hostname']);
|
|
|
|
// Enhanced Ziti installation check
|
|
$zitiInstallationStatus = $this->checkZitiInstallation();
|
|
$status['ziti_status'] = $zitiInstallationStatus['status'];
|
|
$status['ziti_version'] = $zitiInstallationStatus['version'];
|
|
$status['package_installed'] = $zitiInstallationStatus['package_installed'];
|
|
|
|
// Check service status with more thorough checking
|
|
$serviceStatus = $this->checkServiceStatus();
|
|
$status['service_active'] = $serviceStatus['active'];
|
|
|
|
// Check configuration files
|
|
$status['config_exists'] = file_exists(ROUTER_CONFIG);
|
|
|
|
// Check certificates with sudo (since they're root-owned)
|
|
$status['certificates_exist'] = $this->checkCertificatesExist();
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Enhanced Ziti installation checking
|
|
*/
|
|
private function checkZitiInstallation() {
|
|
$result = [
|
|
'status' => 'not_installed',
|
|
'version' => '',
|
|
'package_installed' => false
|
|
];
|
|
|
|
// Check if package is installed via dpkg
|
|
$dpkgOutput = '';
|
|
$packageInstalled = executeCommand('dpkg -l | grep -E "(openziti-router|ziti)" | grep -v "^rc"', $dpkgOutput);
|
|
|
|
if ($packageInstalled && !empty(trim($dpkgOutput))) {
|
|
$result['package_installed'] = true;
|
|
|
|
// Extract version from dpkg output if available
|
|
if (preg_match('/(\d+\.\d+\.\d+)/', $dpkgOutput, $matches)) {
|
|
$result['version'] = $matches[1];
|
|
}
|
|
}
|
|
|
|
// Check if command works
|
|
$versionOutput = '';
|
|
$commandWorks = executeCommand('ziti version 2>/dev/null | head -n1', $versionOutput);
|
|
|
|
if ($commandWorks && !empty(trim($versionOutput))) {
|
|
$result['status'] = 'installed';
|
|
|
|
// Use command output version if we don't have one from dpkg
|
|
if (empty($result['version'])) {
|
|
$result['version'] = trim($versionOutput);
|
|
}
|
|
} else if ($result['package_installed']) {
|
|
// Package is installed but command doesn't work - might be broken
|
|
$result['status'] = 'broken';
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Enhanced service status checking
|
|
*/
|
|
private function checkServiceStatus() {
|
|
$result = [
|
|
'active' => false,
|
|
'enabled' => false,
|
|
'status' => 'unknown'
|
|
];
|
|
|
|
// Check if service is active
|
|
$activeOutput = '';
|
|
if (executeCommand('systemctl is-active ziti-router.service 2>/dev/null', $activeOutput)) {
|
|
$result['active'] = trim($activeOutput) === 'active';
|
|
$result['status'] = trim($activeOutput);
|
|
}
|
|
|
|
// Check if service is enabled
|
|
$enabledOutput = '';
|
|
if (executeCommand('systemctl is-enabled ziti-router.service 2>/dev/null', $enabledOutput)) {
|
|
$result['enabled'] = trim($enabledOutput) === 'enabled';
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Check if certificates exist (using sudo since they're root-owned)
|
|
*/
|
|
private function checkCertificatesExist() {
|
|
if (!is_dir(CERTS_DIR)) {
|
|
return false;
|
|
}
|
|
|
|
// Use sudo to list certificate files since they're root-owned with 600 permissions
|
|
$output = '';
|
|
if (executeCommand("find " . CERTS_DIR . " -name '*.cert' -type f 2>/dev/null", $output)) {
|
|
return !empty(trim($output));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Force refresh system status (clear any caches)
|
|
*/
|
|
public function refreshSystemStatus() {
|
|
// Clear any potential caches
|
|
clearstatcache();
|
|
|
|
// Update package database
|
|
executeCommand('apt-get update -qq 2>/dev/null');
|
|
|
|
return $this->getSystemStatus();
|
|
}
|
|
}
|
|
?>
|