From 8ffe2cae85fdfe3e76c43c1cff358f6d6d03046a Mon Sep 17 00:00:00 2001 From: lgromero Date: Fri, 21 Jun 2024 16:18:19 +0200 Subject: [PATCH] refs #208 adds dameon logic to execute commands with sudo --- bin/oglivecli | 116 ++-- bin/setsmbpass | 26 +- .../Controller/OgBootController.php | 566 +++++++++++------- .../Service/CurlRequestService.php | 110 +++- 4 files changed, 554 insertions(+), 264 deletions(-) diff --git a/bin/oglivecli b/bin/oglivecli index 379bfd5..13d873a 100755 --- a/bin/oglivecli +++ b/bin/oglivecli @@ -40,7 +40,7 @@ # Global constants definition. PROG=$(basename "$(realpath "$0")") # Program name. -OPENGNSYS=/home/qindel/ogboot # OpenGnsys main directory. +OPENGNSYS=/opt/ogboot # OpenGnsys main directory. DOWNLOADDIR=$OPENGNSYS/lib # Directory to store ogLive images. DOWNLOADURL="https://ognproject.evlt.uma.es/trac/downloads" # Download URL. TFTPDIR=$OPENGNSYS/tftpboot # TFTP directory. @@ -316,84 +316,112 @@ function download_old() { function install() { local OGLIVEFILE OGLIVEDIST OGLIVEREV OGLIVEKRNL OGLIVEDIR OGINITRD OGSQFS OGCLIENT=ogclient local COMPRESS SAMBAPASS TMPDIR RSYNCSERV RSYNCCLNT - [ $# -ne 1 ] && raiseError usage + [ $# -ne 1 ] && { echo "{\"error\": \"usage\"}"; exit 1; } + OGLIVEFILE=$(realpath $DOWNLOADDIR/$1) - # Only 1 file in pathname expansion. - [ $(echo $OGLIVEFILE | wc -w) -gt 1 ] && raiseError usage - [ ! -f $OGLIVEFILE ] && raiseError notfound "Downloaded file: \"$1\"." - [ ! -r $OGLIVEFILE ] && raiseError access "Downloaded file: \"$1\"." - [ ! -w $(dirname $INFOFILE) ] && raiseError access "Configuration directory." - [ ! -w $TFTPDIR ] && raiseError access "Installation directory." - [ -z "$(file -b $OGLIVEFILE | grep "ISO.*ogClient")" ] && raiseError access "File is not an ogLive ISO image." - # Working directory: - # 64-bit: ogLive-KernelVersion-rCodeRelease - # 32-bit: ogLive-KernelVersion-i386-rCodeRelease + [ $(echo $OGLIVEFILE | wc -w) -gt 1 ] && { echo "{\"error\": \"usage\"}"; exit 1; } + [ ! -f $OGLIVEFILE ] && { echo "{\"error\": \"not found \"$1\".\"}"; exit 1; } + [ ! -r $OGLIVEFILE ] && { echo "{\"error\": \"access \"$1\".\"}"; exit 1; } + [ ! -w $(dirname $INFOFILE) ] && { echo "{\"error\": \"access configuration directory.\"}"; exit 1; } + [ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; } + [ -z "$(file -b $OGLIVEFILE | grep "ISO.*ogClient")" ] && { echo "{\"error\": \"File is not an ogLive ISO image.\"}"; exit 1; } + OGLIVEDIST="$(echo $OGLIVEFILE|cut -f2 -d-)" OGLIVEREV="${OGLIVEFILE##*-}"; OGLIVEREV="${OGLIVEREV%%.*}" OGLIVEKRNL="$(echo $OGLIVEFILE|cut -f3- -d-)"; OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEREV.*}" OGLIVEARCH="$(echo $OGLIVEFILE|awk -F- '{print $(NF-1)}')" case "$OGLIVEARCH" in - i386|amd64) # Get architecture. + i386|amd64) OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEARCH}" ;; - *) # 32-bit by default. + *) OGLIVEARCH="i386" ;; esac OGLIVEDIR="$TFTPDIR/$DEFOGLIVE-${OGLIVEKRNL%%-*}-$OGLIVEARCH-$OGLIVEREV" OGLIVEDIR="${OGLIVEDIR/amd64-/}" - # Get current or default Samba key. + OGINITRD=$OGLIVEDIR/oginitrd.img [ ! -r $OGINITRD ] && OGINITRD=$TFTPDIR/$DEFOGLIVE/oginitrd.img if [ -r $OGINITRD ]; then COMPRESS=$(file -b "$OGINITRD" | awk '{print tolower($1);}') SAMBAPASS=$($COMPRESS -dc $OGINITRD | \ cpio -i --to-stdout scripts/ogfunctions 2>&1 | \ - sed -n '/^[ ].*OPTIONS=/s/.*pass=\(\w*\).*/\1/p') + sed -n '/^[ \t].*OPTIONS=/s/.*pass=\(\w*\).*/\1/p') fi - # Make ogLive backup. + rm -fr ${OGLIVEDIR}.old mv -fv $OGLIVEDIR ${OGLIVEDIR}.old 2>/dev/null - # Mount ogLive ISO image, update its files and unmount it. + TMPDIR=/tmp/${OGLIVEFILE%.iso} mkdir -p $OGLIVEDIR $TMPDIR trap "umount $TMPDIR; rm -fr $TMPDIR" 1 2 3 6 9 15 - mount -o loop,ro $OGLIVEFILE $TMPDIR - cp -va $TMPDIR/ogclient/* $OGLIVEDIR || raiseError access "Cannot copy files to ogLive directory." + mount -o loop,ro $OGLIVEFILE $TMPDIR || { echo "{\"error\": \"mount failed.\"}"; exit 1; } + cp -va $TMPDIR/ogclient/* $OGLIVEDIR || { echo "{\"error\": \"Cannot copy files to ogLive directory.\"}"; exit 1; } umount $TMPDIR - # Link to default directory if it's the first ogLive. + if [ ! -f $INFOFILE ]; then rm -f $TFTPDIR/$DEFOGLIVE $TFTPDIR/$OGCLIENT - ln -vfs $(basename $OGLIVEDIR) $TFTPDIR/$DEFOGLIVE - ln -vfs $DEFOGLIVE $TFTPDIR/$OGCLIENT + ln -vfs $(basename $OGLIVEDIR) $TFTPDIR/$DEFOGLIVE || { echo "{\"error\": \"Linking to $TFTPDIR/$DEFOGLIVE failed.\"}"; exit 1; } + ln -vfs $DEFOGLIVE $TFTPDIR/$OGCLIENT || { echo "{\"error\": \"Linking to $TFTPDIR/$OGCLIENT failed.\"}"; exit 1; } fi - # Recover or ask for a new Samba access key. + if [ -n "$SAMBAPASS" ]; then - echo -ne "$SAMBAPASS\n$SAMBAPASS\n" | $OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" + echo -ne "$SAMBAPASS\n$SAMBAPASS\n" | $OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" || { echo "{\"error\": \"setsmbpass failed.\"}"; exit 1; } else - $OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" + $OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" || { echo "{\"error\": \"setsmbpass failed.\"}"; exit 1; } fi - # Set permissions. - find -L $OGLIVEDIR -type d -exec chmod 755 {} \; - find -L $OGLIVEDIR -type f -exec chmod 644 {} \; - chown -R :opengnsys $OGLIVEDIR - # Mount SquashFS and check Rsync version. + + find -L $OGLIVEDIR -type d -exec chmod 755 {} \; || { echo "{\"error\": \"chmod directories failed.\"}"; exit 1; } + find -L $OGLIVEDIR -type f -exec chmod 644 {} \; || { echo "{\"error\": \"chmod files failed.\"}"; exit 1; } + chown -R :opengnsys $OGLIVEDIR || { echo "{\"error\": \"chown failed.\"}"; exit 1; } + + echo "Mounting SquashFS and checking Rsync version..." OGSQFS=$OGLIVEDIR/ogclient.sqfs - mount -o loop,ro $OGSQFS $TMPDIR - # If Rsync server version > client version, link to compiled file. - RSYNCSERV=$(rsync --version 2>/dev/null | awk '/protocol/ {print $6}') - RSYNCCLNT=$(chroot $TMPDIR /usr/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}') - if [ -z "$RSYNCSERV" -o ${RSYNCSERV:-0} -gt ${RSYNCCLNT:-1} ]; then - [ -e $OPENGNSYS/client/bin/rsync-$RSYNCSERV ] && mv -f $OPENGNSYS/client/bin/rsync-$RSYNCSERV $OPENGNSYS/client/bin/rsync + + # Intentar montar SquashFS + if mount -o loop,ro $OGSQFS $TMPDIR; then + # Obtener versiones de rsync + RSYNCSERV=$(rsync --version 2>/dev/null | awk '/protocol/ {print $6}') + RSYNCCLNT=$(chroot $TMPDIR /usr/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}') + + # Lógica para manejar rsync + if [ -z "$RSYNCSERV" ] || [ "$RSYNCSERV" -gt "${RSYNCCLNT:-1}" ]; then + [ -e "$OPENGNSYS/client/bin/rsync-$RSYNCSERV" ] && \ + mv -f "$OPENGNSYS/client/bin/rsync-$RSYNCSERV" "$OPENGNSYS/client/bin/rsync" || \ + { echo "{\"error\": \"mv rsync failed.\"}"; umount $TMPDIR; exit 1; } + else + [ -e "$OPENGNSYS/client/bin/rsync" ] && \ + mv -f "$OPENGNSYS/client/bin/rsync" "$OPENGNSYS/client/bin/rsync-$($OPENGNSYS/client/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}')" || \ + { echo "{\"error\": \"mv rsync client failed.\"}"; umount $TMPDIR; exit 1; } + fi + + echo "Unmounting SquashFS..." + if umount $TMPDIR; then + echo "Unmounted successfully" + # Espera antes de intentar eliminar el directorio + sleep 1 + + # Intentar eliminar el directorio TMPDIR + if rmdir $TMPDIR; then + echo "Cleaned up successfully" + else + echo "Warning: rmdir $TMPDIR failed. Attempting force removal." + rm -rf $TMPDIR || echo "{\"error\": \"rm -rf $TMPDIR failed.\"}" + fi + else + echo "{\"error\": \"umount SquashFS failed.\"}" + fi else - # Else, rename compiled file using Rsync protocol number. - [ -e $OPENGNSYS/client/bin/rsync ] && mv -f $OPENGNSYS/client/bin/rsync $OPENGNSYS/client/bin/rsync-$($OPENGNSYS/client/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}') + echo "{\"error\": \"mount SquashFS failed.\"}" fi - # Unmount SquashFS. - umount $TMPDIR - rmdir $TMPDIR - # Update JSON file. - addToJson "$OGLIVEDIST" "$OGLIVEKRNL" "$OGLIVEARCH" "$OGLIVEREV" "$OGLIVEDIR" "$OGLIVEFILE" + + local json_output + json_output=$(jq -n --arg dist "$OGLIVEDIST" --arg krnl "$OGLIVEKRNL" --arg arch "$OGLIVEARCH" --arg rev "$OGLIVEREV" --arg dir "$OGLIVEDIR" --arg iso "$(basename "$OGLIVEFILE")" \ + '{distribution: $dist, kernel: $krnl, architecture: $arch, revision: $rev, directory: $dir, iso: $iso}') + + echo "$json_output" } + # Uninstall an ogLive client. function uninstall() { local ISO DIR INDEX DEFINDEX diff --git a/bin/setsmbpass b/bin/setsmbpass index 57c354d..44a7004 100755 --- a/bin/setsmbpass +++ b/bin/setsmbpass @@ -80,8 +80,25 @@ for OGLIVE in $LIST; do # descomprimir Initrd, sustituir clave y recomprimir Initrd). echo "Configurando cliente \"$OGLIVE\" ..." mkdir -p $TMPDIR - cd $TMPDIR || exit 3 - gzip -dc "$CLIENTINITRD" | cpio -im + cd $TMPDIR || { echo "Error: no se pudo cambiar al directorio temporal."; exit 3; } + + # Verificar si el archivo es gzip o lz4 antes de descomprimir. + if file "$CLIENTINITRD" | grep -q "gzip compressed data"; then + if ! gzip -dc "$CLIENTINITRD" | cpio -im; then + echo "Error: No se pudo descomprimir y extraer $CLIENTINITRD con gzip." + exit 4 + fi + COMPRESS_CMD="gzip -9c" + elif file "$CLIENTINITRD" | grep -q "LZ4 compressed data"; then + if ! lz4 -d "$CLIENTINITRD" | cpio -im; then + echo "Error: No se pudo descomprimir y extraer $CLIENTINITRD con lz4." + exit 4 + fi + COMPRESS_CMD="lz4 -c" + else + echo "Error: $CLIENTINITRD no está en formato gzip o lz4." + exit 4 + fi if [ -f scripts/ogfunctions ]; then sed -i "s/OPTIONS=\(.*\)user=\w*\(.*\)pass=\w*\(.*\)/OPTIONS=\1user=$SAMBAUSER\2pass=$SAMBAPASS\3/" scripts/ogfunctions # TEMPORAL: solución ticket 554, actualizar cliente en caché (ogLive r3257). @@ -97,7 +114,10 @@ EOT chown root.root scripts/passrsync scripts/client.cfg chmod 400 scripts/passrsync scripts/client.cfg # Generar Initrd del cliente. - find . | cpio -H newc -oa | gzip -9c > "$CLIENTINITRD" + if ! find . | cpio -H newc -oa | $COMPRESS_CMD > "$CLIENTINITRD"; then + echo "Error: No se pudo recomprimir $CLIENTINITRD." + exit 5 + fi else echo "$PROG: Aviso: no se ha modificado la clave del cliente \"$OGLIVE\"." fi diff --git a/src/OgBootBundle/Controller/OgBootController.php b/src/OgBootBundle/Controller/OgBootController.php index 33a4d24..73405e8 100644 --- a/src/OgBootBundle/Controller/OgBootController.php +++ b/src/OgBootBundle/Controller/OgBootController.php @@ -168,7 +168,7 @@ Regenerar plantilla - PUT /ogboot/pxe-templates * @Route("/ogboot/v1/oglives", name="getOglives", methods={"GET"}) * @OA\Get( * path="/ogboot/v1/oglives", - * summary="Get information of all installed ogLive clients", + * summary="Get list of all installed ogLive clients", * @OA\Response( * response=200, * description="Successful operation", @@ -177,57 +177,261 @@ Regenerar plantilla - PUT /ogboot/pxe-templates * @OA\Items( * type="object", * @OA\Property( + * property="id", + * type="string", + * description="Unique identifier for the ogLive client, generated from linuxISO.sum", + * example="9e49a085ba74f97a81bdf9b3d0785094" + * ), + * @OA\Property( * property="distribution", * type="string", - * description="Distribution name of the ogLive client" + * description="Distribution name of the installed ogLive client" * ), * @OA\Property( * property="kernel", * type="string", - * description="Kernel version of the ogLive client" + * description="Kernel version of the installed ogLive client" * ), * @OA\Property( * property="architecture", * type="string", - * description="Architecture of the ogLive client" + * description="Architecture of the installed ogLive client" * ), * @OA\Property( * property="revision", * type="string", - * description="Revision of the ogLive client" + * description="Revision of the installed ogLive client" * ), * @OA\Property( * property="directory", * type="string", - * description="Directory name of the ogLive client" + * description="Directory name of the installed ogLive client" * ), * @OA\Property( * property="iso", * type="string", - * description="ISO file name of the ogLive client" + * description="ISO file name of the installed ogLive client" * ) * ) * ) * ), * @OA\Response( - * response=500, - * description="Failed to retrieve information of installed ogLive clients" + * response=404, + * description="No ogLive clients found" * ) * ) */ - public function getOglives(): Response - { +public function getOglives(): Response +{ + $directoryPath = '/opt/ogboot/tftpboot/'; + $pattern = '/^ogLive-([\w.-]+)-r(\d+)$/'; - # $result = $this->curlRequestService->common_request(OG_REST_CMD_POWEROFF, POST, [OG_REST_PARAM_CLIENTS => $ips]); - $result = $this->curlRequestService->callOgLive("show all"); + $ogLives = []; + + if ($handle = opendir($directoryPath)) { + error_log("Opened directory: $directoryPath"); - if ($result) { - return new Response($result, Response::HTTP_OK); - } else { - return new Response('Failed', Response::HTTP_INTERNAL_SERVER_ERROR); + while (false !== ($entry = readdir($handle))) { + error_log("Processing entry: $entry"); + + if ($entry != "." && $entry != ".." && is_dir($directoryPath . $entry)) { + if (preg_match($pattern, $entry, $matches)) { + error_log("Entry matches pattern: $entry"); + + // Evitar directorios .old + if (substr($entry, -4) === '.old') { + error_log("Ignoring old directory: $entry"); + continue; + } + + // Extraer detalles + $distribution = $matches[1]; + $revision = $matches[2]; + $directory = $entry; + $ogLivePath = $directoryPath . $entry; + + // Obtener el ID del archivo linuxISO.sum + $sumFile = $ogLivePath . '/linuxISO.sum'; + $id = ''; + if (file_exists($sumFile)) { + $id = trim(file_get_contents($sumFile)); + } + + // Obtener el nombre del archivo ISO + $iso = ''; + $oldInfoFile = $ogLivePath . '/OLDINFOFILE'; + if (file_exists($oldInfoFile)) { + $iso = trim(file($oldInfoFile, FILE_USE_INCLUDE_PATH | FILE_IGNORE_NEW_LINES)[0]); + } + + // Obtener la versión del kernel + $kernelFile = $ogLivePath . '/ogvmlinuz'; + $kernel = ''; + if (file_exists($kernelFile)) { + $fileOutput = shell_exec("file -bkr $kernelFile"); + if (preg_match('/Linux kernel.*version (\d+\.\d+\.\d+)/', $fileOutput, $kernelMatches)) { + $kernel = $kernelMatches[1]; + } + } + + // Asumir arquitectura como 'amd64'; puedes refinar esto si se necesita más lógica + $architecture = 'amd64'; + + // Construir el objeto + $ogLives[] = [ + 'id' => $id, + 'distribution' => $distribution, + 'kernel' => $kernel, + 'architecture' => $architecture, + 'revision' => $revision, + 'directory' => $directory, + 'iso' => $iso + ]; + } else { + error_log("Entry does not match pattern: $entry"); + } + } else { + error_log("Entry is not a directory: $directoryPath$entry"); + } } + + closedir($handle); + error_log("Closed directory: $directoryPath"); } + if (!empty($ogLives)) { + error_log("Returning ogLives data"); + return new JsonResponse($ogLives, Response::HTTP_OK); + } else { + error_log("No ogLive clients found"); + return new JsonResponse(['error' => 'No ogLive clients found'], Response::HTTP_NOT_FOUND); + } +} + + +/** + * @Route("/ogboot/v1/oglives/{id}", name="getOglive", methods={"GET"}) + * @OA\Get( + * path="/ogboot/v1/oglives/{id}", + * summary="Get information of an installed ogLive client", + * @OA\Parameter( + * name="id", + * in="path", + * description="Checksum of the installed ogLive client", + * required=true, + * @OA\Schema( + * type="string", + * example="9e49a085ba74f97a81bdf9b3d0785094" + * ) + * ), + * @OA\Response( + * response=200, + * description="Successful operation", + * @OA\JsonContent( + * type="object", + * @OA\Property( + * property="id", + * type="string", + * description="Checksum of the installed 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\Response( + * response=404, + * description="ogLive client not found" + * ) + * ) + */ +public function getOglive(Request $request, string $id): Response +{ + $directoryPath = '/opt/ogboot/tftpboot/'; + $pattern = '/^ogLive-([\w.-]+)-([\w.-]+)-r(\d{4,8})$/'; + + $found = false; + $result = []; + + if ($handle = opendir($directoryPath)) { + while (false !== ($entry = readdir($handle))) { + if ($entry != "." && $entry != ".." && is_dir($directoryPath . $entry)) { + if (preg_match($pattern, $entry, $matches)) { + $checksumFilePath = $directoryPath . $entry . '/linuxISO.sum'; + if (file_exists($checksumFilePath)) { + $checksum = trim(file_get_contents($checksumFilePath)); + if ($checksum === $id) { + // Extract details + $distribution = explode('-', $matches[1])[0]; + $kernel = substr($matches[1], strlen($distribution) + 1); + $architecture = 'amd64'; // Assuming architecture, refine as needed + $revision = $matches[3]; + $directory = $entry; + $iso = $this->findIsoFile($directoryPath . $entry); + + // Construct the result + $result = [ + 'id' => $id, + 'distribution' => $distribution, + 'kernel' => $kernel, + 'architecture' => $architecture, + 'revision' => $revision, + 'directory' => $directory, + 'iso' => $iso + ]; + $found = true; + break; + } + } + } + } + } + closedir($handle); + } + + if ($found) { + return new JsonResponse($result, Response::HTTP_OK); + } else { + return new JsonResponse(['error' => 'ogLive client not found'], Response::HTTP_NOT_FOUND); + } +} + +private function findIsoFile(string $directory): string +{ + $files = glob($directory . '/*.iso'); + return count($files) > 0 ? basename($files[0]) : ''; +} + + + + /** * @Route("/ogboot/v1/oglives/default", name="getOgliveDefault", methods={"GET"}) * @OA\Get( @@ -289,89 +493,26 @@ Regenerar plantilla - PUT /ogboot/pxe-templates } } + + /** - * @Route("/ogboot/v1/oglives/{name}", name="getOglive", methods={"GET"}) - * @OA\Get( - * path="/ogboot/v1/oglives/{name}", - * summary="Get information of an installed ogLive client", - * @OA\Parameter( - * name="name", - * in="path", - * description="Name or Directory of the installed ogLive client", + * @Route("/ogboot/v1/oglives/default", name="setOgliveDefault", methods={"POST"}) + * @OA\Post( + * path="/ogboot/v1/oglives/default", + * summary="Set default ogLive client", + * @OA\RequestBody( * required=true, - * @OA\Schema( - * type="string" - * ) - * ), - * @OA\Response( - * response=200, - * description="Successful operation", * @OA\JsonContent( * type="object", * @OA\Property( - * property="distribution", + * property="name", * 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" + * example="ogLive-5.11.0-r20210413", + * description="Name of the ogLive client to set as default" * ) * ) * ), * @OA\Response( - * response=404, - * description="ogLive client not found" - * ) - * ) - */ -public function getOglive(Request $request, string $name): Response -{ - $result = $this->curlRequestService->callOgLive("show " . escapeshellarg($name)); - - if ($result) { - return new Response($result, Response::HTTP_OK); - } else { - return new Response('Failed', Response::HTTP_INTERNAL_SERVER_ERROR); - } -} - -/** - * @Route("/ogboot/v1/oglives/default/{name}", name="setOgliveDefault", methods={"POST"}) - * @OA\Post( - * path="/ogboot/v1/oglives/default/{name}", - * summary="Set default ogLive client", - * @OA\Parameter( - * name="name", - * in="path", - * description="Name of the ogLive client to set as default", - * required=true, - * @OA\Schema( - * type="string" - * ) - * ), - * @OA\Response( * response=200, * description="ogLive client set as default successfully", * @OA\JsonContent( @@ -389,8 +530,16 @@ public function getOglive(Request $request, string $name): Response * ) * ) */ -public function setOgliveDefault(Request $request, string $name): Response +public function setOgliveDefault(Request $request): Response { + $data = json_decode($request->getContent(), true); + + if (!isset($data['name'])) { + return new JsonResponse(['error' => 'Invalid input data'], Response::HTTP_BAD_REQUEST); + } + + $name = $data['name']; + // Obtener la lista de ogLives $listResult = $this->curlRequestService->callOgLive("list"); @@ -409,7 +558,7 @@ public function setOgliveDefault(Request $request, string $name): Response } if ($id === null) { - return new Response('ogLive client not found', Response::HTTP_NOT_FOUND); + return new JsonResponse(['error' => 'ogLive client not found'], Response::HTTP_NOT_FOUND); } // Establecer el ogLive como predeterminado utilizando el ID encontrado @@ -423,6 +572,7 @@ public function setOgliveDefault(Request $request, string $name): Response } + /** @@ -447,113 +597,129 @@ public function setOgliveDefault(Request $request, string $name): Response * ) */ - public function getDownloadMenu(): Response - { +public function getDownloadMenu(): Response +{ - $downloadsOutput = $this->curlRequestService->callOgLive("download"); + $downloadsOutput = $this->curlRequestService->callOgLive("download"); - $downloads = explode("\n", trim($downloadsOutput)); - $result = []; - - foreach ($downloads as $download) { + $downloads = explode("\n", trim($downloadsOutput)); + $result = []; + + foreach ($downloads as $download) { - $pattern = '/^(\d+)\) (\(\*\))?\s?(\(\+\))?\s?(.+\.iso)$/'; - + $pattern = '/^(\d+)\) (\(\*\))?\s?(\(\+\))?\s?(.+\.iso)$/'; + - preg_match($pattern, $download, $matches); + preg_match($pattern, $download, $matches); - if (!empty($matches)) { - $id = $matches[1]; - $installed = !empty($matches[2]); - $compatible = !empty($matches[3]); - $filename = $matches[4]; + if (!empty($matches)) { + $id = $matches[1]; + $installed = !empty($matches[2]); + $compatible = !empty($matches[3]); + $filename = $matches[4]; - $result[] = [ - 'id' => $id, - 'filename' => $filename, - 'installed' => $installed, - 'compatible' => $compatible - ]; - } - } - - $jsonDownloads = json_encode($result); - - - return new Response($jsonDownloads, Response::HTTP_OK, [ - 'Content-Type' => 'application/json' - ]); - } - - /** - * @Route("/ogboot/v1/oglives", name="installOglive", methods={"POST"}) - * @OA\Post( - * path="/ogboot/v1/oglives", - * summary="Install an ogLive client", - * @OA\RequestBody( - * required=true, - * @OA\JsonContent( - * type="object", - * @OA\Property( - * property="isoName", - * type="string", - * description="Name of the ogLive ISO to install", - * example="ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso" - * ) - * ) - * ), - * @OA\Response( - * response=200, - * description="ogLive client installed successfully", - * @OA\JsonContent( - * type="object", - * @OA\Property(property="message", type="string") - * ) - * ), - * @OA\Response( - * response=500, - * description="Failed to install ogLive client", - * @OA\JsonContent( - * type="object", - * @OA\Property(property="error", type="string") - * ) - * ) - * ) - */ - public function installOglive(Request $request): Response - { - $data = json_decode($request->getContent(), true); - $isoName = $data['isoName'] ?? null; - #$isoName = $request->get('isoName'); - var_dump($isoName); - if (!$isoName) { - return new Response('ISO name is required', Response::HTTP_BAD_REQUEST); - } - - $result = $this->curlRequestService->callOgLive("download " . escapeshellarg($isoName)); - - if ($result) { - return new Response($result, Response::HTTP_OK); - } else { - return new Response('Failed', Response::HTTP_INTERNAL_SERVER_ERROR); + $result[] = [ + 'id' => $id, + 'filename' => $filename, + 'installed' => $installed, + 'compatible' => $compatible + ]; } } + $jsonDownloads = json_encode($result); + + + return new Response($jsonDownloads, Response::HTTP_OK, [ + 'Content-Type' => 'application/json' + ]); +} + + /** - * @Route("/ogboot/v1/oglives/{name}", name="uninstallOglive", methods={"DELETE"}) + * @Route("/ogboot/v1/oglives", name="installOglive", methods={"POST"}) + * @OA\Post( + * path="/ogboot/v1/oglives", + * summary="Install an ogLive client", + * @OA\RequestBody( + * required=true, + * @OA\JsonContent( + * type="object", + * @OA\Property( + * property="isoname", + * type="string", + * example="ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso", + * description="Name of the ogLive ISO to install" + * ) + * ) + * ), + * @OA\Response( + * response=200, + * description="ogLive client installed successfully", + * @OA\JsonContent( + * type="object", + * @OA\Property(property="distribution", type="string"), + * @OA\Property(property="kernel", type="string"), + * @OA\Property(property="architecture", type="string"), + * @OA\Property(property="revision", type="string"), + * @OA\Property(property="directory", type="string"), + * @OA\Property(property="iso", type="string") + * ) + * ), + * @OA\Response( + * response=400, + * description="Invalid input data", + * @OA\JsonContent( + * type="object", + * @OA\Property(property="error", type="string") + * ) + * ), + * @OA\Response( + * response=500, + * description="Failed to install ogLive client", + * @OA\JsonContent( + * type="object", + * @OA\Property(property="error", type="string"), + * @OA\Property(property="details", type="string") + * ) + * ) + * ) + */ + + +public function installOglive(Request $request): Response +{ + $data = json_decode($request->getContent(), true); + + if (!isset($data['isoname'])) { + return new JsonResponse(['error' => 'Invalid input data'], Response::HTTP_BAD_REQUEST); + } + + $isoname = $data['isoname']; + $result = $this->curlRequestService->callOgLive("download " . escapeshellarg($isoname)); + + if (is_array($result) && isset($result['success']) && $result['success'] === false) { + return new JsonResponse(['error' => 'Failed to install ogLive client', 'details' => $result['error']], Response::HTTP_INTERNAL_SERVER_ERROR); + } + + return new JsonResponse(['message' => 'ogLive client installed successfully', 'details' => $result['output']], Response::HTTP_OK); +} + + + +/** + * @Route("/ogboot/v1/oglives/{checksum}", name="uninstallOglive", methods={"DELETE"}) * @OA\Delete( - * path="/ogboot/v1/oglives/{name}", + * path="/ogboot/v1/oglives/{checksum}", * summary="Uninstall an ogLive client", * @OA\Parameter( - * name="name", + * name="checksum", * in="path", - * description="Name of the ogLive client to uninstall", + * description="Checksum of the ogLive client to uninstall", * required=true, - * @OA\Schema( - * type="string" - * ) + * @OA\Schema(type="string", example="9e49a085ba74f97a81bdf9b3d0785094") * ), * @OA\Response( * response=200, @@ -577,39 +743,25 @@ public function setOgliveDefault(Request $request, string $name): Response * ) * ) */ -public function uninstallOglive(Request $request, string $name): Response +public function uninstallOglive(string $checksum): Response { - // Obtener la lista de ogLives - $listResult = $this->curlRequestService->callOgLive("list"); - - if (!$listResult) { - return new Response('Failed to retrieve ogLive list', Response::HTTP_INTERNAL_SERVER_ERROR); - } - - // Buscar el ID correspondiente al nombre proporcionado - $lines = explode("\n", trim($listResult)); - $id = null; - foreach ($lines as $line) { - if (strpos($line, $name) !== false) { - $id = explode(" ", trim($line))[0]; - break; - } - } - - if ($id === null) { - return new Response('ogLive client not found', Response::HTTP_NOT_FOUND); - } - - // Desinstalar el ogLive utilizando el ID encontrado - $result = $this->curlRequestService->callOgLive("uninstall $id"); + $result = $this->curlRequestService->callOgLive("uninstall " . escapeshellarg($checksum)); if ($result) { - return new JsonResponse(['message' => 'ogLive client uninstalled successfully'], Response::HTTP_OK); + // Decodifica la respuesta JSON del demonio + $response = json_decode($result, true); + + if (isset($response['error'])) { + return new JsonResponse(['error' => $response['error']], Response::HTTP_INTERNAL_SERVER_ERROR); + } + + return new JsonResponse(['message' => 'ogLive client uninstalled successfully', 'details' => $response['details']], Response::HTTP_OK); } else { return new JsonResponse(['error' => 'Failed to uninstall ogLive client'], Response::HTTP_INTERNAL_SERVER_ERROR); } } + /** * @Route("/ogboot/v1/pxes", name="get_boot_files", methods={"GET"}) * @OA\Get( diff --git a/src/OgBootBundle/Service/CurlRequestService.php b/src/OgBootBundle/Service/CurlRequestService.php index 15c9f83..786b0cf 100644 --- a/src/OgBootBundle/Service/CurlRequestService.php +++ b/src/OgBootBundle/Service/CurlRequestService.php @@ -18,15 +18,105 @@ class CurlRequestService return $bits; } - public function callOgLive($parameter) - { - $ogLiveCliPath = sprintf("%s/bin/oglivecli", dirname(dirname(dirname(__DIR__)))); - - $command = sprintf("%s %s", $ogLiveCliPath, $parameter); - - syslog(LOG_INFO, 'command '.$command); - $output = shell_exec($command); - - return $output; +// src/Service/CurlRequestService.php + +public function installOglive($isoname) +{ + $socketPath = '/tmp/oglive_daemon.sock'; + $socket = socket_create(AF_UNIX, SOCK_STREAM, 0); + if ($socket === false) { + syslog(LOG_ERR, 'Error al crear el socket: ' . socket_strerror(socket_last_error())); + return ['success' => false, 'output' => 'Error al crear el socket']; + } + + $result = socket_connect($socket, $socketPath); + if ($result === false) { + syslog(LOG_ERR, 'Error al conectar con el socket: ' . socket_strerror(socket_last_error($socket))); + socket_close($socket); + return ['success' => false, 'output' => 'Error al conectar con el socket']; + } + + $command = [ + 'action' => 'download', + 'args' => [$isoname] + ]; + + socket_write($socket, json_encode($command), strlen(json_encode($command))); + + $response = ''; + $status = []; + + while ($buffer = socket_read($socket, 2048)) { + $response .= $buffer; + $status[] = json_decode($buffer, true); + } + + socket_close($socket); + + // Analiza el último estado recibido + $lastStatus = end($status); + if ($lastStatus && $lastStatus['status'] === 'completed') { + return ['success' => true, 'output' => $lastStatus]; + } else { + return ['success' => false, 'output' => $status]; } } + + + +public function callOgLive($parameter) +{ + $socketPath = '/tmp/oglive_daemon.sock'; // Path to the UNIX socket + $socket = socket_create(AF_UNIX, SOCK_STREAM, 0); + if ($socket === false) { + syslog(LOG_ERR, 'Error al crear el socket: ' . socket_strerror(socket_last_error())); + return [ + 'success' => false, + 'error' => 'Error al crear el socket' + ]; + } + + $result = socket_connect($socket, $socketPath); + if ($result === false) { + syslog(LOG_ERR, 'Error al conectar con el socket: ' . socket_strerror(socket_last_error($socket))); + socket_close($socket); + return [ + 'success' => false, + 'error' => 'Error al conectar con el socket' + ]; + } + + $args = explode(' ', $parameter); + $action = array_shift($args); // Toma la primera palabra como la acción + $command = [ + 'action' => $action, + 'args' => $args + ]; + + syslog(LOG_INFO, 'Sending command to daemon: ' . json_encode($command)); + socket_write($socket, json_encode($command), strlen(json_encode($command))); + + $response = ''; + while ($buffer = socket_read($socket, 2048)) { + $response .= $buffer; + } + + socket_close($socket); + + $decodedResponse = json_decode($response, true); + + if (isset($decodedResponse['success']) && $decodedResponse['success']) { + return $decodedResponse['output']; + } else { + syslog(LOG_ERR, 'Error al ejecutar el comando: ' . $decodedResponse['error']); + return [ + 'success' => false, + 'error' => $decodedResponse['error'] ?? 'Unknown error' + ]; + } +} + + + + +}