From fedd164b02866401448f624cfc427b3211f69bee Mon Sep 17 00:00:00 2001 From: lgromero Date: Tue, 15 Oct 2024 12:51:55 +0000 Subject: [PATCH] refs #868 #864 #866 #949 #943 #870 Return hard info of disk usage, adds id to get default oglive, return error code in oglivecli, control error code in service and controller endpoints, updates swagger documentation in some oglives endpoints, adds new errores 400 and 404 in oglivecli functions and control errores in getOglives, getOgliveDefault and uninstall. Dont allow to uninstall default oglive --- bin/oglivecli | 76 ++++-- .../Controller/OgBootController.php | 238 +++++++++--------- .../Service/CurlRequestService.php | 22 +- 3 files changed, 202 insertions(+), 134 deletions(-) diff --git a/bin/oglivecli b/bin/oglivecli index 32e4d7a..f9589f8 100755 --- a/bin/oglivecli +++ b/bin/oglivecli @@ -436,37 +436,57 @@ function install() { # Uninstall an ogLive client. function uninstall() { - local CHECKSUM DIR + local CHECKSUM DIR DEFAULT_OGLIVE_DIR DEFAULT_CHECKSUM # Validar que se proporcionó exactamente un argumento (el checksum) - [ $# -ne 1 ] && { echo "{\"error\": \"usage: uninstall {checksum}\"}"; exit 1; } + [ $# -ne 1 ] && { echo "{\"error\": \"BAD_REQUEST\", \"message\": \"usage: uninstall {checksum}\"}"; exit 400; } CHECKSUM=$1 # Verificar acceso a los directorios necesarios - [ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; } + [ ! -w $TFTPDIR ] && { echo "{\"error\": \"SERVER_ERROR\", \"message\": \"access installation directory.\"}"; exit 500; } + + # Verificar el enlace simbólico del ogLive por defecto + if [ -L "$TFTPDIR/ogLive" ]; then + DEFAULT_OGLIVE_DIR=$(readlink -f "$TFTPDIR/ogLive") + DEFAULT_CHECKSUM_FILE="$DEFAULT_OGLIVE_DIR/ogclient.sqfs.sum" + + # Verificar si el archivo de checksum del ogLive por defecto existe + if [ -f "$DEFAULT_CHECKSUM_FILE" ]; then + DEFAULT_CHECKSUM=$(cat "$DEFAULT_CHECKSUM_FILE" | cut -d ' ' -f 1) + + # Comparar el checksum proporcionado con el del ogLive por defecto + if [ "$CHECKSUM" == "$DEFAULT_CHECKSUM" ]; then + echo "{\"error\": \"FORBIDDEN\", \"message\": \"Cannot uninstall the default ogLive client.\"}" + exit 403 + fi + fi + fi # Buscar el directorio correspondiente al checksum DIR=$(find $TFTPDIR -type f -name 'ogclient.sqfs.sum' -exec grep -l "$CHECKSUM" {} \; | xargs -I{} dirname {}) - # Si no se encuentra el directorio, devolver error + # Si no se encuentra el directorio, devolver error 404 if [ -z "$DIR" ]; then - echo "{\"error\": \"ogLive client with checksum $CHECKSUM not found.\"}" - exit 1 + echo "{\"error\": \"NOT_FOUND\", \"message\": \"ogLive client with checksum $CHECKSUM not found.\"}" + exit 404 fi # Eliminar archivos y directorio, redirigiendo la salida a /dev/null rm -vfr $DIR > /dev/null 2>&1 - # Comprobar si la eliminación tuvo éxito + # Comprobar si la eliminación tuvo éxito, si no, devolver error 500 if [ -d "$DIR" ]; then - echo "{\"error\": \"Failed to uninstall ogLive client in $DIR.\"}" - exit 1 + echo "{\"error\": \"SERVER_ERROR\", \"message\": \"Failed to uninstall ogLive client in $DIR.\"}" + exit 500 fi # Devolver mensaje de éxito echo "{\"message\": \"ogLive client uninstalled successfully.\", \"details\": \"Removed directory: $DIR\"}" + exit 200 } + + # Get information about the default ogLive client. function get_default() { local DEFAULT_LINK="$TFTPDIR/$DEFOGLIVE" @@ -562,15 +582,29 @@ function set_default() { # Get disk usage information function disk_usage() { - DISK_INFO=$(df -h / | awk 'NR==2{print "{\"total\":\""$2"\", \"used\":\""$3"\", \"available\":\""$4"\", \"percentage\":\""$5"\"}"}') + DISK_INFO=$(df / | awk 'NR==2{print "{\"total\":\""$2"\", \"used\":\""$3"\", \"available\":\""$4"\", \"percentage\":\""$5"\"}"}') echo $DISK_INFO } # Function to list installed ogLive clients and the default ogLive client function list_installed_oglives() { local INST NF DEF - INST=$(find $TFTPDIR/ -type d -name "$DEFOGLIVE-*" -a ! -name "*.old" -printf "%f\n" | sort) + + # Verificar si el directorio TFTPDIR es accesible + if [ ! -d "$TFTPDIR" ]; then + echo "{\"error\": \"SERVER_ERROR\", \"message\": \"TFTP directory not found or not accessible.\"}" + exit 500 + fi + + # Buscar directorios de ogLive instalados + INST=$(find "$TFTPDIR/" -type d -name "$DEFOGLIVE-*" -a ! -name "*.old" -printf "%f\n" 2>/dev/null | sort) + if [ -z "$INST" ]; then + echo "{\"error\": \"NOT_FOUND\", \"message\": \"No installed ogLive clients found.\"}" + exit 404 + fi + local installed_ogLives=() + local oglive_count=0 for i in $INST; do local OGLIVEDIR="$TFTPDIR/$i" @@ -589,13 +623,16 @@ function list_installed_oglives() { OGLIVEARCH=$(jq -r '.OGLIVEARCH' "$OGLIVEJSON") OGLIVEREV=$(jq -r '.OGLIVEREV' "$OGLIVEJSON") else - echo "{\"error\": \"oglive_info.json not found in $OGLIVEDIR.\"}" - continue + echo "{\"error\": \"NOT_FOUND\", \"message\": \"oglive_info.json not found in $OGLIVEDIR.\"}" + continue # Continuar con el siguiente ogLive en lugar de detener el proceso fi # Obtener el checksum del archivo ogclient.sqfs.sum if [ -f "$CHECKSUM_FILE" ]; then CHECKSUM=$(cat "$CHECKSUM_FILE" | cut -d ' ' -f 1) + else + echo "{\"error\": \"NOT_FOUND\", \"message\": \"Checksum file not found in $OGLIVEDIR.\"}" + continue fi # Crear el JSON con los datos del ogLive @@ -609,12 +646,19 @@ function list_installed_oglives() { '{id: $id, distribution: $dist, kernel: $krnl, architecture: $arch, revision: $rev, directory: $dir}') installed_ogLives+=("$DATA") + oglive_count=$((oglive_count + 1)) # Verificar si es el ogLive por defecto - [ -n "$(stat -c "%N" $TFTPDIR/$DEFOGLIVE | awk '$3~/'$i'/ {print}')" ] && DEF="$i" + [ -n "$(stat -c "%N" "$TFTPDIR/$DEFOGLIVE" | awk '$3~/'$i'/ {print}')" ] && DEF="$i" done - local default_oglive=$(basename $(readlink -f $TFTPDIR/$DEFOGLIVE)) + # Verificar si se encontraron ogLives + if [ "$oglive_count" -eq 0 ]; then + echo "{\"error\": \"NOT_FOUND\", \"message\": \"No valid ogLive clients found.\"}" + exit 404 + fi + + local default_oglive=$(basename "$(readlink -f "$TFTPDIR/$DEFOGLIVE")") # Crear el JSON final con la lista de ogLives instalados y el ogLive por defecto jq -n \ @@ -624,6 +668,7 @@ function list_installed_oglives() { default_oglive: $default_oglive, installed_ogLives: $installed_ogLives }' + exit 0 } # Get information about an installed ogLive client. @@ -726,3 +771,4 @@ esac exit $? + diff --git a/src/OgBootBundle/Controller/OgBootController.php b/src/OgBootBundle/Controller/OgBootController.php index 674624a..a1e61b6 100644 --- a/src/OgBootBundle/Controller/OgBootController.php +++ b/src/OgBootBundle/Controller/OgBootController.php @@ -125,12 +125,10 @@ public function getStatus(): Response * response=200, * description="Isos retrieved successfully", * @OA\JsonContent( - * type="array", - * @OA\Items(type="object", - * @OA\Property(property="id", type="integer"), - * @OA\Property(property="filename", type="string"), - * @OA\Property(property="installed", type="boolean"), - * @OA\Property(property="compatible", type="boolean") + * type="object", + * @OA\Property(property="success", type="string"), + * @OA\Property(property="message", type="array", + * @OA\Items(ref="#/components/schemas/DownloadOgLive") * ) * ) * ), @@ -140,22 +138,32 @@ public function getStatus(): Response * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string"), - * @OA\Property(property="details", type="string") + * @OA\Property(property="message", type="string") * ) * ) * ) */ public function getDownloadMenu(): Response { + // Llamar al servicio para obtener las ISOs disponibles $downloadsOutput = $this->curlRequestService->callOgLive("download"); - if (is_array($downloadsOutput) && isset($downloadsOutput['success']) && $downloadsOutput['success'] === false) { - return new JsonResponse(['error' => 'Failed to retrieve downloads', 'details' => $downloadsOutput['error']], Response::HTTP_INTERNAL_SERVER_ERROR); + // Verificar si hubo un error en la respuesta + if (is_array($downloadsOutput) && isset($downloadsOutput['error'])) { + return new JsonResponse( + ['error' => 'FAILED_TO_RETRIEVE_ISOS', 'message' => $downloadsOutput['message']], + Response::HTTP_INTERNAL_SERVER_ERROR + ); } - return new JsonResponse($downloadsOutput, Response::HTTP_OK); -} + // Formatear la respuesta según el nuevo formato + $response = [ + 'success' => 'ISOs retrieved successfully', + 'message' => $downloadsOutput['output']['downloads'] // Aquí la estructura ya está en el formato correcto de la salida del shell script + ]; + return new JsonResponse($response, Response::HTTP_OK); +} /** * @Route("/ogboot/v1/oglives", name="getOglives", methods={"GET"}) * @OA\Get( @@ -163,45 +171,90 @@ public function getDownloadMenu(): Response * summary="Get list of all installed ogLive clients", * @OA\Response( * response=200, - * description="Successful operation", + * description="List of installed ogLive clients retrieved successfully", * @OA\JsonContent( * type="object", - * @OA\Property(property="default_oglive", type="string", description="Default ogLive client"), - * @OA\Property( - * property="installed_ogLives", - * type="array", - * @OA\Items( - * type="object", - * @OA\Property(property="id", type="string", description="Unique identifier for the ogLive client"), - * @OA\Property(property="filename", type="string", description="Filename of the ogLive client"), - * @OA\Property(property="distribution", type="string", description="Distribution name of the installed ogLive client"), - * @OA\Property(property="kernel", type="string", description="Kernel version of the installed ogLive client"), - * @OA\Property(property="architecture", type="string", description="Architecture of the installed ogLive client"), - * @OA\Property(property="revision", type="string", description="Revision of the installed ogLive client"), - * @OA\Property(property="directory", type="string", description="Directory name of the installed ogLive client"), - * @OA\Property(property="iso", type="string", description="ISO file name of the installed ogLive client") + * @OA\Property(property="success", type="string", example="ogLive clients retrieved successfully"), + * @OA\Property(property="message", type="object", + * @OA\Property(property="default_oglive", type="string", description="The default ogLive client"), + * @OA\Property(property="installed_ogLives", type="array", + * @OA\Items(ref="#/components/schemas/OgLive") * ) * ) * ) * ), * @OA\Response( * response=404, - * description="No ogLive clients found" + * description="No ogLive clients found", + * @OA\JsonContent( + * type="object", + * @OA\Property(property="error", type="string", example="NOT_FOUND"), + * @OA\Property(property="message", type="string", example="No ogLive clients found.") + * ) + * ), + * @OA\Response( + * response=500, + * description="Server or unknown error occurred", + * @OA\JsonContent( + * oneOf={ + * @OA\Schema( + * @OA\Property(property="error", type="string", example="SERVER_ERROR"), + * @OA\Property(property="message", type="string", example="Failed to retrieve ogLive clients due to server error.") + * ), + * @OA\Schema( + * @OA\Property(property="error", type="string", example="UNKNOWN_ERROR"), + * @OA\Property(property="message", type="string", example="An unknown error occurred.") + * ) + * } + * ) * ) * ) */ + public function getOglives(): Response { - // Llama al servicio que ejecuta el comando oglivecli y procesa la salida - $ogLiveConfigResult = $this->curlRequestService->callOgLive("list_installed_oglives"); + // Llama al servicio que ejecuta el comando oglivecli y obtiene tanto el output como el código de salida + $response = $this->curlRequestService->callOgLive("list_installed_oglives"); + $ogLiveConfigResult = $response['output']; + $exitCode = $response['exitCode']; - if (empty($ogLiveConfigResult) || !isset($ogLiveConfigResult['installed_ogLives'])) { - return new JsonResponse(['error' => 'No ogLive clients found'], Response::HTTP_NOT_FOUND); + // Manejo de errores basado en el código de salida + if ($exitCode === 404) { + return new JsonResponse( + ['error' => 'NOT_FOUND', 'message' => 'No ogLive clients found.'], + Response::HTTP_NOT_FOUND + ); + } elseif ($exitCode === 500) { + return new JsonResponse( + ['error' => 'SERVER_ERROR', 'message' => 'Failed to retrieve ogLive clients due to server error.'], + Response::HTTP_INTERNAL_SERVER_ERROR + ); + } elseif ($exitCode !== 0) { + // Manejar otros posibles códigos de error no esperados + return new JsonResponse( + ['error' => 'UNKNOWN_ERROR', 'message' => 'An unknown error occurred.'], + Response::HTTP_INTERNAL_SERVER_ERROR + ); } - return new JsonResponse($ogLiveConfigResult, Response::HTTP_OK); + // Verificar si la salida es válida + if (empty($ogLiveConfigResult) || !isset($ogLiveConfigResult['installed_ogLives'])) { + return new JsonResponse( + ['error' => 'NOT_FOUND', 'message' => 'No ogLive clients found.'], + Response::HTTP_NOT_FOUND + ); + } + + // Formatear la respuesta final en caso de éxito + $response = [ + 'success' => 'ogLive clients retrieved successfully', + 'message' => $ogLiveConfigResult // Incluye la estructura completa con default_oglive e installed_ogLives + ]; + + return new JsonResponse($response, Response::HTTP_OK); } + /** * @Route("/ogboot/v1/oglives/default", name="getOgliveDefault", methods={"GET"}) * @OA\Get( @@ -212,36 +265,8 @@ public function getOglives(): Response * description="Successful operation", * @OA\JsonContent( * type="object", - * @OA\Property( - * property="distribution", - * type="string", - * description="Distribution name of the default ogLive client" - * ), - * @OA\Property( - * property="kernel", - * type="string", - * description="Kernel version of the default ogLive client" - * ), - * @OA\Property( - * property="architecture", - * type="string", - * description="Architecture of the default ogLive client" - * ), - * @OA\Property( - * property="revision", - * type="string", - * description="Revision of the default ogLive client" - * ), - * @OA\Property( - * property="directory", - * type="string", - * description="Directory name of the default ogLive client" - * ), - * @OA\Property( - * property="iso", - * type="string", - * description="ISO file name of the default ogLive client" - * ) + * @OA\Property(property="success", type="string", example="Se han obtenido la lista de oglives instalados correctamente"), + * @OA\Property(property="message", ref="#/components/schemas/OgLive") * ) * ), * @OA\Response( @@ -281,36 +306,8 @@ public function getOgliveDefault(Request $request): Response * description="Successful operation", * @OA\JsonContent( * type="object", - * @OA\Property( - * property="distribution", - * type="string", - * description="Distribution name of the installed ogLive client" - * ), - * @OA\Property( - * property="kernel", - * type="string", - * description="Kernel version of the installed ogLive client" - * ), - * @OA\Property( - * property="architecture", - * type="string", - * description="Architecture of the installed ogLive client" - * ), - * @OA\Property( - * property="revision", - * type="string", - * description="Revision of the installed ogLive client" - * ), - * @OA\Property( - * property="directory", - * type="string", - * description="Directory name of the installed ogLive client" - * ), - * @OA\Property( - * property="iso", - * type="string", - * description="ISO file name of the installed ogLive client" - * ) + * @OA\Property(property="success", type="string", example="Se han obtenido la lista de oglives instalados correctamente"), + * @OA\Property(property="message", ref="#/components/schemas/OgLive") * ) * ), * @OA\Response( @@ -332,10 +329,6 @@ public function getOglive(string $checksum): Response - - - - /** * @Route("/ogboot/v1/oglives/default", name="setOgliveDefault", methods={"PUT"}) * @OA\Put( @@ -486,8 +479,8 @@ public function setOgliveDefault(Request $request): Response // Responder que la instalación se ha completado return new JsonResponse([ - 'message' => 'ogLive client installation completed', - 'details' => $installResult + 'success' => 'ogLive client installation completed', + 'message' => $installResult ], JsonResponse::HTTP_OK); } catch (Exception $e) { @@ -565,32 +558,53 @@ public function uninstallOglive(string $checksum): Response { // Llamada al servicio para desinstalar el cliente ogLive error_log("Calling curlRequestService with checksum: $checksum"); - $result = $this->curlRequestService->callOgLive("uninstall " . escapeshellarg($checksum)); + + // Ejecutar el comando y capturar tanto el resultado como el código de salida + $response = $this->curlRequestService->callOgLive("uninstall " . escapeshellarg($checksum)); + $result = $response['output']; + $exitCode = $response['exitCode']; - // Verificar la respuesta del servicio + // Verificar la respuesta del servicio según el código de salida error_log("Service call result: " . print_r($result, true)); + error_log("Exit code: " . $exitCode); - if (is_array($result) && isset($result['error'])) { - // Error encontrado en la respuesta - error_log("Error found in response: " . $result['error']); - return new JsonResponse(['error' => $result['error']], Response::HTTP_INTERNAL_SERVER_ERROR); - } elseif (is_array($result) && isset($result['message'])) { - // Respuesta exitosa - error_log("Success response: " . print_r($result, true)); + if ($exitCode === 404) { + // ogLive client no encontrado + return new JsonResponse([ + 'error' => 'NOT_FOUND', + 'message' => $result['message'] ?? 'ogLive client not found.' + ], Response::HTTP_NOT_FOUND); + } elseif ($exitCode === 403) { + // Intento de desinstalar el ogLive por defecto + return new JsonResponse([ + 'error' => 'FORBIDDEN', + 'message' => $result['message'] ?? 'Cannot uninstall the default ogLive client.' + ], Response::HTTP_FORBIDDEN); + } elseif ($exitCode === 500) { + // Error interno del servidor + return new JsonResponse([ + 'error' => 'SERVER_ERROR', + 'message' => $result['message'] ?? 'Failed to uninstall ogLive client.' + ], Response::HTTP_INTERNAL_SERVER_ERROR); + } elseif ($exitCode === 200) { + // Desinstalación exitosa return new JsonResponse([ 'message' => $result['message'], 'details' => $result['details'] ?? '' ], Response::HTTP_OK); } else { - // Manejar el caso en que no se recibió una respuesta válida del servicio - error_log("Failed to uninstall ogLive client, empty result from service"); - return new JsonResponse(['error' => 'Failed to uninstall ogLive client'], Response::HTTP_INTERNAL_SERVER_ERROR); + // Manejar otros códigos de error no previstos + return new JsonResponse([ + 'error' => 'UNKNOWN_ERROR', + 'message' => 'An unknown error occurred.' + ], Response::HTTP_INTERNAL_SERVER_ERROR); } } + /** * @Route("/ogboot/v1/pxes", name="get_boot_files", methods={"GET"}) * @OA\Get( @@ -653,8 +667,7 @@ public function getBootFiles(): JsonResponse * response=200, * description="Successful operation", * @OA\JsonContent( - * type="obj/opt/ogboot/var/log - * ect", + * type="object", * @OA\Property(property="template_name", type="string", description="Template name", example="pxe"), * @OA\Property(property="mac", type="string", description="MAC address", example="00:50:56:22:11:12"), * @OA\Property(property="lang", type="string", description="Language", example="es_ES.UTF-8"), @@ -1170,3 +1183,4 @@ public function createTemplate(Request $request) } + diff --git a/src/OgBootBundle/Service/CurlRequestService.php b/src/OgBootBundle/Service/CurlRequestService.php index 79bb496..039ccee 100644 --- a/src/OgBootBundle/Service/CurlRequestService.php +++ b/src/OgBootBundle/Service/CurlRequestService.php @@ -43,18 +43,26 @@ public function callOgLive($parameter) $commandToRun = $ogLiveCliPath . ' ' . $action . ' ' . implode(' ', $cleanedArgs); // Registrar el comando en syslog para depuración - syslog(LOG_INFO, 'command ' . $commandToRun); + // Ejecutar el comando, capturando la salida y el código de salida + $output = []; + $exitCode = null; + exec($commandToRun, $output, $exitCode); // Ejecuta el comando, captura la salida y el código de salida - // Ejecutar el comando - $output = shell_exec($commandToRun); - syslog(LOG_INFO, 'output ' . $output); + // Unir la salida en una sola cadena y registrar en syslog + $outputString = implode("\n", $output); + syslog(LOG_INFO, 'output ' . $outputString); + syslog(LOG_INFO, 'exitCode ' . $exitCode); // Decodificar la salida JSON si es posible - $decodedOutput = json_decode($output, true); - - return $decodedOutput; + $decodedOutput = json_decode($outputString, true); + error_log('Decoded Output: ' . print_r($decodedOutput, true)); + return [ + 'output' => $decodedOutput, // Retorna la salida decodificada (JSON) + 'exitCode' => $exitCode // Retorna el código de salida del comando + ]; } } +