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"); if ($this->progressCallback && is_callable($this->progressCallback)) { call_user_func($this->progressCallback, $step, $message, $percentage); } } /** * Main enrollment process */ public function enrollRouter($hashKey, $apiEndpoint = null) { try { 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', 'Setting up OpenZiti package repository...'); // Add GPG key $gpgCommand = 'curl -sSLf https://get.openziti.io/tun/package-repos.gpg | gpg --dearmor --output /usr/share/keyrings/openziti.gpg'; if (!executeCommand($gpgCommand)) { throw new Exception('Failed to add OpenZiti GPG key'); } // Set proper permissions if (!executeCommand('chmod a+r /usr/share/keyrings/openziti.gpg')) { throw new Exception('Failed to set GPG key permissions'); } // Add repository to sources list $repoContent = 'deb [signed-by=/usr/share/keyrings/openziti.gpg] https://packages.openziti.org/zitipax-openziti-deb-stable debian main'; if (!file_put_contents('/etc/apt/sources.list.d/openziti-release.list', $repoContent)) { throw new Exception('Failed to add OpenZiti repository'); } // Update package list $this->reportProgress('INSTALL', 'Updating package list...'); if (!executeCommand('apt-get update')) { throw new Exception('Failed to update package list'); } // Install openziti-router package $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'); } } // 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)) { if (!mkdir($dir, $permissions, true)) { throw new Exception("Failed to create directory: $dir"); } } chmod($dir, $permissions); } return true; } /** * Save configuration files */ private function saveConfiguration() { // Save JWT if (!file_put_contents(JWT_FILE, $this->routerData['jwt'])) { throw new Exception('Failed to save JWT file'); } chmod(JWT_FILE, 0600); // Save router configuration if (!file_put_contents(ROUTER_CONFIG, $this->routerData['routerConfig']['yaml'])) { throw new Exception('Failed to save router configuration'); } chmod(ROUTER_CONFIG, 0644); // Fix router configuration for proper enrollment $this->fixRouterConfiguration(); return true; } /** * Fix router configuration (replicate bash script logic) */ private function fixRouterConfiguration() { // Create backup copy(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 = <<&1'; $output = ''; if (!executeCommand($command, $output)) { throw new Exception('Router enrollment failed: ' . $output); } // Verify certificates were created $routerName = $this->routerData['routerInfo']['name']; $certFile = CERTS_DIR . '/' . $routerName . '.cert'; if (!file_exists($certFile)) { throw new Exception('Router certificate not found after enrollment'); } return true; } /** * Create systemd service */ private function createSystemdService() { $finalConfig = '/etc/zitirouter/zitirouter.yaml'; // Copy router config to final location if (!copy(ROUTER_CONFIG, $finalConfig)) { throw new Exception('Failed to copy router config to final location'); } chmod($finalConfig, 0644); $serviceContent = <<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 */ public function getSystemStatus() { $status = [ 'hostname' => '', 'ziti_status' => 'unknown', 'ziti_version' => '', 'service_active' => false, 'config_exists' => false, 'certificates_exist' => false ]; // Get hostname executeCommand('hostname', $status['hostname']); $status['hostname'] = trim($status['hostname']); // Check if ziti command exists and get version if ($this->checkCommand('ziti')) { executeCommand('ziti version 2>/dev/null | head -n1', $status['ziti_version']); $status['ziti_version'] = trim($status['ziti_version']); $status['ziti_status'] = 'installed'; } else { $status['ziti_status'] = 'not_installed'; } // Check service status $output = ''; if (executeCommand('systemctl is-active ziti-router.service 2>/dev/null', $output)) { $status['service_active'] = trim($output) === 'active'; } // Check configuration files $status['config_exists'] = file_exists(ROUTER_CONFIG); // Check certificates if (is_dir(CERTS_DIR)) { $certFiles = glob(CERTS_DIR . '/*.cert'); $status['certificates_exist'] = !empty($certFiles); } return $status; } } ?>