From 538e3fafe1fc9ba8f3f3a84bf3603f3251ba93f7 Mon Sep 17 00:00:00 2001 From: lgromero Date: Thu, 16 Jan 2025 13:14:34 +0100 Subject: [PATCH] refs #1131 fix bug in create boot files that dont adds ogcore and oglog parameters --- .../Controller/OgBootController.php | 148 ++++++++++-------- 1 file changed, 87 insertions(+), 61 deletions(-) diff --git a/src/OgBootBundle/Controller/OgBootController.php b/src/OgBootBundle/Controller/OgBootController.php index 4053c2a..0133288 100644 --- a/src/OgBootBundle/Controller/OgBootController.php +++ b/src/OgBootBundle/Controller/OgBootController.php @@ -1464,6 +1464,8 @@ public function getBootFiles(): JsonResponse * ) * ) */ + + public function createBootFile(Request $request): JsonResponse { $operation = 'ogboot.createBootFile'; @@ -1477,29 +1479,17 @@ public function createBootFile(Request $request): JsonResponse ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); $data = json_decode($request->getContent(), true); + $templateName = $data['template_name'] ?? null; $mac = $this->validateAndFormatMac($data['mac'] ?? null); + //Si nos pasan el puerto se lo quitamos ya que server_ip siempre tirara por Samba $serverIp = $data['server_ip'] ?? null; - if ($serverIp && strpos($serverIp, ':') !== false) { $serverIp = explode(':', $serverIp)[0]; } - $ogLiveDir = $data['oglivedir'] ?? 'ogLive'; - $this->logger->debug(json_encode([ - 'severity' => 'DEBUG', - 'operation' => $operation, - 'component' => $component, - 'params' => [ - 'template_name' => $templateName, - 'mac' => $mac, - 'server_ip' => $serverIp, - 'oglivedir' => $ogLiveDir - ], - 'desc' => 'Input data for PXE file creation.' - ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); - + // Verificación de los campos obligatorios if (!$templateName || !$mac) { $httpCode = '400'; $this->logger->warning(json_encode([ @@ -1509,13 +1499,10 @@ public function createBootFile(Request $request): JsonResponse 'http_code' => $httpCode, 'desc' => 'Missing required fields: mac and/or template_name.' ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); - - return new JsonResponse( - ['error' => 'Missing required fields: mac and template_name'], - Response::HTTP_BAD_REQUEST - ); + return new JsonResponse(['error' => 'Missing required fields: mac and template_name'], Response::HTTP_BAD_REQUEST); } + // Validación adicional para asegurarnos de que no hay caracteres inseguros if (!preg_match('/^[a-zA-Z0-9._-]+$/', $templateName) || strpos($templateName, '..') !== false) { $httpCode = '400'; $this->logger->warning(json_encode([ @@ -1526,16 +1513,41 @@ public function createBootFile(Request $request): JsonResponse 'params' => ['template_name' => $templateName], 'desc' => 'Invalid template name or unauthorized access attempt.' ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); - return new JsonResponse( - ['error' => 'INVALID_TEMPLATE_NAME', 'message' => 'Invalid template name or unauthorized access attempt.'], + ['error' => 'INVALID_TEMPLATE_NAME', 'message' => 'Nombre de la plantilla no válido o intento de acceso no autorizado.'], Response::HTTP_BAD_REQUEST ); } + + // Parámetros opcionales + $parameters = [ + 'LANG' => $data['lang'] ?? 'es_ES.UTF-8', + 'ip' => $data['ip'] ?? '', + 'router' => $data['router'] ?? '', + 'netmask' => $data['netmask'] ?? '', + 'computer_name' => $data['computer_name'] ?? '', + 'netiface' => $data['netiface'] ?? '', + 'group' => $data['group'] ?? '', + 'ogrepo' => isset($data['ogrepo']) ? explode(':', $data['ogrepo'])[0] : '', + 'ogcore' => isset($data['ogcore']) ? explode(':', $data['ogcore'])[0] : '', + 'oglive' => isset($data['oglive']) ? explode(':', $data['oglive'])[0] : $serverIp, + 'oglog' => isset($data['oglog']) ? explode(':', $data['oglog'])[0] : $serverIp, + 'ogshare' => isset($data['ogshare']) ? explode(':', $data['ogshare'])[0] : $serverIp, + 'oglivedir' => $data['oglivedir'] ?? '', + 'ogprof' => $data['ogprof'] ?? 'false', + 'hardprofile' => $data['hardprofile'] ?? '', + 'ogntp' => $data['ogntp'] ?? '', + 'ogdns' => $data['ogdns'] ?? '', + 'ogproxy' => $data['ogproxy'] ?? '', + 'ogunit' => $data['ogunit'] ?? '', + 'resolution' => $data['resolution'] ?? '788' + ]; + $templateDir = $this->tftpbootDir . '/ipxe_scripts/templates'; $templatePath = $templateDir . '/' . $templateName; + // Verificar si la plantilla existe if (!file_exists($templatePath)) { $httpCode = '404'; $this->logger->info(json_encode([ @@ -1546,11 +1558,7 @@ public function createBootFile(Request $request): JsonResponse 'params' => ['template_path' => $templatePath], 'desc' => 'Template not found.' ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); - - return new JsonResponse( - ['error' => 'TEMPLATE_NOT_FOUND', 'message' => 'Template not found.'], - Response::HTTP_NOT_FOUND - ); + return new JsonResponse(['error' => 'TEMPLATE_NOT_FOUND', 'message' => 'No se encontró la plantilla especificada'], Response::HTTP_NOT_FOUND); } $templateContent = file_get_contents($templatePath); @@ -1564,45 +1572,61 @@ public function createBootFile(Request $request): JsonResponse 'params' => ['template_path' => $templatePath], 'desc' => 'Failed to read the template.' ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); - - return new JsonResponse( - ['error' => 'FAILED_TO_READ_TEMPLATE', 'message' => 'Failed to read template.'], - Response::HTTP_INTERNAL_SERVER_ERROR - ); + return new JsonResponse(['error' => 'FAILED_TO_READ_TEMPLATE', 'message' => 'Error al leer la plantilla'], Response::HTTP_INTERNAL_SERVER_ERROR); } - $this->logger->debug(json_encode([ - 'severity' => 'DEBUG', - 'operation' => $operation, - 'component' => $component, - 'desc' => 'Template content loaded.' - ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); - + // Construcción de los argumentos del kernel $kernelArgs = 'ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 ' . - 'oglivedir=${ISODIR} ' . - 'LANG=' . ($data['lang'] ?? 'es_ES.UTF-8') . ' ' . - 'ip=' . ($data['ip'] ?? '') . ':' . $serverIp . ':' . ($data['router'] ?? '') . ':' . ($data['netmask'] ?? '') . ':' . ($data['computer_name'] ?? '') . ':' . ($data['netiface'] ?? '') . ':none '; - - $this->logger->debug(json_encode([ - 'severity' => 'DEBUG', - 'operation' => $operation, - 'component' => $component, - 'params' => ['kernelArgs' => $kernelArgs], - 'desc' => 'Kernel arguments constructed.' - ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); + 'oglivedir=${ISODIR}' . ' ' . + 'LANG=' . $parameters['LANG'] . ' ' . + 'ip=' . $parameters['ip'] . ':' . $serverIp . ':' . $parameters['router'] . ':' . $parameters['netmask'] . ':' . $parameters['computer_name'] . ':' . $parameters['netiface'] . ':none ' . + 'group=' . str_replace(' ', '_', trim($parameters['group'])) . ' ' . + 'ogrepo=' . $parameters['ogrepo'] . ' ' . + 'ogcore=' . $parameters['ogcore'] . ' ' . + 'oglive=' . $parameters['oglive'] . ' ' . + 'oglog=' . $parameters['oglog'] . ' ' . + 'ogshare=' . $parameters['ogshare'] . ' ' . + 'ogprof=' . ($parameters['ogprof'] === 'true' ? 'true' : 'false') . ' ' . + (!empty($parameters['hardprofile']) ? 'hardprofile=' . str_replace(' ', '_', trim($parameters['hardprofile'])) . ' ' : '') . + (!empty($parameters['ogntp']) ? 'ogntp=' . $parameters['ogntp'] . ' ' : '') . + (!empty($parameters['ogdns']) ? 'ogdns=' . $parameters['ogdns'] . ' ' : '') . + (!empty($parameters['ogproxy']) ? 'ogproxy=' . $parameters['ogproxy'] . ' ' : '') . + (!empty($parameters['ogunit']) ? 'ogunit=' . $parameters['ogunit'] . ' ' : '') . + (is_numeric($parameters['resolution']) && $parameters['resolution'] <= 999 ? 'vga=' . $parameters['resolution'] : + (strpos($parameters['resolution'], ':') !== false ? 'video=' . $parameters['resolution'] : ' ' . $parameters['resolution'])); + // Esta será llamada a http para arrancar kernel e imagen de inicialización + // Si lo requiriese debe llevar puerto ya que se comunica con nginx $serverIpPort = $this->ogBootIP; if (!empty($this->ogBootPort)) { $serverIpPort .= ':' . $this->ogBootPort; } - + // Extraer solo el nombre del directorio si contiene una ruta completa PROVISIONAL + if (strpos($ogLiveDir, '/') !== false) { + $ogLiveDir = basename($ogLiveDir); + } $pxeContent = str_replace( ['__INFOHOST__', '__SERVERIP__', '__OGLIVE__'], - [$kernelArgs, $serverIpPort, basename($ogLiveDir)], + [$kernelArgs, $serverIpPort, $ogLiveDir], $templateContent ); - if (file_put_contents($this->tftpbootDir . '/ipxe_scripts/01-' . $mac, $pxeContent) === false) { + + // Insertar el comentario con el nombre de la plantilla después de #!ipxe + if (strpos($pxeContent, '#!ipxe') === 0) { + $pxeContent = "#!ipxe\n#Template: $templateName\n" . substr($pxeContent, 6); + } else { + $pxeContent = "#!ipxe\n#Template: $templateName\n" . $pxeContent; + } + + // Nombre del archivo PXE basado en la MAC + $pxeFileName = '01-' . $mac; + + // Ruta para guardar el archivo PXE + $pxeFilePath = $this->tftpbootDir . '/ipxe_scripts/' . $pxeFileName; + + // Crear el archivo PXE + if (file_put_contents($pxeFilePath, $pxeContent) === false) { $httpCode = '500'; $this->logger->error(json_encode([ 'severity' => 'ERROR', @@ -1611,13 +1635,8 @@ public function createBootFile(Request $request): JsonResponse 'http_code' => $httpCode, 'desc' => 'Failed to create PXE file.' ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); - - return new JsonResponse( - ['error' => 'FAILED_TO_CREATE_PXE_FILE', 'message' => 'Failed to create PXE file.'], - Response::HTTP_INTERNAL_SERVER_ERROR - ); + return new JsonResponse(['error' => 'FAILED_TO_CREATE_PXE_FILE', 'message' => 'Error al crear el archivo PXE'], Response::HTTP_INTERNAL_SERVER_ERROR); } - $httpCode = '200'; $this->logger->info(json_encode([ 'severity' => 'INFO', @@ -1631,10 +1650,14 @@ public function createBootFile(Request $request): JsonResponse 'success' => 'PXE file created successfully', 'message' => $pxeContent ], Response::HTTP_OK); + + // Retornar la plantilla creada en el formato solicitado + return new JsonResponse([ + 'success' => 'PXE file created successfully', + 'message' => $pxeContent + ], Response::HTTP_OK); } - - function validateAndFormatMac($mac) { @@ -1657,6 +1680,9 @@ function validateAndFormatMac($mac) } + + + /** * @Route("/ogboot/v1/pxes/{mac}", name="ogboot_delete_boot_file", methods={"DELETE"}) * @OA\Delete(